logo

パレット - カラフルに🎨

Palette — ビジュアルページビルダー、デザインの専門知識は不要です。

ライブデモ パレットをダウンロード

Scroll

Content Entity Field定義の定義と使用

17/05/2020, by maria

Contentエンティティは、エンティティクラスに定義を提供することにより、すべてのフィールドを明示的に定義する必要があります。フィールド定義はTyped data APIに基づいています(エンティティがそれをどのように実装するかを参照)。

フィールド定義

エンティティタイプは、エンティティクラスの静的メソッドで基本フィールドを定義します。基本フィールドは、ノードのタイトルや作成/変更日時など、特定のエンティティタイプに常に存在する非設定フィールドです。エンティティマネージャーは、hook_entity_field_info() と hook_entity_field_info_alter() を呼び出すことにより、他のモジュールが提供するカスタムフィールドと非設定フィールドを補完します。これは、Field UI を通じて設定されたフィールドが追加される方法でもあります(これらのフックは API によるともはや存在しません)。

フィールド定義は FieldDefinitionInterface を実装する単純なオブジェクトであり、基本フィールドは通常 BaseFieldDefinition クラスを使用して作成され、カスタムフィールドは対応する設定オブジェクト(いわゆる Field と FieldInstance)とともにインターフェイスを直接実装します。
フィールド定義は、フィールドアイテムまたはフィールドアイテムのプロパティの検証制約を定義する場所でもあります。フィールドタイプのプラグイン実装はすべて使用できます。(このインターフェイスとクラスはもはや存在しません)。

現在、フィールドは常にフィールドアイテムのリストです。つまり、タイプとして定義された FieldItem クラスは、これらのフィールドアイテムのリストを表す FieldItemList クラスでラップされます。

すべてのフィールド(基本フィールドを含む)は、表示と編集のためのウィジェットとフォーマッターを持つこともできます。

基本フィールド

以下は、ノードエンティティタイプのフィールド定義の省略された例です。

use Drupal\Core\Field\BaseFieldDefinition;

class Node implements NodeInterface {

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions($entity_type) {
    // The node id is an integer, using the IntegerItem field item class.
    $fields['nid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Node ID'))
      ->setDescription(t('The node ID.'))
      ->setReadOnly(TRUE);

    // The UUID field uses the uuid_field type which ensures that a new UUID will automatically be generated when an entity is created.
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The node UUID.'))
      ->setReadOnly(TRUE);

    // The language code is defined as a language_field, which, again, ensures that a valid default language
    // code is set for new entities.
    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Language code'))
      ->setDescription(t('The node language code.'));

    // The title is StringItem, the default value is an empty string and defines a property constraint for the
    // value to be at most 255 characters long.
    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Title'))
      ->setDescription(t('The title of this node, always treated as non-markup plain text.'))
      ->setRequired(TRUE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 255,
      ));

    // The uid is an entity reference to the user entity type, which allows to access the user id with $node->uid->target_id
    // and the user entity with $node->uid->entity. NodeInterface also defines getAuthor() and getAuthorId(). (@todo: check owner vs. revisionAuthor)
    $fields['uid'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('User ID'))
      ->setDescription(t('The user ID of the node author.'))
      ->setSettings(array(
        'target_type' => 'user',
        'default_value' => 0,
      ));

    // The changed field type automatically updates the timestamp every time the
    // entity is saved.
    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the node was last edited.'))
    return $fields;
  }
}

複数値フィールド

フィールドに許可される最大アイテム数を指定するには、setCardinality() メソッドを呼び出します。
たとえば、3つの要素を持つことができるフィールドを定義するには:

->setCardinality(3);

無制限の値を持つフィールドを定義するには、次のように呼び出します:

->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);

「ユーザー」エンティティへの参照の複数値フィールドの定義例:

$fields['my_field'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('The label of the field'))
  ->setDescription(t('The description of the field.'))
  ->setRevisionable(TRUE)
  ->setSetting('target_type', 'user')
  ->setSetting('handler', 'default')
  ->setTranslatable(TRUE)
  ->setDisplayOptions('view', [
    'label' => 'hidden',
    'type' => 'author',
    'weight' => 0,
  ])
  ->setDisplayOptions('form', [
    'type' => 'entity_reference_autocomplete',
    'weight' => 5,
    'settings' => [
      'match_operator' => 'CONTAINS',
      'size' => '60',
      'autocomplete_type' => 'tags',
      'placeholder' => '',
    ],
  ])
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayConfigurable('view', TRUE);
  ->setRequired(TRUE)
  ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);

エンティティは、特定のバンドルにのみ存在するフィールドを提供したり、バンドルごとにフィールドを変更したりすることもできます。たとえば、ノードタイトルはバンドルごとに異なるラベルを持つことができます。バンドルごとの変更を可能にするには、変更を加える前に基本フィールド定義をクローンする必要があります。そうしないと、基本フィールド定義が変更され、すべてのバンドルに影響するからです。

use Drupal\node\Entity\NodeType;

  /**
   * {@inheritdoc}
   */
  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
    $node_type = NodeType::load($bundle);
    $fields = array();
    if (isset($node_type->title_label)) {
      $fields['title'] = clone $base_field_definitions['title'];
      $fields['title']->setLabel($node_type->title_label);
    }
    return $fields;
  }

フィールドタイプ

Drupal コアは、基本フィールドに使用できるフィールドタイプのリストを提供します。さらに、モジュールは、使用することもできる追加のフィールドタイプを提供できます。

  • 文字列(string): 単純な文字列
  • 論理値(boolean): 整数として格納される論理値。
  • 整数(integer): 最小値と最大値の検証設定を備えた整数(小数と浮動小数点数にも提供されます)
  • 小数(decimal): 設定可能な精度とスケールを持つ小数。
  • float: 浮動小数点数
  • 言語(language): 言語コードと、計算プロパティとしての言語を保持します
  • タイムスタンプ(timestamp): 整数として格納される Unix タイムスタンプ
  • 作成日時(created): デフォルト値として現在の時刻を使用するタイムスタンプ。
  • 変更日時(changed): エンティティが保存されるたびに現在の時刻に自動的に更新されるタイムスタンプ。
  • datetime: 日付は ISO 8601 文字列として格納されます。
  • URI: URI を保持します。link モジュールは、リンクのタイトルを含むことができ、内部または外部の URI/ルートを指すことができる link フィールドタイプも提供します。
  • uuid: デフォルト値として新しい UUID を生成する UUID フィールド。
  • Eメール(email): 適切な検証、ウィジェット、フォーマッターを備えた Eメール。
  • entity_reference: target_id と計算プロパティのエンティティフィールドを介したエンティティへの参照。entity_reference.module は、有効な場合にウィジェットとフォーマッターを提供します。
  • マップ(map): シリアル化された文字列として格納される、任意の数の任意プロパティを保持できます

設定可能なフィールド

追加のフィールドは、hook_entity_base_field_info() と hook_entity_bundle_field_info() で登録できます。次の例では、base フィールドと bundle フィールドを追加します。

use Drupal\Core\Field\BaseFieldDefinition;

/**
 * Implements hook_entity_base_field_info().
 */
function path_entity_base_field_info(EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') {
    $fields['path'] = BaseFieldDefinition::create('path')
      ->setLabel(t('The path alias'))
      ->setComputed(TRUE);

    return $fields;
  }
}

/**
 * Implements hook_entity_bundle_field_info().
 */
function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  if ($entity_type->isFieldable()) {
    // Configurable fields, which are always attached to a specific bundle, are
    // added 'by bundle'.
    return Field::fieldInfo()->getBundleInstances($entity_type->id(), $bundle);
  }
}

上記のそれぞれに対応する alter フックが存在します。

ストレージ

フィールドに特別な要件がない場合、Entity Field API はデータベースストレージを処理し、データベーススキーマを適宜更新できます。これは、計算フィールドとしてマークされていない(setComputed(TRUE))フィールド、または独自のフィールドストレージを提供することを明示的に指定していない(setCustomStorage(TRUE))フィールドのデフォルトです。

コンテンツが強調表示されているかどうかを示す単純な論理値を保持する新しい基本フィールドを、すべての Node エンティティに追加したいとします。

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;

/**
 * Implements hook_entity_base_field_info().
 */
function MYMODULE_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = array();

  // Add a 'Highlight' base field to all node types.
  if ($entity_type->id() === 'node') {
    $fields['highlight'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Highlight'))
      ->setDescription(t('Whether or not the node is highlighted.'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDisplayOptions('form', array(
        'type' => 'boolean_checkbox',
        'settings' => array(
          'display_label' => TRUE,
        ),
      ))
      ->setDisplayConfigurable('form', TRUE);
  }

  return $fields;
}

何度も試しましたが、update.php にアクセスしても列はデータベースに追加されませんでしたが、以下を実行すると

  \Drupal::entityTypeManager()->clearCachedDefinitions();
  \Drupal::service('entity.definition_update_manager')->applyUpdates();

データベースに列が作成されます。注: これにより、他のフィールド定義で保留されている可能性のある更新も実行されます。

更新: 上記のコードは Drupal 8.7 では機能しません

この変更記録の例を参照してください

新しいフィールドストレージ定義のインストール

function example_update_8701() {
  $field_storage_definition = BaseFieldDefinition::create('boolean')
    ->setLabel(t('Revision translation affected'))
    ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
    ->setReadOnly(TRUE)
    ->setRevisionable(TRUE)
    ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'block_content', 'block_content', $field_storage_definition);
}

カスタムモジュールが新しいフィールドを追加する場合、モジュールの有効化時に自動的に追加され、モジュールのアンインストール時に削除されます。

モジュールが既にインストールされており、フィールド定義を更新するために hook_update_N を書く必要がある場合は、次のようにします:

/**
 * Add in highlight field to all nodes.
 */
function MYMODULE_update_8001() {
  $entity_type = \Drupal::service('entity_type.manager')->getDefinition('node');
  \Drupal::service('entity.definition_update_manager')->updateEntityType($entity_type);
}

または

/**
 * Add 'revision_translation_affected' field to 'node' entities.
 */
function node_update_8001() {
  // Install the definition that this field had in
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // at the time that this update function was written. If/when code is
  // deployed that changes that definition, the corresponding module must
  // implement an update function that invokes
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // with the new definition.
  $storage_definition = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
}

詳細と例については、Https://www.drupal.org/node/2554097 を参照してください。

フィールド定義の操作

注. オブジェクトは複雑なデータであるため、ComplexDataInterface に従う必要があります。型付きデータの観点では、複雑なデータオブジェクトに含まれるすべての型付きデータ項目はプロパティです。この制限/強制名付けは将来解除される可能性があります。

// Checks whether an entity has a certain field.
$entity->hasField('field_tags');

// Returns an array with named keys for all fields and their
// definitions. For example the 'image' field.
$field_definitions = $entity->getFieldDefinitions();

// Returns an array with name keys for all field item properties and their
// definitions of the image field. For example the 'file_id' and 'alt' properties.
$property_definitions = $entity->image->getFieldDefinition()->getPropertyDefinitions();

// Returns only definition for the 'alt' property.
$alt_definition = $entity->image->getFieldDefinition()->getPropertyDefinition('alt');

// Entity field definitions can also be requested from the entity manager,
// the following returns all fields that are available for all bundles.
\Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type);

// The following returns fields that are available for the given bundle.
\Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle);

基本フィールド用のウィジェットとフォーマッター

基本フィールドは、設定可能なフィールドと同様に、使用するウィジェットとフォーマッターを指定できます。ウィジェットとフォーマッター、および必要なオプションは、FieldDefinition クラスで次のように指定します:

use Drupal\Core\Field\BaseFieldDefinition;

// ...

    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Title'))
      ->setDescription(t('The title of this node, always treated as non-markup plain text.'))
      ->setRequired(TRUE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 255,
      ))
      ->setDisplayOptions('view', array(
        'label' => 'hidden',
        'type' => 'string',
        'weight' => -5,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string',
        'weight' => -5,
      ))
      ->setDisplayConfigurable('form', TRUE);

これにより、「string」フォーマッターとウィジェットが使用され、ノードタイトルの重みが設定されます。setDisplayConfigurable() は、フォーム表示/表示管理 UI でフィールドを表示できるようにするために使用でき、順序やラベルの表示を変更できます。現在、コアでは UI でウィジェットやその設定を変更することはできません。

フィールドをデフォルトで非表示に設定するには、setDisplayOptions() に渡す配列で region キーを定義し、hidden に設定することもできます。