From 2f1e909a4548643b31f0aef5e1d8cb80542a2be0 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Sat, 7 Jun 2014 12:05:03 -0500 Subject: [PATCH] Issue #2211723 by yched, Berdir: FieldInstance::__construct() loads all field_config entities. --- .../field/src/Entity/FieldInstanceConfig.php | 133 +++++++++++------- .../src/FieldInstanceConfigEntityUnitTest.php | 18 ++- 2 files changed, 87 insertions(+), 64 deletions(-) diff --git a/core/modules/field/src/Entity/FieldInstanceConfig.php b/core/modules/field/src/Entity/FieldInstanceConfig.php index ab7dd470b4c..0292ec94376 100644 --- a/core/modules/field/src/Entity/FieldInstanceConfig.php +++ b/core/modules/field/src/Entity/FieldInstanceConfig.php @@ -7,12 +7,14 @@ namespace Drupal\field\Entity; +use Drupal\Component\Utility\String; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\field\FieldException; +use Drupal\field\FieldConfigInterface; use Drupal\field\FieldInstanceConfigInterface; /** @@ -202,7 +204,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi /** * The data definition of a field item. * - * @var \Drupal\Core\TypedData\FieldItemDataDefinition + * @var \Drupal\Core\Field\TypedData\FieldItemDataDefinition */ protected $itemDefinition; @@ -218,7 +220,8 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * - field_name: The name of the field this is an instance of. This only * supports non-deleted fields. * - field_uuid: (optional) The uuid of the field this is an instance of. - * If present, this has priority over the 'field_name' value. + * If present and the instance is marked as 'deleted', this has priority + * over the 'field_name' value for retrieving the related field. * - entity_type: required. * - bundle: required. * @@ -231,47 +234,21 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * @ingroup field_crud */ public function __construct(array $values, $entity_type = 'field_instance_config') { - // Load the corresponding field. In case the instance was deleted, load the - // field based on the UUID, otherwise use the field name. - if (!empty($values['deleted'])) { - if ($fields = entity_load_multiple_by_properties('field_config', array('uuid' => $values['field_uuid'], 'include_deleted' => TRUE))) { - $field = current($fields); - } - else { - throw new FieldException(format_string('Attempt to create an instance of field @field_name that does not exist on entity type @entity_type.', array('@field_name' => $values['field_name'], '@entity_type' => $values['entity_type']))); - } + // Check required properties. + if (empty($values['field_name'])) { + throw new FieldException('Attempt to create an instance of a field without a field_name.'); } - elseif (isset($values['field_name']) && isset($values['entity_type'])) { - $field = FieldConfig::loadByName($values['entity_type'], $values['field_name']); - if (empty($field)) { - throw new FieldException(format_string('Attempt to create an instance of field @field_name that does not exist on entity type @entity_type.', array('@field_name' => $values['field_name'], '@entity_type' => $values['entity_type']))); - } - $values['field_uuid'] = $field->uuid(); + if (empty($values['entity_type'])) { + throw new FieldException(String::format('Attempt to create an instance of field @field_name without an entity_type.', array('@field_name' => $values['field_name']))); } - else { - throw new FieldException('Attempt to create an instance of an unspecified field.'); + if (empty($values['bundle'])) { + throw new FieldException(String::format('Attempt to create an instance of field @field_name without a bundle.', array('@field_name' => $values['field_name']))); } - // At this point, we have a Field we can assign. - $this->field = $field; - // Discard the 'field_type' entry that is added in config records to ease // schema generation. See self::toArray(). unset($values['field_type']); - // Check required properties. - if (empty($values['entity_type'])) { - throw new FieldException(format_string('Attempt to create an instance of field @field_name without an entity_type.', array('@field_name' => $this->field->name))); - } - if (empty($values['bundle'])) { - throw new FieldException(format_string('Attempt to create an instance of field @field_name without a bundle.', array('@field_name' => $this->field->name))); - } - - // 'Label' defaults to the field name (mostly useful for field instances - // created in tests). - $values += array( - 'label' => $this->field->name, - ); parent::__construct($values, $entity_type); } @@ -318,6 +295,24 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi return $properties; } + /** + * {@inheritdoc} + */ + public function postCreate(EntityStorageInterface $storage) { + // Validate that we have a valid field for this instance. This throws an + // exception if the field is invalid. + $field = $this->getField(); + + // Make sure the field_uuid is populated. + $this->field_uuid = $field->uuid(); + + // 'Label' defaults to the field name (mostly useful for field instances + // created in tests). + if (empty($this->label)) { + $this->label = $this->field->name; + } + } + /** * Overrides \Drupal\Core\Entity\Entity::preSave(). * @@ -330,9 +325,11 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi $entity_manager = \Drupal::entityManager(); $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + $field = $this->getField(); + if ($this->isNew()) { // Set the default instance settings. - $this->settings += $field_type_manager->getDefaultInstanceSettings($this->field->type); + $this->settings += $field_type_manager->getDefaultInstanceSettings($field->type); // Notify the entity storage. $entity_manager->getStorage($this->entity_type)->onInstanceCreate($this); } @@ -348,7 +345,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi throw new FieldException("Cannot change an existing instance's field."); } // Set the default instance settings. - $this->settings += $field_type_manager->getDefaultInstanceSettings($this->field->type); + $this->settings += $field_type_manager->getDefaultInstanceSettings($field->type); // Notify the entity storage. $entity_manager->getStorage($this->entity_type)->onInstanceUpdate($this); } @@ -364,7 +361,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi public function calculateDependencies() { parent::calculateDependencies(); // Manage dependencies. - $this->addDependency('entity', $this->field->getConfigDependencyName()); + $this->addDependency('entity', $this->getField()->getConfigDependencyName()); $bundle_entity_type_id = \Drupal::entityManager()->getDefinition($this->entity_type)->getBundleEntityType(); if ($bundle_entity_type_id != 'bundle') { // If the target entity type uses entities to manage its bundles then @@ -473,6 +470,34 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function getField() { + if (!$this->field) { + // Load the corresponding field. + // - If the instance is deleted (case of field purge), load the field + // based on the UUID. + // - Otherwise (regular case), fetch the field from the EntityManager + // registry. + if (!empty($this->deleted)) { + if ($fields = entity_load_multiple_by_properties('field_config', array('uuid' => $this->field_uuid, 'include_deleted' => TRUE))) { + $field = current($fields); + } + else { + throw new FieldException(String::format('Attempt to create an instance of field @field_name that does not exist on entity type @entity_type.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type))); + } + } + else { + $fields = \Drupal::entityManager()->getFieldStorageDefinitions($this->entity_type); + if (!isset($fields[$this->field_name])) { + throw new FieldException(String::format('Attempt to create an instance of field @field_name that does not exist on entity type @entity_type.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type))); + } + if (!$fields[$this->field_name] instanceof FieldConfigInterface) { + throw new FieldException(String::format('Attempt to create a configurable instance of non-configurable field @field_name.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type))); + } + $field = $fields[$this->field_name]; + } + + $this->field = $field; + } + return $this->field; } @@ -480,21 +505,21 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function getName() { - return $this->field->name; + return $this->field_name; } /** * {@inheritdoc} */ public function getType() { - return $this->field->type; + return $this->getField()->type; } /** * {@inheritdoc} */ public function getSettings() { - return $this->settings + $this->field->getSettings(); + return $this->settings + $this->getField()->getSettings(); } /** @@ -505,7 +530,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi return $this->settings[$setting_name]; } else { - return $this->field->getSetting($setting_name); + return $this->getField()->getSetting($setting_name); } } @@ -513,21 +538,21 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function getProvider() { - return $this->field->getProvider(); + return $this->getField()->getProvider(); } /** * {@inheritdoc} */ public function isTranslatable() { - return $this->field->translatable; + return $this->getField()->translatable; } /** * {@inheritdoc} */ public function isRevisionable() { - return $this->field->isRevisionable(); + return $this->getField()->isRevisionable(); } /** @@ -575,7 +600,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function getCardinality() { - return $this->field->cardinality; + return $this->getField()->cardinality; } /** @@ -589,7 +614,7 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function isMultiple() { - return $this->field->isMultiple(); + return $this->getField()->isMultiple(); } /** @@ -752,49 +777,49 @@ class FieldInstanceConfig extends ConfigEntityBase implements FieldInstanceConfi * {@inheritdoc} */ public function getPropertyDefinition($name) { - return $this->field->getPropertyDefinition($name); + return $this->getField()->getPropertyDefinition($name); } /** * {@inheritdoc} */ public function getPropertyDefinitions() { - return $this->field->getPropertyDefinitions(); + return $this->getField()->getPropertyDefinitions(); } /** * {@inheritdoc} */ public function getPropertyNames() { - return $this->field->getPropertyNames(); + return $this->getField()->getPropertyNames(); } /** * {@inheritdoc} */ public function getMainPropertyName() { - return $this->field->getMainPropertyName(); + return $this->getField()->getMainPropertyName(); } /** * {@inheritdoc} */ public function getSchema() { - return $this->field->getSchema(); + return $this->getField()->getSchema(); } /** * {@inheritdoc} */ public function getColumns() { - return $this->field->getColumns(); + return $this->getField()->getColumns(); } /** * {@inheritdoc} */ public function hasCustomStorage() { - return $this->field->hasCustomStorage(); + return $this->getField()->hasCustomStorage(); } /** diff --git a/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php b/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php index 7ab37dce806..2b18307ecba 100644 --- a/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php +++ b/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php @@ -87,12 +87,12 @@ class FieldInstanceConfigEntityUnitTest extends UnitTestCase { ->method('getConfigDependencyName') ->will($this->returnValue('field.field.test_entity_type.test_field')); - $field_storage = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface'); - $field_storage - ->expects($this->any()) - ->method('load') - ->with('test_entity_type.test_field') - ->will($this->returnValue($field)); + $this->entityManager->expects($this->any()) + ->method('getFieldStorageDefinitions') + ->with('test_entity_type') + ->will($this->returnValue(array( + $field->name => $field, + ))); // Mock the interfaces necessary to create a dependency on a bundle entity. $bundle_entity = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityInterface'); @@ -109,10 +109,8 @@ class FieldInstanceConfigEntityUnitTest extends UnitTestCase { $this->entityManager->expects($this->any()) ->method('getStorage') - ->will($this->returnValueMap(array( - array('field_config', $field_storage), - array('bundle_entity_type', $storage), - ))); + ->with('bundle_entity_type') + ->will($this->returnValue($storage)); $target_entity_type = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface'); $target_entity_type->expects($this->any())