diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index f0855efd5c5..82e5241f6ff 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -213,9 +213,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C */ public function getDataDefinition() { $definition = EntityDataDefinition::create($this->getEntityTypeId()); - if ($this->bundle() != $this->getEntityTypeId()) { - $definition->setBundles(array($this->bundle())); - } + $definition->setBundles(array($this->bundle())); return $definition; } @@ -485,8 +483,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C */ public function getFieldDefinitions() { if (!isset($this->fieldDefinitions)) { - $bundle = $this->bundle != $this->entityTypeId ? $this->bundle : NULL; - $this->fieldDefinitions = \Drupal::entityManager()->getFieldDefinitions($this->entityTypeId, $bundle); + $this->fieldDefinitions = \Drupal::entityManager()->getFieldDefinitions($this->entityTypeId, $this->bundle()); } return $this->fieldDefinitions; } @@ -987,4 +984,11 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C return $referenced_entities; } + /** + * {@inheritdoc} + */ + public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { + return array(); + } + } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index 59f596c801f..dee43a0dd90 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -40,7 +40,7 @@ interface ContentEntityInterface extends EntityInterface, RevisionableInterface, public function initTranslation($langcode); /** - * Defines the base fields of the entity type. + * Provides base field definitions for an entity type. * * Implementations typically use the class \Drupal\Core\Field\FieldDefinition * for creating the field definitions; for example a 'name' field could be @@ -50,16 +50,47 @@ interface ContentEntityInterface extends EntityInterface, RevisionableInterface, * ->setLabel(t('Name')); * @endcode * - * @param string $entity_type - * The entity type to return properties for. Useful when a single class is - * used for multiple, possibly dynamic entity types. + * If some elements in a field definition need to vary by bundle, use + * \Drupal\Core\Entity\ContentEntityInterface::bundleFieldDefinitions(). + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. Useful when a single class is used for multiple, + * possibly dynamic entity types. * * @return \Drupal\Core\Field\FieldDefinitionInterface[] - * An array of entity field definitions, keyed by field name. + * An array of base field definitions for the entity type, keyed by field + * name. * * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() + * @see \Drupal\Core\Entity\ContentEntityInterface::bundleFieldDefinitions() */ - public static function baseFieldDefinitions($entity_type); + public static function baseFieldDefinitions(EntityTypeInterface $entity_type); + + /** + * Provides or alters field definitions for a specific bundle. + * + * The field definitions returned here for the bundle take precedence on the + * base field definitions specified by baseFieldDefinitions() for the entity + * type. + * + * @todo Provide a better DX for field overrides. + * See https://drupal.org/node/2145115. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. Useful when a single class is used for multiple, + * possibly dynamic entity types. + * @param string $bundle + * The bundle. + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions + * The list of base field definitions. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of bundle field definitions, keyed by field name. + * + * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() + * @see \Drupal\Core\Entity\ContentEntityInterface::baseFieldDefinitions() + */ + public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions); /** * Returns whether the entity has a field with the given name. diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 5684a9dbef0..5bfd687fdba 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -78,13 +78,11 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface protected $languageManager; /** - * An array of field information per entity type, i.e. containing definitions. + * Static cache of base field definitions. * * @var array - * - * @see hook_entity_field_info() */ - protected $entityFieldInfo; + protected $baseFieldDefinitions; /** * Static cache of field definitions per bundle and entity type. @@ -296,87 +294,140 @@ class EntityManager extends PluginManagerBase implements EntityManagerInterface /** * {@inheritdoc} */ - public function getFieldDefinitions($entity_type_id, $bundle = NULL) { - if (!isset($this->entityFieldInfo[$entity_type_id])) { - // First, try to load from cache. - $cid = 'entity_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->id; + public function getBaseFieldDefinitions($entity_type_id) { + // Check the static cache. + if (!isset($this->baseFieldDefinitions[$entity_type_id])) { + // Not prepared, try to load from cache. + $cid = 'entity_base_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->id; if ($cache = $this->cache->get($cid)) { - $this->entityFieldInfo[$entity_type_id] = $cache->data; + $this->baseFieldDefinitions[$entity_type_id] = $cache->data; } else { - // @todo: Refactor to allow for per-bundle overrides. - // See https://drupal.org/node/2114707. - $entity_type = $this->getDefinition($entity_type_id); - $class = $entity_type->getClass(); + // Rebuild the definitions and put it into the cache. + $this->baseFieldDefinitions[$entity_type_id] = $this->buildBaseFieldDefinitions($entity_type_id); + $this->cache->set($cid, $this->baseFieldDefinitions[$entity_type_id], Cache::PERMANENT, array('entity_types' => TRUE, 'entity_field_info' => TRUE)); + } + } + return $this->baseFieldDefinitions[$entity_type_id]; + } - $base_definitions = $class::baseFieldDefinitions($entity_type_id); - foreach ($base_definitions as &$base_definition) { - $base_definition->setTargetEntityTypeId($entity_type_id); - } - $this->entityFieldInfo[$entity_type_id] = array( - 'definitions' => $base_definitions, - // Contains definitions of optional (per-bundle) fields. - 'optional' => array(), - // An array keyed by bundle name containing the optional fields added - // by the bundle. - 'bundle map' => array(), - ); + /** + * Builds base field definitions for an entity type. + * + * @param string $entity_type_id + * The entity type ID. Only entity types that implement + * \Drupal\Core\Entity\ContentEntityInterface are supported + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of field definitions, keyed by field name. + * + * @throws \LogicException + * Thrown if one of the entity keys is flagged as translatable. + */ + protected function buildBaseFieldDefinitions($entity_type_id) { + $entity_type = $this->getDefinition($entity_type_id); + $class = $entity_type->getClass(); - // Invoke hooks. - $result = $this->moduleHandler->invokeAll($entity_type_id . '_field_info'); - $this->entityFieldInfo[$entity_type_id] = NestedArray::mergeDeep($this->entityFieldInfo[$entity_type_id], $result); - $result = $this->moduleHandler->invokeAll('entity_field_info', array($entity_type_id)); - $this->entityFieldInfo[$entity_type_id] = NestedArray::mergeDeep($this->entityFieldInfo[$entity_type_id], $result); + $base_field_definitions = $class::baseFieldDefinitions($entity_type); - // Automatically set the field name for non-configurable fields. - foreach (array('definitions', 'optional') as $key) { - foreach ($this->entityFieldInfo[$entity_type_id][$key] as $field_name => &$definition) { - if ($definition instanceof FieldDefinition) { - $definition->setName($field_name); - } - } - } + // Invoke hook. + $result = $this->moduleHandler->invokeAll('entity_base_field_info', array($entity_type)); + $base_field_definitions = NestedArray::mergeDeep($base_field_definitions, $result); - // Invoke alter hooks. - $hooks = array('entity_field_info', $entity_type_id . '_field_info'); - $this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type_id], $entity_type_id); - - // Ensure all basic fields are not defined as translatable. - $keys = array_intersect_key(array_filter($entity_type->getKeys()), array_flip(array('id', 'revision', 'uuid', 'bundle'))); - $untranslatable_fields = array_flip(array('langcode') + $keys); - foreach (array('definitions', 'optional') as $key) { - foreach ($this->entityFieldInfo[$entity_type_id][$key] as $field_name => &$definition) { - if (isset($untranslatable_fields[$field_name]) && $definition->isTranslatable()) { - throw new \LogicException(String::format('The @field field cannot be translatable.', array('@field' => $definition->getLabel()))); - } - } - } - - $this->cache->set($cid, $this->entityFieldInfo[$entity_type_id], Cache::PERMANENT, array('entity_types' => TRUE, 'entity_field_info' => TRUE)); + // Automatically set the field name for non-configurable fields. + foreach ($base_field_definitions as $field_name => $base_field_definition) { + if ($base_field_definition instanceof FieldDefinition) { + $base_field_definition->setName($field_name); + $base_field_definition->setTargetEntityTypeId($entity_type_id); } } - if (!$bundle) { - return $this->entityFieldInfo[$entity_type_id]['definitions']; - } - else { - // Add in per-bundle fields. - if (!isset($this->fieldDefinitions[$entity_type_id][$bundle])) { - $this->fieldDefinitions[$entity_type_id][$bundle] = $this->entityFieldInfo[$entity_type_id]['definitions']; - if (isset($this->entityFieldInfo[$entity_type_id]['bundle map'][$bundle])) { - $this->fieldDefinitions[$entity_type_id][$bundle] += array_intersect_key($this->entityFieldInfo[$entity_type_id]['optional'], array_flip($this->entityFieldInfo[$entity_type_id]['bundle map'][$bundle])); - } + // Invoke alter hook. + $this->moduleHandler->alter('entity_base_field_info', $base_field_definitions, $entity_type); + + // Ensure all basic fields are not defined as translatable. + $keys = array_intersect_key(array_filter($entity_type->getKeys()), array_flip(array('id', 'revision', 'uuid', 'bundle'))); + $untranslatable_fields = array_flip(array('langcode') + $keys); + foreach ($base_field_definitions as $field_name => $definition) { + if (isset($untranslatable_fields[$field_name]) && $definition->isTranslatable()) { + throw new \LogicException(String::format('The @field field cannot be translatable.', array('@field' => $definition->getLabel()))); } - return $this->fieldDefinitions[$entity_type_id][$bundle]; } + + return $base_field_definitions; + } + + /** + * {@inheritdoc} + */ + public function getFieldDefinitions($entity_type_id, $bundle) { + if (!isset($this->fieldDefinitions[$entity_type_id][$bundle])) { + $base_field_definitions = $this->getBaseFieldDefinitions($entity_type_id); + // Not prepared, try to load from cache. + $cid = 'entity_bundle_field_definitions:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->id; + if ($cache = $this->cache->get($cid)) { + $bundle_field_definitions = $cache->data; + } + else { + // Rebuild the definitions and put it into the cache. + $bundle_field_definitions = $this->buildBuildFieldDefinitions($entity_type_id, $bundle, $base_field_definitions); + $this->cache->set($cid, $bundle_field_definitions, Cache::PERMANENT, array('entity_types' => TRUE, 'entity_field_info' => TRUE)); + } + // Field definitions consist of the bundle specific overrides and the + // base fields, merge them together. Use array_replace() to replace base + // fields with by bundle overrides and keep them in order, append + // additional by bundle fields. + $this->fieldDefinitions[$entity_type_id][$bundle] = array_replace($base_field_definitions, $bundle_field_definitions); + } + return $this->fieldDefinitions[$entity_type_id][$bundle]; + } + + /** + * Builds field definitions for a specific bundle within an entity type. + * + * @param string $entity_type_id + * The entity type ID. Only entity types that implement + * \Drupal\Core\Entity\ContentEntityInterface are supported. + * @param string $bundle + * The bundle. + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions + * The list of base field definitions. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of bundle field definitions, keyed by field name. Does + * not include base fields. + */ + protected function buildBuildFieldDefinitions($entity_type_id, $bundle, array $base_field_definitions) { + $entity_type = $this->getDefinition($entity_type_id); + $class = $entity_type->getClass(); + + // Allow the entity class to override the base fields. + $bundle_field_definitions = $class::bundleFieldDefinitions($entity_type, $bundle, $base_field_definitions); + + // Invoke 'per bundle' hook. + $result = $this->moduleHandler->invokeAll('entity_bundle_field_info', array($entity_type, $bundle, $base_field_definitions)); + $bundle_field_definitions = NestedArray::mergeDeep($bundle_field_definitions, $result); + + // Automatically set the field name for non-configurable fields. + foreach ($bundle_field_definitions as $field_name => $field_definition) { + if ($field_definition instanceof FieldDefinition) { + $field_definition->setName($field_name); + $field_definition->setTargetEntityTypeId($entity_type_id); + } + } + + // Invoke 'per bundle' alter hook. + $this->moduleHandler->alter('entity_bundle_field_info', $bundle_field_definitions, $entity_type, $bundle); + + return $bundle_field_definitions; } /** * {@inheritdoc} */ public function clearCachedFieldDefinitions() { - unset($this->entityFieldInfo); - unset($this->fieldDefinitions); + $this->baseFieldDefinitions = array(); + $this->fieldDefinitions = array(); Cache::deleteTags(array('entity_field_info' => TRUE)); } diff --git a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php index 1cb7ab4b041..e40ff94a0d9 100644 --- a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php @@ -23,23 +23,38 @@ interface EntityManagerInterface extends PluginManagerInterface { public function getEntityTypeLabels(); /** - * Gets an array of content entity field definitions. + * Gets the base field definitions for a content entity type. * - * If a bundle is passed, fields specific to this bundle are included. + * Only fields that are not specific to a given bundle or set of bundles are + * returned. This excludes configurable fields, as they are always attached + * to a specific bundle. * * @param string $entity_type_id - * The entity type to get field definitions for. Only entity types that - * implement \Drupal\Core\Entity\ContentEntityInterface are supported. - * @param string $bundle - * (optional) The entity bundle for which to get field definitions. If NULL - * is passed, no bundle-specific fields are included. Defaults to NULL. + * The entity type ID. Only entity types that implement + * \Drupal\Core\Entity\ContentEntityInterface are supported. * * @return \Drupal\Core\Field\FieldDefinitionInterface[] - * An array of entity field definitions, keyed by field name. + * The array of base field definitions for the entity type, keyed by field + * name. * - * @see \Drupal\Core\TypedData\TypedDataManager::create() + * @throws \LogicException + * Thrown if one of the entity keys is flagged as translatable. */ - public function getFieldDefinitions($entity_type_id, $bundle = NULL); + public function getBaseFieldDefinitions($entity_type_id); + + /** + * Gets the field definitions for a specific bundle. + * + * @param string $entity_type_id + * The entity type ID. Only entity types that implement + * \Drupal\Core\Entity\ContentEntityInterface are supported. + * @param string $bundle + * The bundle. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * The array of field definitions for the bundle, keyed by field name. + */ + public function getFieldDefinitions($entity_type_id, $bundle); /** * Creates a new access controller instance. diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php index 222145f99aa..ec66b05518e 100644 --- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php @@ -268,7 +268,7 @@ class FieldableDatabaseStorageController extends FieldableEntityStorageControlle } $data = $query->execute(); - $field_definitions = \Drupal::entityManager()->getFieldDefinitions($this->entityTypeId); + $field_definitions = \Drupal::entityManager()->getBaseFieldDefinitions($this->entityTypeId); $translations = array(); if ($this->revisionDataTable) { $data_column_names = array_flip(array_diff(drupal_schema_fields_sql($this->entityType->getRevisionDataTable()), drupal_schema_fields_sql($this->entityType->getBaseTable()))); @@ -1187,7 +1187,7 @@ class FieldableDatabaseStorageController extends FieldableEntityStorageControlle $entity_type_id = $field->entity_type; $entity_manager = \Drupal::entityManager(); $entity_type = $entity_manager->getDefinition($entity_type_id); - $definitions = $entity_manager->getFieldDefinitions($entity_type_id); + $definitions = $entity_manager->getBaseFieldDefinitions($entity_type_id); // Define the entity ID schema based on the field definitions. $id_definition = $definitions[$entity_type->getKey('id')]; diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php index 87c68669cfe..e3302a518f3 100644 --- a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php +++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php @@ -60,8 +60,12 @@ class EntityDataDefinition extends ComplexDataDefinitionBase implements EntityDa // @todo: Add support for handling multiple bundles. // See https://drupal.org/node/2169813. $bundles = $this->getBundles(); - $bundle = is_array($bundles) && count($bundles) == 1 ? reset($bundles) : NULL; - $this->propertyDefinitions = \Drupal::entityManager()->getFieldDefinitions($entity_type_id, $bundle); + if (is_array($bundles) && count($bundles) == 1) { + $this->propertyDefinitions = \Drupal::entityManager()->getFieldDefinitions($entity_type_id, reset($bundles)); + } + else { + $this->propertyDefinitions = \Drupal::entityManager()->getBaseFieldDefinitions($entity_type_id); + } } else { // No entity type given. diff --git a/core/lib/Drupal/Core/Field/ConfigFieldItemList.php b/core/lib/Drupal/Core/Field/ConfigFieldItemList.php index a33ef10a683..35b7098a8ba 100644 --- a/core/lib/Drupal/Core/Field/ConfigFieldItemList.php +++ b/core/lib/Drupal/Core/Field/ConfigFieldItemList.php @@ -7,60 +7,16 @@ namespace Drupal\Core\Field; -use Drupal\field\FieldInstanceConfigInterface; -use Drupal\Core\TypedData\TypedDataInterface; -use Drupal\field\Field; - /** * Represents a configurable entity field item list. */ class ConfigFieldItemList extends FieldItemList implements ConfigFieldItemListInterface { - /** - * The Field instance definition. - * - * @var \Drupal\field\FieldInstanceConfigInterface - */ - protected $instance; - - /** - * {@inheritdoc} - */ - public function __construct($definition, $name = NULL, TypedDataInterface $parent = NULL) { - parent::__construct($definition, $name, $parent); - // Definition can be the field config or field instance. - if ($definition instanceof FieldInstanceConfigInterface) { - $this->instance = $definition; - } - } - - /** - * {@inheritdoc} - */ - public function getFieldDefinition() { - // Configurable fields have the field_config entity injected as definition, - // but we want to return the more specific field instance here. - // @todo: Overhaul this once we have per-bundle field definitions injected, - // see https://drupal.org/node/2114707. - if (!isset($this->instance)) { - $entity = $this->getEntity(); - $instances = Field::fieldInfo()->getBundleInstances($entity->getEntityTypeId(), $entity->bundle()); - if (isset($instances[$this->getName()])) { - $this->instance = $instances[$this->getName()]; - } - else { - // For base fields, fall back to return the general definition. - return parent::getFieldDefinition(); - } - } - return $this->instance; - } - /** * {@inheritdoc} */ public function getConstraints() { - $constraints = array(); + $constraints = parent::getConstraints(); // Check that the number of values doesn't exceed the field cardinality. For // form submitted values, this can only happen with 'multiple value' // widgets. diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index ff77acb6622..e9fe3ad9b98 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -437,4 +437,13 @@ class TypedDataManager extends DefaultPluginManager { return $constraints; } + + /** + * {@inheritdoc} + */ + public function clearCachedDefinitions() { + parent::clearCachedDefinitions(); + $this->prototypes = array(); + } + } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php index 3ade60ec4fe..1a6bcdf8ea8 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php @@ -8,6 +8,7 @@ namespace Drupal\aggregator\Entity; use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Symfony\Component\DependencyInjection\Container; use Drupal\Core\Entity\EntityStorageControllerInterface; @@ -120,7 +121,7 @@ class Feed extends ContentEntityBase implements FeedInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['fid'] = FieldDefinition::create('integer') ->setLabel(t('Feed ID')) ->setDescription(t('The ID of the aggregator feed.')) diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php index 191f5bcc582..dfc07aa73e0 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php @@ -10,6 +10,7 @@ namespace Drupal\aggregator\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\aggregator\ItemInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; /** @@ -60,7 +61,7 @@ class Item extends ContentEntityBase implements ItemInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['iid'] = FieldDefinition::create('integer') ->setLabel(t('Aggregator item ID')) ->setDescription(t('The ID of the feed item.')) diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php index c2b03255c6e..008774f0fc1 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php @@ -9,6 +9,7 @@ namespace Drupal\custom_block\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\custom_block\CustomBlockInterface; @@ -163,7 +164,7 @@ class CustomBlock extends ContentEntityBase implements CustomBlockInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['id'] = FieldDefinition::create('integer') ->setLabel(t('Custom block ID')) ->setDescription(t('The custom block ID.')) diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php index 321dfc40070..08aa9a3963d 100644 --- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php +++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php @@ -11,6 +11,7 @@ use Drupal\Component\Utility\Number; use Drupal\Core\Entity\ContentEntityBase; use Drupal\comment\CommentInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Language\Language; use Drupal\Core\TypedData\DataDefinition; @@ -210,7 +211,7 @@ class Comment extends ContentEntityBase implements CommentInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['cid'] = FieldDefinition::create('integer') ->setLabel(t('Comment ID')) ->setDescription(t('The comment ID.')) diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentValidationTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentValidationTest.php index 5f7e03f3753..020e1ab136b 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentValidationTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentValidationTest.php @@ -69,6 +69,7 @@ class CommentValidationTest extends EntityUnitTestBase { 'entity_id' => $node->id(), 'entity_type' => 'node', 'field_name' => 'comment', + 'comment_body' => $this->randomName(), )); $violations = $comment->validate(); diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php index 62b83d9ab78..a3a62cb985c 100644 --- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php +++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php @@ -9,6 +9,7 @@ namespace Drupal\contact\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\contact\MessageInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; /** @@ -139,7 +140,7 @@ class Message extends ContentEntityBase implements MessageInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['category'] = FieldDefinition::create('entity_reference') ->setLabel(t('Category ID')) ->setDescription(t('The ID of the associated category.')) diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index ba0022ba060..b6f8f5eb016 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -9,6 +9,8 @@ use Drupal\content_translation\Plugin\Derivative\ContentTranslationLocalTasks; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityFormControllerInterface; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; use Drupal\Core\TypedData\TranslatableInterface; @@ -143,27 +145,23 @@ function content_translation_entity_bundle_info_alter(&$bundles) { } /** - * Implements hook_entity_field_info_alter(). + * Implements hook_entity_base_field_info_alter(). */ -function content_translation_entity_field_info_alter(&$info, $entity_type) { - $translation_settings = \Drupal::config('content_translation.settings')->get($entity_type); +function content_translation_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { + $translation_settings = \Drupal::config('content_translation.settings')->get($entity_type->id()); if ($translation_settings) { // Currently field translatability is defined per-field but we may want to - // make it per-instance instead, so leaving the possibility open for further - // easier refactoring. - $fields = array(); + // make it per-instance instead. In that case, we will need to implement + // hook_bundle_field_info_alter() instead. + $field_settings = array(); foreach ($translation_settings as $bundle => $settings) { - $fields += !empty($settings['content_translation']['fields']) ? $settings['content_translation']['fields'] : array(); + $field_settings += !empty($settings['content_translation']['fields']) ? $settings['content_translation']['fields'] : array(); } - $keys = array('definitions', 'optional'); - foreach ($fields as $name => $translatable) { - foreach ($keys as $key) { - if (isset($info[$key][$name])) { - $info[$key][$name]->setTranslatable((bool) $translatable); - break; - } + foreach ($field_settings as $name => $translatable) { + if (isset($fields[$name]) && $fields[$name] instanceof FieldDefinition) { + $fields[$name]->setTranslatable((bool) $translatable); } } } diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php index fb31666cba2..93d132d0517 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php @@ -10,7 +10,6 @@ namespace Drupal\entity; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Entity\Display\EntityDisplayInterface; /** @@ -325,20 +324,14 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl * Returns the definitions of the fields that are candidate for display. */ protected function getFieldDefinitions() { + // Entity displays are sometimes created for non-content entities. + // @todo Prevent this in https://drupal.org/node/2095195. + if (!\Drupal::entityManager()->getDefinition($this->targetEntityType)->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { + return array(); + } + if (!isset($this->fieldDefinitions)) { - // @todo Replace this with \Drupal::entityManager()->getFieldDefinition() - // when it can hand the $instance objects (and then reconsider the - // $this->fieldDefinitions static cache ?) - // https://drupal.org/node/2114707 - $entity_manager = \Drupal::entityManager(); - $entity_type = $entity_manager->getDefinition($this->targetEntityType); - $definitions = array(); - if ($entity_type->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { - $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->targetEntityType, 'bundle' => $this->bundle, 'entity_id' => NULL)); - foreach ($entity as $field_name => $items) { - $definitions[$field_name] = $items->getFieldDefinition(); - } - } + $definitions = \Drupal::entityManager()->getFieldDefinitions($this->targetEntityType, $this->bundle); // The display only cares about fields that specify display options. // Discard base fields that are not rendered through formatters / widgets. diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php index 987919dc571..84e48f8a912 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutocompleteTest.php @@ -23,14 +23,14 @@ class EntityReferenceAutocompleteTest extends EntityUnitTestBase { * * @var string */ - protected $entityType = 'entity_test_label'; + protected $entityType = 'entity_test'; /** * The bundle used in this test. * * @var string */ - protected $bundle = 'entity_test_label'; + protected $bundle = 'entity_test'; /** * The name of the field used in this test. diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index d6130919b09..3898037b40b 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -124,31 +124,18 @@ function field_invoke_method($method, $target_function, EntityInterface $entity, * @param $options * An associative array of options, as provided to field_invoke_method(). Only * the following keys are considered: - * - deleted * - field_name - * - field_id * See field_invoke_method() for details. * * @return * The array of selected field definitions. */ function _field_invoke_get_field_definitions($entity_type, $bundle, $options) { - // @todo Replace with \Drupal::entityManager()->getFieldDefinition() after - // [#2047229] lands. - $entity = _field_create_entity_from_ids((object) array('entity_type' => $entity_type, 'bundle' => $bundle, 'entity_id' => NULL)); - $field_definitions = array(); + $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $bundle); if (isset($options['field_name'])) { - if ($entity->hasField($options['field_name'])) { - $field_definitions[] = $entity->get($options['field_name'])->getFieldDefinition(); - } + $definitions = array_intersect_key($definitions, array($options['field_name'] => TRUE)); } - else { - foreach ($entity as $items) { - $field_definitions[] = $items->getFieldDefinition(); - } - } - - return $field_definitions; + return $definitions; } /** diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 9d2dd06231d..0305928f478 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -7,8 +7,10 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Xss; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Template\Attribute; use Drupal\entity\Entity\EntityViewDisplay; +use Drupal\field\Field; /* * Load all public Field API functions. Drupal currently has no @@ -189,29 +191,14 @@ function field_system_info_alter(&$info, $file, $type) { } /** - * Implements hook_entity_field_info() to define all configured fields. + * Implements hook_entity_bundle_field_info(). */ -function field_entity_field_info($entity_type) { - $property_info = array(); - - foreach (field_info_instances($entity_type) as $bundle_name => $instances) { - $optional = $bundle_name != $entity_type; - // @todo: Improve hook_entity_field_info() to allow per-bundle field - // definitions, such that we can pass on field instances as field - // definitions here. See https://drupal.org/node/2114707. - - foreach ($instances as $field_name => $instance) { - if ($optional) { - $property_info['optional'][$field_name] = $instance->getField(); - $property_info['bundle map'][$bundle_name][] = $field_name; - } - else { - $property_info['definitions'][$field_name] = $instance->getField(); - } - } +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); } - - return $property_info; } /** diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php index 9428dc00806..1c0518eedae 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php @@ -162,7 +162,7 @@ class FieldAttachOtherTest extends FieldUnitTestBase { // Create two entities. $entity1 = entity_create('entity_test', array('id' => 1, 'type' => 'entity_test')); $entity1->{$this->field_name}->setValue($this->_generateTestFieldValues(1)); - $entity2 = entity_create('entity_test', array('id' => 2, 'type' => 'test_bundle')); + $entity2 = entity_create('entity_test', array('id' => 2, 'type' => 'entity_test')); $entity2->{$this->field_name}->setValue($this->_generateTestFieldValues(1)); // Run buildMultiple(), and check that the entities come out as expected. diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php index ce2eb1d5a2c..ecd41fd40f2 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php @@ -104,17 +104,8 @@ abstract class DisplayOverviewBase extends OverviewBase { * The array of field definitions */ protected function getFieldDefinitions() { - // @todo Replace this entire implementation with - // \Drupal::entityManager()->getFieldDefinition() when it can hand the - // $instance objects - https://drupal.org/node/2114707 - $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->entity_type, 'bundle' => $this->bundle, 'entity_id' => NULL)); - $field_definitions = array(); - foreach ($entity as $field_name => $items) { - $field_definitions[$field_name] = $items->getFieldDefinition(); - } - $context = $this->displayContext; - return array_filter($field_definitions, function(FieldDefinitionInterface $field_definition) use ($context) { + return array_filter($this->entityManager->getFieldDefinitions($this->entity_type, $this->bundle), function(FieldDefinitionInterface $field_definition) use ($context) { return $field_definition->isDisplayConfigurable($context); }); } diff --git a/core/modules/file/lib/Drupal/file/Entity/File.php b/core/modules/file/lib/Drupal/file/Entity/File.php index d74dee8331f..e883d135c0c 100644 --- a/core/modules/file/lib/Drupal/file/Entity/File.php +++ b/core/modules/file/lib/Drupal/file/Entity/File.php @@ -9,6 +9,7 @@ namespace Drupal\file\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Language\Language; use Drupal\file\FileInterface; @@ -240,7 +241,7 @@ class File extends ContentEntityBase implements FileInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['fid'] = FieldDefinition::create('integer') ->setLabel(t('File ID')) ->setDescription(t('The file ID.')) diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php index fcacb46cc0f..62f697f38ad 100644 --- a/core/modules/node/lib/Drupal/node/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Entity/Node.php @@ -9,6 +9,7 @@ namespace Drupal\node\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; @@ -351,7 +352,7 @@ class Node extends ContentEntityBase implements NodeInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['nid'] = FieldDefinition::create('integer') ->setLabel(t('Node ID')) ->setDescription(t('The node ID.')) @@ -378,11 +379,8 @@ class Node extends ContentEntityBase implements NodeInterface { ->setDescription(t('The node language code.')); $fields['title'] = FieldDefinition::create('text') - // @todo Account for $node_type->title_label when per-bundle overrides are - // possible - https://drupal.org/node/2114707. ->setLabel(t('Title')) ->setDescription(t('The title of this node, always treated as non-markup plain text.')) - ->setClass('\Drupal\node\NodeTitleItemList') ->setRequired(TRUE) ->setTranslatable(TRUE) ->setSettings(array( @@ -451,4 +449,17 @@ class Node extends ContentEntityBase implements NodeInterface { return $fields; } + /** + * {@inheritdoc} + */ + public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { + $node_type = node_type_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; + } + } diff --git a/core/modules/node/lib/Drupal/node/NodeTitleItemList.php b/core/modules/node/lib/Drupal/node/NodeTitleItemList.php deleted file mode 100644 index 2b811931ffb..00000000000 --- a/core/modules/node/lib/Drupal/node/NodeTitleItemList.php +++ /dev/null @@ -1,34 +0,0 @@ -getType()); - if (isset($node_type->title_label)) { - $definition->setLabel($node_type->title_label); - } - parent::__construct($definition, $name, $node); - } - -} diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module index 128b31a98a5..9913431791a 100644 --- a/core/modules/node/tests/modules/node_access_test/node_access_test.module +++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -9,6 +9,7 @@ * a special 'node test view' permission. */ +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\node\NodeInterface; @@ -78,15 +79,15 @@ function node_access_test_permission() { } /** - * Implements hook_entity_field_info(). + * Implements hook_entity_base_field_info(). */ -function node_access_test_entity_field_info($entity_type) { - if ($entity_type === 'node') { - $info['definitions']['private'] = FieldDefinition::create('boolean') - ->setLabel(t('Private')) - ->setComputed(TRUE); +function node_access_test_entity_base_field_info(EntityTypeInterface $entity_type) { + if ($entity_type->id() === 'node') { + $fields['private'] = FieldDefinition::create('boolean') + ->setLabel(t('Private')) + ->setComputed(TRUE); - return $info; + return $fields; } } diff --git a/core/modules/path/path.module b/core/modules/path/path.module index b2ad95cfd59..20d9fae9113 100644 --- a/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -5,6 +5,7 @@ * Enables users to rename URLs. */ +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Language\Language; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\ContentEntityInterface; @@ -197,14 +198,14 @@ function path_form_taxonomy_term_form_alter(&$form, $form_state) { } /** - * Implements hook_entity_field_info(). + * Implements hook_entity_base_field_info(). */ -function path_entity_field_info($entity_type) { - if ($entity_type === 'taxonomy_term' || $entity_type === 'node') { - $info['definitions']['path'] = FieldDefinition::create('path') +function path_entity_base_field_info(EntityTypeInterface $entity_type) { + if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') { + $fields['path'] = FieldDefinition::create('path') ->setLabel(t('The path alias')) ->setComputed(TRUE); - return $info; + return $fields; } } diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php index b609bbd9b0d..2ba7625d9f6 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/Shortcut.php @@ -9,6 +9,7 @@ namespace Drupal\shortcut\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Routing\UrlMatcher; use Drupal\Core\Url; @@ -133,7 +134,7 @@ class Shortcut extends ContentEntityBase implements ShortcutInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['id'] = FieldDefinition::create('integer') ->setLabel(t('ID')) ->setDescription(t('The ID of the shortcut.')) diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index cdd594654c3..aefb73b9527 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -659,62 +659,101 @@ function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDi } /** - * Define custom entity fields. + * Provides custom base field definitions for a content entity type. * - * @param string $entity_type_id - * The entity type for which to define entity fields. + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. * - * @return array - * An array of entity field information having the following optional entries: - * - definitions: An array of field definitions to add to all entities of this - * type, keyed by field name. - * - optional: An array of field definitions for optional entity fields, keyed - * by field name. Optional fields are fields that only exist for certain - * bundles of the entity type. - * - bundle map: An array keyed by bundle name, containing the names of - * optional fields that entities of this bundle have. + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of field definitions, keyed by field name. * - * @see hook_entity_field_info_alter() + * @see hook_entity_base_field_info_alter() + * @see hook_entity_bundle_field_info() + * @see hook_entity_bundle_field_info_alter() * @see \Drupal\Core\Field\FieldDefinitionInterface * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() - * @see \Drupal\Core\TypedData\TypedDataManager::create() */ -function hook_entity_field_info($entity_type_id) { - if (mymodule_uses_entity_type($entity_type_id)) { - $info = array(); - $info['definitions']['mymodule_text'] = FieldDefinition::create('string') +function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) { + if ($entity_type->id() == 'node') { + $fields = array(); + $fields['mymodule_text'] = FieldDefinition::create('string') ->setLabel(t('The text')) ->setDescription(t('A text property added by mymodule.')) ->setComputed(TRUE) ->setClass('\Drupal\mymodule\EntityComputedText'); - if ($entity_type_id == 'node') { - // Add a property only to entities of the 'article' bundle. - $info['optional']['mymodule_text_more'] = FieldDefinition::create('string') - ->setLabel(t('More text')) - ->setComputed(TRUE) - ->setClass('\Drupal\mymodule\EntityComputedMoreText'); - - $info['bundle map']['article'][0] = 'mymodule_text_more'; - } - return $info; + return $fields; } } /** - * Alter defined entity fields. + * Alters base field definitions for a content entity type. * - * @param array $info - * The entity field info array as returned by hook_entity_field_info(). - * @param string $entity_type_id - * The entity type for which entity fields are defined. + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields + * The array of base field definitions for the entity type. + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. * - * @see hook_entity_field_info() + * @see hook_entity_base_field_info() + * @see hook_entity_bundle_field_info() + * @see hook_entity_bundle_field_info_alter() */ -function hook_entity_field_info_alter(&$info, $entity_type_id) { - if (!empty($info['definitions']['mymodule_text'])) { +function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) { + // Alter the mymodule_text field to use a custom class. + if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) { + $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText'); + } +} + +/** + * Provides field definitions for a specific bundle within an entity type. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param string $bundle + * The bundle. + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions + * The list of base field definitions for the entity type. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * An array of bundle field definitions, keyed by field name. + * + * @see hook_entity_base_field_info() + * @see hook_entity_base_field_info_alter() + * @see hook_entity_bundle_field_info_alter() + * @see \Drupal\Core\Field\FieldDefinitionInterface + * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() + */ +function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { + // Add a property only to nodes of the 'article' bundle. + if ($entity_type->id() == 'node' && $bundle == 'article') { + $fields = array(); + $fields['mymodule_text_more'] = FieldDefinition::create('string') + ->setLabel(t('More text')) + ->setComputed(TRUE) + ->setClass('\Drupal\mymodule\EntityComputedMoreText'); + return $fields; + } +} + +/** + * Alters bundle field definitions. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields + * The array of bundle field definitions. + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param string $bundle + * The bundle. + * + * @see hook_entity_base_field_info() + * @see hook_entity_base_field_info_alter() + * @see hook_entity_bundle_field_info() + */ +function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) { + if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) { // Alter the mymodule_text field to use a custom class. - $info['definitions']['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText'); + $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php index eece8321d16..5dcfd38aaab 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php @@ -356,8 +356,9 @@ class EntityFieldTest extends EntityUnitTestBase { * The entity type to run the tests with. */ protected function checkIntrospection($entity_type) { - // Test getting metadata upfront. - $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type); + // Test getting metadata upfront. The entity types used for this test have + // a default bundle that is the same as the entity type. + $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $entity_type); $this->assertEqual($definitions['name']->getType(), 'string', $entity_type .': Name field found.'); $this->assertEqual($definitions['user_id']->getType(), 'entity_reference', $entity_type .': User field found.'); $this->assertEqual($definitions['field_test_text']->getType(), 'text', $entity_type .': Test-text-field field found.'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php index 286599186c3..d3b58429664 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php @@ -513,16 +513,16 @@ class EntityTranslationTest extends EntityLanguageTestBase { $entity_type = 'entity_test_mulrev'; $this->state->set('entity_test.field_definitions.translatable', array('name' => FALSE)); $this->entityManager->clearCachedFieldDefinitions(); - $definitions = $this->entityManager->getFieldDefinitions($entity_type); + $definitions = $this->entityManager->getBaseFieldDefinitions($entity_type); $this->assertFalse($definitions['name']->isTranslatable(), 'Field translatability can be disabled programmatically.'); $this->state->set('entity_test.field_definitions.translatable', array('name' => TRUE)); $this->entityManager->clearCachedFieldDefinitions(); - $definitions = $this->entityManager->getFieldDefinitions($entity_type); + $definitions = $this->entityManager->getBaseFieldDefinitions($entity_type); $this->assertTrue($definitions['name']->isTranslatable(), 'Field translatability can be enabled programmatically.'); // Check that field translatability is disabled by default. - $base_field_definitions = EntityTestMulRev::baseFieldDefinitions($entity_type); + $base_field_definitions = EntityTestMulRev::baseFieldDefinitions($this->entityManager->getDefinition($entity_type)); $this->assertTrue(!isset($base_field_definitions['id']->translatable), 'Translatability for the id field is not defined.'); $this->assertFalse($definitions['id']->isTranslatable(), 'Field translatability is disabled by default.'); @@ -533,7 +533,7 @@ class EntityTranslationTest extends EntityLanguageTestBase { $message = format_string('Field %field cannot be translatable.', array('%field' => $name)); try { - $definitions = $this->entityManager->getFieldDefinitions($entity_type); + $this->entityManager->getBaseFieldDefinitions($entity_type); $this->fail($message); } catch (\LogicException $e) { diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php index 23a62e1359e..e2669d5d771 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTypedDataDefinitionTest.php @@ -100,7 +100,7 @@ class EntityTypedDataDefinitionTest extends DrupalUnitTestBase { $field_definitions = $entity_definition->getPropertyDefinitions(); // Comparison should ignore the internal static cache, so compare the // serialized objects instead. - $this->assertEqual(serialize($field_definitions), serialize(\Drupal::entityManager()->getFieldDefinitions('node'))); + $this->assertEqual(serialize($field_definitions), serialize(\Drupal::entityManager()->getBaseFieldDefinitions('node'))); $this->assertEqual($entity_definition->getPropertyDefinition('title')->getItemDefinition()->getDataType(), 'field_item:text'); $this->assertNull($entity_definition->getMainPropertyName()); $this->assertNull($entity_definition->getPropertyDefinition('invalid')); diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 9bcc69f4666..70c82598e7e 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Session\AccountInterface; @@ -73,12 +74,12 @@ function entity_test_entity_type_alter(array &$entity_types) { } /** - * Implements hook_entity_field_info_alter(). + * Implements hook_entity_base_field_info_alter(). */ -function entity_test_entity_field_info_alter(&$info, $entity_type) { - if ($entity_type == 'entity_test_mulrev' && ($names = \Drupal::state()->get('entity_test.field_definitions.translatable'))) { +function entity_test_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { + if ($entity_type->id() == 'entity_test_mulrev' && ($names = \Drupal::state()->get('entity_test.field_definitions.translatable'))) { foreach ($names as $name => $value) { - $info['definitions'][$name]->setTranslatable($value); + $fields[$name]->setTranslatable($value); } } } diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php index 72acdf26695..d55bb8d7258 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php @@ -8,6 +8,7 @@ namespace Drupal\entity_test\Entity; use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Language\Language; @@ -108,7 +109,7 @@ class EntityTest extends ContentEntityBase implements EntityOwnerInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['id'] = FieldDefinition::create('integer') ->setLabel(t('ID')) ->setDescription(t('The ID of the test entity.')) diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php index 94dceceac6d..c76cff70198 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php @@ -7,6 +7,7 @@ namespace Drupal\entity_test\Entity; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; /** @@ -41,7 +42,7 @@ class EntityTestBaseFieldDisplay extends EntityTest { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); $fields['test_no_display'] = FieldDefinition::create('text') diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php index 2292ca50b9c..49f7d5fe829 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php @@ -7,6 +7,7 @@ namespace Drupal\entity_test\Entity; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\entity_test\Entity\EntityTest; @@ -46,7 +47,7 @@ class EntityTestMul extends EntityTest { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); $fields['default_langcode'] = FieldDefinition::create('boolean') diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php index e82dde35486..870af93d6fe 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php @@ -7,6 +7,7 @@ namespace Drupal\entity_test\Entity; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\entity_test\Entity\EntityTestRev; @@ -46,7 +47,7 @@ class EntityTestMulRev extends EntityTestRev { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); $fields['revision_id'] = FieldDefinition::create('integer') diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php index 5ab256194a1..61753d9c849 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php @@ -7,6 +7,7 @@ namespace Drupal\entity_test\Entity; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\entity_test\Entity\EntityTest; @@ -30,7 +31,8 @@ use Drupal\entity_test\Entity\EntityTest; * "id" = "id", * "uuid" = "uuid", * "revision" = "revision_id", - * "bundle" = "type" + * "bundle" = "type", + * "label" = "name", * }, * links = { * "canonical" = "entity_test.edit_entity_test_rev", @@ -65,7 +67,7 @@ class EntityTestRev extends EntityTest { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); $fields['revision_id'] = FieldDefinition::create('integer') diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php index e366b8576c0..5a7e6fd0b88 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php @@ -9,6 +9,7 @@ namespace Drupal\taxonomy\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Language\Language; use Drupal\Core\TypedData\DataDefinition; @@ -197,7 +198,7 @@ class Term extends ContentEntityBase implements TermInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['tid'] = FieldDefinition::create('integer') ->setLabel(t('Term ID')) ->setDescription(t('The term ID.')) diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php index 44bce77c0f2..b38ea07c0e5 100644 --- a/core/modules/user/lib/Drupal/user/Entity/User.php +++ b/core/modules/user/lib/Drupal/user/Entity/User.php @@ -10,6 +10,7 @@ namespace Drupal\user\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Entity\EntityMalformedException; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\user\UserInterface; @@ -423,7 +424,7 @@ class User extends ContentEntityBase implements UserInterface { /** * {@inheritdoc} */ - public static function baseFieldDefinitions($entity_type) { + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['uid'] = FieldDefinition::create('integer') ->setLabel(t('User ID')) ->setDescription(t('The user ID.')) diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/argument_validator/Entity.php b/core/modules/views/lib/Drupal/views/Plugin/views/argument_validator/Entity.php index d5daf4b2d0b..1f2fd61533e 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/argument_validator/Entity.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/argument_validator/Entity.php @@ -102,7 +102,7 @@ class Entity extends ArgumentValidatorPluginBase { } $bundles_title = $entity_type->getBundleLabel() ?: $this->t('Bundles'); if ($entity_type->isSubclassOf('Drupal\Core\Entity\ContentEntityInterface')) { - $fields = $this->entityManager->getFieldDefinitions($entity_type_id); + $fields = $this->entityManager->getBaseFieldDefinitions($entity_type_id); } $bundle_name = (empty($fields) || empty($fields[$bundle_type]['label'])) ? t('bundles') : $fields[$bundle_type]['label']; $form['bundles'] = array( diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index eaae25a4978..2f8c2337fb9 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -451,6 +451,18 @@ class EntityManagerTest extends UnitTestCase { $this->assertNull($this->entityManager->getAdminRouteInfo('apple', 'delicious')); } + /** + * Tests the getBaseFieldDefinitions() method. + * + * @covers ::getBaseFieldDefinitions() + */ + public function testGetBaseFieldDefinitions() { + $field_definition = $this->setUpEntityWithFieldDefinition(); + + $expected = array('id' => $field_definition); + $this->assertSame($expected, $this->entityManager->getBaseFieldDefinitions('test_entity_type')); + } + /** * Tests the getFieldDefinitions() method. * @@ -460,84 +472,84 @@ class EntityManagerTest extends UnitTestCase { $field_definition = $this->setUpEntityWithFieldDefinition(); $expected = array('id' => $field_definition); - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type')); $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type', 'test_entity_bundle')); } + /** + * Tests the getBaseFieldDefinitions() method with caching. + * + * @covers ::getBaseFieldDefinitions() + */ + public function testGetBaseFieldDefinitionsWithCaching() { + $field_definition = $this->setUpEntityWithFieldDefinition(); + + $expected = array('id' => $field_definition); + + $this->cache->expects($this->at(0)) + ->method('get') + ->with('entity_base_field_definitions:test_entity_type:en', FALSE) + ->will($this->returnValue(FALSE)); + $this->cache->expects($this->once()) + ->method('set'); + $this->cache->expects($this->at(2)) + ->method('get') + ->with('entity_base_field_definitions:test_entity_type:en', FALSE) + ->will($this->returnValue((object) array('data' => $expected))); + + $this->assertSame($expected, $this->entityManager->getBaseFieldDefinitions('test_entity_type')); + $this->entityManager->testClearEntityFieldInfo(); + $this->assertSame($expected, $this->entityManager->getBaseFieldDefinitions('test_entity_type')); + } + + /** * Tests the getFieldDefinitions() method with caching. * * @covers ::getFieldDefinitions() */ public function testGetFieldDefinitionsWithCaching() { - $field_definition = $this->setUpEntityWithFieldDefinition(); + $field_definition = $this->setUpEntityWithFieldDefinition(FALSE, 'id', 0); $expected = array('id' => $field_definition); - // @todo Investigate why this is 0 and 2, not 0/1 or 1/2. $this->cache->expects($this->at(0)) ->method('get') - ->with('entity_field_definitions:test_entity_type:en', FALSE) + ->with('entity_base_field_definitions:test_entity_type:en', FALSE) + ->will($this->returnValue((object) array('data' => $expected))); + $this->cache->expects($this->at(1)) + ->method('get') + ->with('entity_bundle_field_definitions:test_entity_type:test_bundle:en', FALSE) ->will($this->returnValue(FALSE)); $this->cache->expects($this->at(2)) - ->method('get') - ->with('entity_field_definitions:test_entity_type:en', FALSE) - ->will($this->returnValue((object) array('data' => array('definitions' => $expected)))); - - $this->cache->expects($this->once()) ->method('set'); + $this->cache->expects($this->at(3)) + ->method('get') + ->with('entity_base_field_definitions:test_entity_type:en', FALSE) + ->will($this->returnValue((object) array('data' => $expected))); + $this->cache->expects($this->at(4)) + ->method('get') + ->with('entity_bundle_field_definitions:test_entity_type:test_bundle:en', FALSE) + ->will($this->returnValue((object) array('data' => $expected))); - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type')); + $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type', 'test_bundle')); $this->entityManager->testClearEntityFieldInfo(); - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type')); + $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type', 'test_bundle')); } /** - * Tests the getFieldDefinitions() method with bundle map. + * Tests the getBaseFieldDefinitions() method with an invalid definition. * - * @covers ::getFieldDefinitions() - */ - public function testGetFieldDefinitionsWithBundleMap() { - $field_definition = $this->setUpEntityWithFieldDefinition(TRUE); - - $this->moduleHandler->expects($this->at(0)) - ->method('invokeAll') - ->will($this->returnValue(array())); - $this->moduleHandler->expects($this->at(1)) - ->method('invokeAll') - ->will($this->returnValue(array( - 'bundle map' => array( - 'test_entity_bundle' => array( - 'custom_field', - ), - ), - 'optional' => array( - 'custom_field' => $field_definition, - ), - ))); - - $expected = array('id' => $field_definition); - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type')); - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type', 'test_entity_type')); - - $expected['custom_field'] = $field_definition; - $this->assertSame($expected, $this->entityManager->getFieldDefinitions('test_entity_type', 'test_entity_bundle')); - } - - /** - * Tests the getFieldDefinitions() method with an invalid definition. - * - * @covers ::getFieldDefinitions() + * @covers ::getBaseFieldDefinitions() * * @expectedException \LogicException */ - public function testGetFieldDefinitionsInvalidDefinition() { + public function testGetBaseFieldDefinitionsInvalidDefinition() { $langcode_definition = $this->setUpEntityWithFieldDefinition(FALSE, 'langcode'); $langcode_definition->expects($this->once()) ->method('isTranslatable') ->will($this->returnValue(TRUE)); - $this->entityManager->getFieldDefinitions('test_entity_type'); + $this->entityManager->getBaseFieldDefinitions('test_entity_type'); } /** @@ -552,30 +564,33 @@ class EntityManagerTest extends UnitTestCase { * @return \Drupal\Core\Field\FieldDefinition|\PHPUnit_Framework_MockObject_MockObject * A field definition object. */ - protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $field_definition_id = 'id') { + protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $field_definition_id = 'id', $base_field_definition_calls = 1) { $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); $entity = $this->getMock('Drupal\Tests\Core\Entity\TestContentEntityInterface'); $entity_class = get_class($entity); - $entity_type->expects($this->exactly(2)) + $entity_type->expects($this->any()) ->method('getClass') ->will($this->returnValue($entity_class)); - $entity_type->expects($this->once()) + $entity_type->expects($this->any()) ->method('getKeys') ->will($this->returnValue(array())); $field_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinition') ->disableOriginalConstructor() ->getMock(); - $entity_class::staticExpects($this->once()) + $entity_class::staticExpects($this->exactly($base_field_definition_calls)) ->method('baseFieldDefinitions') ->will($this->returnValue(array( $field_definition_id => $field_definition, ))); + $entity_class::staticExpects($this->any()) + ->method('bundleFieldDefinitions') + ->will($this->returnValue(array())); - $this->moduleHandler->expects($this->once()) + $this->moduleHandler->expects($this->any()) ->method('alter'); if (!$custom_invoke_all) { - $this->moduleHandler->expects($this->exactly(2)) + $this->moduleHandler->expects($this->any()) ->method('invokeAll') ->will($this->returnValue(array())); } @@ -804,7 +819,8 @@ class TestEntityManager extends EntityManager { * Allows the $entityFieldInfo property to be cleared. */ public function testClearEntityFieldInfo() { - $this->entityFieldInfo = NULL; + $this->baseFieldDefinitions = array(); + $this->fieldDefinitions = array(); } } diff --git a/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php b/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php index bb65e87b7f2..33b51daedc2 100644 --- a/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php @@ -77,7 +77,7 @@ class FieldableDatabaseStorageControllerTest extends UnitTestCase { ->with('test_entity') ->will($this->returnValue($definition)); $entity_manager->expects($this->any()) - ->method('getFieldDefinitions') + ->method('getBaseFieldDefinitions') ->with('test_entity') ->will($this->returnValue($fields));