Рейтинг:2

Как получить имена таблиц, в которых хранятся данные полей?

флаг cn

В Drupal 7 можно было получить физические имена таблиц базы данных, используя следующий код, это было довольно просто.

$field_definitions = field_info_fields();
foreach ($field_definitions как $field => $definition) {
  $current_storage = $definition['storage']['details']['sql'][FIELD_LOAD_CURRENT];
  $current_table = ключ($current_storage);
  $revision_storage = $definition['storage']['details']['sql'][FIELD_LOAD_REVISION];
  $revision_table = ключ($revision_storage);
}

В Drupal 9 API сущностей изменился к лучшему, и теперь существуют классы и сервисы для извлечения информации такого типа.Это все хорошо, я понимаю большинство концепций, связанных с этим, но я не могу на всю жизнь экстраполировать, как получить те же самые данные.

Моя цель - перебрать все мои типы сущностей, которые реализуют ContentEntityTypeInterface, получить их поля, а затем построить массив, который выглядит примерно так: у меня есть очень специализированный скрипт Drush, который я пытаюсь перенести с Drupal 7.

$ пример = [
  'узел' => [
    'поле_что-то' => [
      'current' => 'some_table_name'
      'revision' => 'some_table_name'
    ]
  ],
  'заблокировать' => [
    'поле_что-то' => [
      'current' => 'some_table_name'
      'revision' => 'some_table_name'
    ]
  ]
];

*Конечно, принимая во внимание, действительно ли поле может быть изменено.

Самостоятельно я определил, что по большей части имена таблиц в конечном итоге выглядят как $entityType . '__' . $поле['имя'] и $entityType . '_revision__' . $поле['имя'] но жесткое кодирование моего скрипта ломается, когда используются уникальные идентификаторы. Например, пользовательские блоки имеют имена таблиц, такие как block_content_r__7fe666c7a4. Мне нужно иметь возможность вытащить эти данные из своего рода «определения полевого хранилища».

Решение: Согласно @Clive, решение состояло в том, чтобы получить класс хранения для каждого типа объекта, а затем использовать его для получения сопоставлений таблиц. Это прекрасно работает для небазовых полей, но если вам нужно базовое поле, решение будет другим. Вот что у меня получилось:

$поля = [];
foreach ($this->getContentEntityTypes() as $contentEntityType) {
  $tableMapping = $this->entityTypeManager->getStorage($contentEntityType->id())->getTableMapping();
  foreach ($this->entityFieldManager->getFieldStorageDefinitions($contentEntityType->id()) as $field) {
    // Мы используем requireDedicatedTableStorage() для фильтрации базовых полей 
    если ($tableMapping->requiresDedicatedTableStorage($field)) {
      $fieldInfo = [
        'имя' => $field->getName(),
        'тип' => $field->getType(),
        'table' => $tableMapping->getDedicatedDataTableName($field)
      ];
      если ($field->isRevisionable()) {
        $fieldInfo['table_revision'] = $tableMapping->getDedicatedRevisionTableName($field);
      }
      $fields[$contentEntityType->id()][] = $fieldInfo;
    }
  }
}
вернуть $поля;

Я написал отдельный метод для получения своих объектов контента, который использовал приведенный выше код.

функция getContentEntityTypes() {
  $contentEntityTypes = [];
  $entity_type_definitions = $this->entityTypeManager->getDefinitions();
  /* @var $definition EntityTypeInterface */
  foreach ($entity_type_definitions как $entityType) {
    if ($entityType instanceof ContentEntityTypeInterface && in_array(SqlEntityStorageInterface::class, class_implements($entityType->getStorageClass())))) {
      $contentEntityTypes[] = $entityType;
    }
  }
  вернуть $contentEntityTypes;
}
Рейтинг:4
флаг cn

Предполагая серверную часть хранилища SQL, имена таблиц доступны из TableMappingInterface::getAllFieldTableNames(). Вы можете получить отображение таблицы типа объекта из его обработчика хранилища.

Это, вероятно, может быть более элегантным, но должно быть хорошей отправной точкой:

используйте Drupal\Core\Entity\ContentEntityTypeInterface;
используйте Drupal\Core\Entity\Sql\SqlEntityStorageInterface;

...

// Эти службы должны быть внедрены, если позволяет контекст.
$entity_type_manager = \Drupal::entityTypeManager();
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');

$таблицы = [];
foreach ($entity_type_manager->getDefinitions() как $entity_type) {
  // Только список типов объектов содержимого, использующих хранилище SQL.
  if ($entity_type instanceof ContentEntityTypeInterface && in_array(SqlEntityStorageInterface::class, class_implements($entity_type->getStorageClass())))) {
    $storage = $entity_type_manager->getStorage($entity_type->id());

    foreach ($field_manager->getFieldStorageDefinitions($entity_type->id()) как $field) {
      $tables[$entity_type->id()][$field->getName()] = $storage->getTableMapping()
        ->getAllFieldTableNames($field->getName());
    }
  }
}

Это даст вам такой результат:

введите описание изображения здесь

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

флаг cn
Это потрясающе! Я знал, что это через диспетчер полей сущностей, но не знал, как оттуда перейти к сопоставлению таблиц. Я попробую это в понедельник и посмотрю, как все пойдет! Большое спасибо!
флаг cn
Я быстро взглянул на это, и это сработало. Я бы предположил, что могу спросить определение поля, можно ли его пересматривать, а затем есть способ получить это имя таблицы?
флаг cn
Вы можете спросить, можно ли его изменить с помощью `$field->isRevisionable()`, но получить точное имя таблицы сложнее, поскольку базовые поля могут существовать в нескольких таблицах. Если вам просто нужны небазовые поля или, точнее, те, которые не находятся в базовых таблицах и таблицах базовых версий, вы можете использовать `$storage->getTableMapping()->requiresDedicatedTableStorage($field)` для фильтрации кандидатов, а затем используйте `$storage->getTableMapping()->getDedicatedDataTableName($field)` и `->getDedicatedRevisionTableName($field)`, чтобы получить имена таблиц
флаг cn
Да, это сработало отлично. Мой окончательный код был добавлен к вопросу. Спасибо еще раз за помощь!

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

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