Score: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

ตัวอย่าง $ = [
  'โหนด' => [
    'field_something' => [
      'ปัจจุบัน' => 'some_table_name'
      'แก้ไข' => 'some_table_name'
    ]
  ]
  'บล็อก' => [
    'field_something' => [
      'ปัจจุบัน' => 'some_table_name'
      'แก้ไข' => 'some_table_name'
    ]
  ]
];

*โดยคำนึงถึงว่าฟิลด์นั้นสามารถแก้ไขได้จริงตั้งแต่แรกหรือไม่

ด้วยตัวฉันเอง ฉันตัดสินใจเองว่าชื่อตารางส่วนใหญ่จะเป็นแบบเดียวกัน $entityType . '__' . $field['ชื่อ'] และ $entityType . '_revision__' . $field['ชื่อ'] แต่การฮาร์ดโค้ดสคริปต์ของฉันจะพังลงเมื่อมีการใช้รหัสเฉพาะ ตัวอย่างเช่น บล็อกแบบกำหนดเองจะมีชื่อตารางเช่น block_content_r__7fe666c7a4. ฉันต้องสามารถดึงข้อมูลนั้นออกจาก "คำจำกัดความของที่เก็บข้อมูลฟิลด์" ได้

สารละลาย: ตาม @Clive วิธีแก้ไขคือการรับคลาสพื้นที่เก็บข้อมูลสำหรับเอนทิตีแต่ละประเภท จากนั้นใช้เพื่อดึงข้อมูลการแมปตาราง วิธีนี้ใช้ได้ดีกับฟิลด์ที่ไม่ใช่ฐาน แต่ถ้าคุณต้องการฟิลด์ฐาน โซลูชันจะแตกต่างออกไป นี่คือสิ่งที่ฉันลงเอยด้วย:

$ฟิลด์ = [];
foreach ($this->getContentEntityTypes() เป็น $contentEntityType) {
  $tableMapping = $this->entityTypeManager->getStorage($contentEntityType->id())->getTableMapping();
  foreach ($this->entityFieldManager->getFieldStorageDefinitions($contentEntityType->id()) เป็น $field) {
    // เราใช้ needDedicatedTableStorage() เพื่อกรองฟิลด์พื้นฐาน 
    ถ้า ($tableMapping->requiresDedicatedTableStorage($field)) {
      $fieldInfo = [
        'ชื่อ' => $field->getName(),
        'type' => $field->getType(),
        'table' => $tableMapping->getDedicatedDataTableName($ฟิลด์)
      ];
      ถ้า ($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) {
    ถ้า (อินสแตนซ์ $entityType ของ ContentEntityTypeInterface && in_array(SqlEntityStorageInterface::class, class_implements($entityType->getStorageClass()))) {
      $contentEntityTypes[] = $entityType;
    }
  }
  ส่งคืน $contentEntityTypes;
}
Score: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 เท่านั้น
  ถ้า (อินสแตนซ์ $entity_type ของ 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 flag
นี่มันสมบูรณ์แบบ! ฉันรู้ว่ามันผ่านตัวจัดการฟิลด์เอนทิตี แต่ไม่แน่ใจว่าจะไปยังการแมปตารางได้อย่างไร ฉันจะลองทำสิ่งนี้ในวันจันทร์และดูว่าทุกอย่างจะเป็นอย่างไร! ขอบคุณมาก!
cn flag
ฉันดูอย่างรวดเร็วและใช้งานได้ ฉันจะถือว่าฉันสามารถถามคำจำกัดความของฟิลด์ได้หากสามารถแก้ไขได้ แล้วมีวิธีการรับชื่อตารางนั้นหรือไม่
cn flag
คุณสามารถถามว่าแก้ไขได้หรือไม่ด้วย `$field->isRevisionable()` แต่การได้ชื่อตารางที่แน่นอนนั้นซับซ้อนกว่า เนื่องจากอาจมีฟิลด์พื้นฐานในหลายตาราง หากคุณต้องการเพียงแค่ฟิลด์ที่ไม่ใช่ฐาน หรือให้ถูกต้องมากกว่านั้นก็คือฟิลด์ที่ไม่อยู่ในตารางการแก้ไขฐานและฐาน คุณสามารถใช้ `$storage->getTableMapping()->requiresDedicatedTableStorage($field)` เพื่อกรองตัวเลือก จากนั้น ใช้ `$storage->getTableMapping()->getDedicatedDataTableName($field)` และ `->getDedicatedRevisionTableName($field)` เพื่อรับชื่อตาราง
cn flag
Yup, that worked perfectly. My final code has been added to the question. Thanks again for the help!

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา