Рейтинг:2

добавить поле пользователю в hook_update_n

флаг pl

В последнем выпуске нашего существующего модуля необходимо определить МНОЖЕСТВО новых полей, привязанных к пользователю drupal. Для каждого поля в {module}/config/Optional есть конфигурация поля и конфигурация хранения поля. Затем я реализую hook_update_n в {module}/{module}.install, чтобы обнаруживать новые записи конфигурации и добавлять их, если они не существуют. Запуск кода устанавливает конфиг (я его вижу с помощью drush cget), но не создает соответствующие таблицы БД для новых полей.

Если я перейду на большинство страниц, таких как /admin/config/люди/аккаунты/поля, я получаю сообщение "На веб-сайте произошла непредвиденная ошибка. Повторите попытку позже".

Если я очистил кеш (драш кр), я получаю сообщение об ошибке,

В строке 53 ExceptionHandler.php:

  SQLSTATE[42S02]: базовая таблица или представление не найдены: 1146 Таблица «intranet.user__field_s_uid» не существует: SELECT «t».*
  ОТ
  "user__field_s_uid" "т"
  ГДЕ ("entity_id" В (:db_condition_placeholder_0)) И ("удалено" = :db_condition_placeholder_1) И ("langcode" В (:db_condition_placeholder_2, :db_c
  ondition_placeholder_3, :db_condition_placeholder_4))
  ЗАКАЗ ПО "ДЕЛЬТА" АСЦ; Множество
  (
      [:db_condition_placeholder_0] => 0
      [:db_condition_placeholder_1] => 0
      [:db_condition_placeholder_2] => ru
      [:db_condition_placeholder_3] => и
      [:db_condition_placeholder_4] => zxx
  )

В StatementWrapper.php строка 116:

  SQLSTATE [42S02]: базовая таблица или представление не найдены: 1146 Таблица «intranet.user__field_s_uid» не существует

Чтобы сайт снова заработал, мне нужно удалить конфигурацию (drush cdel...).

Что мне не хватает, что мешает созданию хранилища БД? Нужно ли мне программно создавать таблицу БД для использования поля? (если да, то как?)

файл: {модуль}.install

<?php                                                              
используйте Drupal\Component\Serialization\Yaml;                           
используйте Drupal\Component\Utility\NestedArray;                          
используйте Drupal\field\Entity\FieldStorageConfig;                        
используйте Drupal\field\Entity\FieldConfig;                               
                                                                   
функция {модуль}_update_9001(&$песочница = NULL){             
  $modulePath = \Drupal::service('extension.list.module')          
        ->getPath('{модуль}');                      
  $config_factory = \Drupal::configFactory();                      
  $configPathObjects = \Drupal::service('file_system')             
    ->scanDirectory($modulePath.'/config/Optional','~поле.*~');   
                                                                   
  foreach ($configPathObjects как $configPath){                     
                                                                   
    $config = $config_factory->getEditable($configPath->имя);     
    если($config->isNew()){                                          
      $configSettings = NestedArray::mergeDeep(                    
          Ямл:: декодировать (                                            
            file_get_contents(                                     
              "$modulePath/config/необязательный/{$configPath->имя файла}"
              )                                                    
            ),$config                                              
          );                                                       
      $config->setdata($configSettings);                           
      $config->сохранить(ИСТИНА);                                         
    }                                                              
  }                                                                
}                                                                  

файл: config/необязательный/field.field.user.user.field_s_uid.yml

код языка: en                                                                   
статус: правда                                                                   
зависимости:                                                                  
  конфигурация:                                                                      
    - field.storage.user.field_s_uid                                           
  модуль:                                                                      
    - пользователь                                                                     
идентификатор: user.user.field_s_uid                                                      
имя_поля: field_s_uid                                                        
тип_объекта: пользователь                                                              
пакет: пользователь                                                                   
метка: s_uid                                                                   
описание: «Уникальный идентификатор этого пользователя, автоматически устанавливаемый БД, не должен изменяться пользователями/администраторами».                                              
требуется: ложь                                                                
переводимый: ложный                                                            
значение по умолчанию: {  }                                                            
default_value_callback: ''                                                     
настройки:                                                                      
  мин: ноль                                                                    
  максимум: ноль                                                                    
  префикс: ''                                                                   
  суффикс: ''                                                                   
field_type: целое число                                                            

файл: config/необязательный/field.storage.user.field_s_uid.yml

код языка: en
статус: правда
зависимости:
  модуль:
    - пользователь
идентификатор: user.field_s_uid
имя_поля: field_s_uid
тип_объекта: пользователь
тип: целое число
настройки:
  без знака: ложь
  Размер: нормальный
модуль: ядро
заблокировано: ложь
кардинальность: 1
переводимый: правда
индексы: { }
persist_with_no_fields: ложь
custom_storage: ложь
флаг ru
Сначала необходимо убедиться, что FieldStorage установлен.
Рейтинг:2
флаг pl

Окончательное решение основано на принятом решении от @4k4 (см. ответ).

<?php
используйте Drupal\Core\Database\Database;
используйте Drupal\Component\Serialization\Yaml;
используйте Drupal\Component\Utility\NestedArray;
используйте Drupal\field\Entity\FieldStorageConfig;
используйте Drupal\field\Entity\FieldConfig;
используйте Drupal\Core\Utility\UpdateException;

/**
 * Добавление обязательных полей к пользовательским объектам.
 */
функция {модуль}_update_9001(){
  $modulePath = \Drupal::service('extension.list.module')
        ->getPath('{модуль}');
  $configPathStorageObjects = \Drupal::service('файловая_система')
    ->scanDirectory($modulePath.'/config/Optional','~field\.storage\.user\..*~');
  \Drupal::logger('staffdb')->notice('объекты хранилища: <pre>'.print_r($configPathStorageObjects,true).'</pre>');

  //добавляем хранилище отсутствующих полей
  foreach ($configPathStorageObjects как $configPath){
    $config = FieldStorageConfig::loadByName('user',str_replace('field.storage.user.','',$configPath->name));
    если (is_null ($ конфигурация)) {
      $configSettings = Yaml::decode(
          file_get_contents(
            "$modulePath/config/необязательный/{$configPath->имя файла}"
            )
          );
      $fieldStorage = FieldStorageConfig::create($configSettings);
      $fieldStorage->сохранить();
    }
  }

  //добавляем недостающие поля пользователям
  $configPathFieldObjects = \Drupal::service('файловая_система')
    ->scanDirectory($modulePath.'/config/Optional','~field\.field\.user\.user\..*~');
  foreach ($configPathFieldObjects как $configPath){
    $config = FieldConfig::loadByName('пользователь', 'пользователь', str_replace('field.field.user.user.','',$configPath->name));
    если (is_null ($ конфигурация)) {
      $configSettings = Yaml::decode(
          file_get_contents(
            "$modulePath/config/необязательный/{$configPath->имя файла}"
            )
          );
      $field = FieldConfig::create($configSettings);
      $поле->сохранить();
    }
  }
}
Рейтинг:2
флаг cn

Вам потребуются классы сущностей конфигурации FieldStorageConfig::create() и FieldConfig::create(). У вас уже есть операторы использования, но вы их не используете. В противном случае события сущности, такие как postcreate и presave, не вызываются.

Кстати, если вы измените конфигурацию объекта конфигурации через $config_factory->getEditable() это работает только до тех пор, пока вы не изменяете ничего, влияющего на упомянутые события объекта.Если вам нужно сохранить объекты конфигурации без переопределения, лучше загрузить их с помощью ConfigEntityStorageInterface::loadOverrideFree().

флаг ru
Использование `FieldStorageConfig` или `FieldConfig` означает, что вам явно нужно просмотреть каждую конфигурацию (-type) одну за другой. Нет ли возможности сразу установить целый каталог произвольных конфигурационных файлов? Я использовал тот же метод, что и @Kevin Finkenbinder, который я видел в [файле установки дистрибутива Varbase](https://git.drupalcode.org/project/varbase_bootstrap_paragraphs/-/blob/9.0.x/varbase_bootstrap_paragraphs. install#L39): Сначала FieldStorage, потом все остальное. Такой подход не спасает?
4uk4 avatar
флаг cn
Связанный код работает только из-за $config_installer->installOptionalConfig(), который впоследствии повторно сохраняет добавленные объекты конфигурации.
4uk4 avatar
флаг cn
и в конце код использует трюк для исправления любых ошибок обновления https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21EntityDefinitionUpdateManager.php/function/EntityDefinitionUpdateManager%3A%3AapplyUpdates /8.9.х. Этот метод больше не доступен.
флаг pl
Спасибо. Это дало мне то, что мне было нужно, и помечено как принятый ответ. Для помощи другим, таким как @Hudri, я также разместил окончательный код ниже (https://drupal.stackexchange.com/a/307977/19071), который позволяет мне перебирать несколько добавляемых файлов.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.