diff --git a/core/lib/Drupal/Core/Field/FieldItemListComputedInterface.php b/core/lib/Drupal/Core/Field/FieldItemListComputedInterface.php index f6a6769..6adff61 100644 --- a/core/lib/Drupal/Core/Field/FieldItemListComputedInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemListComputedInterface.php @@ -1,7 +1,7 @@ getClass(); if (!empty($class)) { - $reflectionClass = new ReflectionClass($class); - return $reflectionClass->isSubclassOf('\Drupal\Core\Field\FieldItemListComputed'); + return is_subclass_of($class, '\Drupal\Core\Field\FieldItemListComputedInterface'); } return FALSE; - } } diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index ef52582..163269c 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -12,7 +12,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Field\FieldItemListComputed; +use Drupal\Core\Field\FieldItemListComputedInterface; use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\TypedData\Validation\MetadataFactory; use Drupal\Core\Validation\ConstraintManager; @@ -310,7 +310,7 @@ public function getPropertyInstance(TypedDataInterface $object, $property_name, $property->setContext($property_name, $object); if (isset($value)) { $property->setValue($value, FALSE); - } elseif ($property instanceof FieldItemListComputed) { + } elseif ($property instanceof FieldItemListComputedInterface) { // populate the computed list with values as there are no initial values to set. $property->computeItems(); } diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php index d7f2dd0..0248763 100644 --- a/core/modules/field/src/Entity/FieldConfig.php +++ b/core/modules/field/src/Entity/FieldConfig.php @@ -56,6 +56,13 @@ class FieldConfig extends FieldConfigBase implements FieldConfigInterface { protected $fieldStorage; /** + * Flag indicating whether the field is computed. + * + * @var bool + */ + protected $computed; + + /** * Constructs a FieldConfig object. * * In most cases, Field entities are created via @@ -303,14 +310,23 @@ public function getDisplayOptions($display_context) { * {@inheritdoc} */ public function isReadOnly() { - return FALSE; + return $this->isComputed(); } /** * {@inheritdoc} */ public function isComputed() { - return FALSE; + if (!isset($this->computed)) { + $item_type_definition = \Drupal::typedDataManager() + ->getDefinition('field_item:' . $this->getType()); + if ($item_type_definition && isset($item_type_definition['list_class'])) { + $this->computed = is_subclass_of($item_type_definition['list_class'], '\Drupal\Core\Field\FieldItemListComputedInterface'); + } else { + $this->computed = FALSE; + } + } + return $this->computed; } /** diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index 1c0d5bd..807441e 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -205,6 +205,13 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI protected static $inDeletion = FALSE; /** + * Flag indicating whether the field is computed. + * + * @var bool + */ + protected $computed; + + /** * Constructs a FieldStorageConfig object. * * @param array $values @@ -448,7 +455,7 @@ public function getSchema() { * {@inheritdoc} */ public function hasCustomStorage() { - return FALSE; + return $this->isComputed(); } /** @@ -670,7 +677,7 @@ public function getTargetEntityTypeId() { * {@inheritdoc} */ public function isQueryable() { - return TRUE; + return !$this->isComputed(); } /** @@ -680,6 +687,9 @@ public function isQueryable() { * TRUE if the field has data for any entity; FALSE otherwise. */ public function hasData() { + if ($this->isComputed()) { + return FALSE; + } return \Drupal::entityManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); } @@ -807,4 +817,17 @@ public function setIndexes(array $indexes) { return $this; } + + protected function isComputed() { + if (!isset($this->computed)) { + $item_type_definition = \Drupal::typedDataManager() + ->getDefinition('field_item:' . $this->getType()); + if ($item_type_definition && isset($item_type_definition['list_class'])) { + $this->computed = is_subclass_of($item_type_definition['list_class'], '\Drupal\Core\Field\FieldItemListComputedInterface'); + } else { + $this->computed = FALSE; + } + } + return $this->computed; + } } diff --git a/core/modules/field/tests/modules/field_computed_test/field_computed_test.module b/core/modules/field/tests/modules/field_computed_test/field_computed_test.module index 28bd677..9f77e96 100644 --- a/core/modules/field/tests/modules/field_computed_test/field_computed_test.module +++ b/core/modules/field/tests/modules/field_computed_test/field_computed_test.module @@ -7,22 +7,22 @@ function field_computed_test_entity_base_field_info(EntityTypeInterface $entity) if ($entity->id() === 'node') { $fields = array(); - $fields['field_dice_count'] = BaseFieldDefinition::create('integer') - ->setCustomStorage(false) + $fields['dice_count'] = BaseFieldDefinition::create('integer') + ->setSetting('unsigned', TRUE) ->setLabel(t('Dice count')) - ->setDisplayOptions('view', array( - 'label' => 'inline', - 'type' => 'text_textfield', - 'weight' => 0, - )) ->setDisplayOptions('form', array( - 'type' => 'integer', + 'type' => 'number', 'weight' => 10, )) - ->setDisplayConfigurable('form', TRUE); + ->setDisplayConfigurable('form', TRUE) + ->setDisplayOptions('view', array( + 'label' => 'inline', + 'type' => 'number_integer', + 'weight' => 0, + )); // set a custom list class an explicitly define the field to be computed - $fields['field_dice_result'] = BaseFieldDefinition::create('integer') + $fields['dice_result'] = BaseFieldDefinition::create('integer') ->setLabel(t('Dice result')) ->setClass('\Drupal\field_computed_test\Plugin\Field\FieldType\DiceItemList') ->setComputed(TRUE) @@ -33,7 +33,7 @@ function field_computed_test_entity_base_field_info(EntityTypeInterface $entity) )); // set a custom list class and rely on that class to mark the field as computed - $fields['field_dice_result_v2'] = BaseFieldDefinition::create('integer') + $fields['dice_result_v2'] = BaseFieldDefinition::create('integer') ->setLabel(t('Dice result V2')) ->setClass('\Drupal\field_computed_test\Plugin\Field\FieldType\DiceItemList') ->setDisplayOptions('view', array( @@ -43,15 +43,11 @@ function field_computed_test_entity_base_field_info(EntityTypeInterface $entity) )); // use a field type which uses a list class that marks the field as computed - $fields['field_dice_result_v3'] = BaseFieldDefinition::create('dice') + $fields['dice_result_v3'] = BaseFieldDefinition::create('dice') ->setLabel(t('Dice result V3')) ->setDisplayOptions('view', array( 'label' => 'inline', 'weight' => 0, - )) - ->setDisplayOptions('form', array( - 'type' => 'integer', - 'weight' => 10, )); return $fields; diff --git a/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldType/DiceItemList.php b/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldType/DiceItemList.php index a71f274..102f91e 100644 --- a/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldType/DiceItemList.php +++ b/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldType/DiceItemList.php @@ -12,7 +12,7 @@ class DiceItemList extends FieldItemListComputed { * {@inheritdoc} */ protected function computeItemValues() { - $items_count = $this->getEntity()->field_dice_count->value; + $items_count = $this->getEntity()->dice_count->value; $values = []; foreach (range(0, $items_count - 1) as $delta) { $values[$delta] = [ diff --git a/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldWidget/DiceWidget.php b/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldWidget/DiceWidget.php index 9e22a97..9d9b0f4 100644 --- a/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldWidget/DiceWidget.php +++ b/core/modules/field/tests/modules/field_computed_test/src/Plugin/Field/FieldWidget/DiceWidget.php @@ -23,7 +23,7 @@ class DiceWidget extends WidgetBase { public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $element = $element + [ - '#markup' => 'This is a computed field that contains a number of random values where the amount of items depends on value of the field_dice_count field on the same entity.', + '#markup' => 'Dummy widget.', ]; return $element; } diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index b26c225..badfc08 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -361,19 +361,21 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // Create the field storage and field. try { $this->entityManager->getStorage('field_storage_config')->create($field_storage_values)->save(); + /** @var \Drupal\field\FieldConfigInterface $field */ $field = $this->entityManager->getStorage('field_config')->create($field_values); $field->save(); $this->configureEntityFormDisplay($values['field_name'], $widget_id); $this->configureEntityViewDisplay($values['field_name'], $formatter_id); - // Always show the field settings step, as the cardinality needs to be // configured for new fields. $route_parameters = array( 'field_config' => $field->id(), ) + FieldUI::getRouteBundleParameter($entity_type, $this->bundle); - $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_storage_edit_form", 'route_parameters' => $route_parameters); - $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", 'route_parameters' => $route_parameters); + if (!$field->isComputed()) { + $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_storage_edit_form", 'route_parameters' => $route_parameters); + $destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", 'route_parameters' => $route_parameters); + } $destinations[] = array('route_name' => "entity.{$this->entityTypeId}.field_ui_fields", 'route_parameters' => $route_parameters); // Store new field information for any additional submit handlers.