diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php index faa6d0d..fd3535f 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Entity\Entity; +use Drupal\Component\Utility\SortArray; use Drupal\Core\Entity\EntityConstraintViolationListInterface; use Drupal\Core\Entity\EntityDisplayPluginCollection; use Drupal\Core\Entity\FieldableEntityInterface; @@ -160,8 +161,14 @@ public function buildForm(FieldableEntityInterface $entity, array &$form, FormSt // Set #parents to 'top-level' by default. $form += ['#parents' => []]; + // Sort the components by their weight in order to allow a form element from + // a widget to depend on the processed elements of another form element from + // a another widget. + $components = $this->getComponents(); + uasort($components, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']); + // Let each widget generate the form elements. - foreach ($this->getComponents() as $name => $options) { + foreach ($components as $name => $options) { if ($widget = $this->getRenderer($name)) { $items = $entity->get($name); $items->filterEmptyItems(); diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php index ac36411..a021b05 100644 --- a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php +++ b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php @@ -316,15 +316,11 @@ public function fieldAccess($operation, FieldDefinitionInterface $field_definiti $default = $items ? $items->defaultAccess($operation, $account) : AccessResult::allowed(); // Explicitly disallow changing the entity ID and entity UUID. - if ($operation === 'edit') { - if ($field_definition->getName() === $this->entityType->getKey('id')) { - return $return_as_object ? AccessResult::forbidden('The entity ID cannot be changed') : FALSE; - } - elseif ($field_definition->getName() === $this->entityType->getKey('uuid')) { - // UUIDs can be set when creating an entity. - if ($items && ($entity = $items->getEntity()) && !$entity->isNew()) { - return $return_as_object ? AccessResult::forbidden('The entity UUID cannot be changed')->addCacheableDependency($entity) : FALSE; - } + if ($operation === 'edit' && + ($field_definition->getName() === $this->entityType->getKey('id') || $field_definition->getName() === $this->entityType->getKey('uuid'))) { + // IDs and UUIDs can be set when creating an entity. + if ($items && ($entity = $items->getEntity()) && !$entity->isNew()) { + return $return_as_object ? AccessResult::forbidden('The entity ' . $field_definition->getLabel() . ' cannot be changed') : FALSE; } } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringMachineNameWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringMachineNameWidget.php new file mode 100644 index 0000000..44d10fa --- /dev/null +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringMachineNameWidget.php @@ -0,0 +1,105 @@ + '', + 'exists' => '', + 'label' => '', + 'replace_pattern' => '', + 'replace' => '', + ] + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $entity_type = $this->fieldDefinition->getTargetEntityTypeId(); + $bundle = $this->fieldDefinition->getTargetBundle(); + $fields = []; + /**@var \Drupal\Core\Field\FieldDefinitionInterface $field */ + foreach (\Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle) as $field_name => $field) { + $fields[$field_name] = $field->getLabel(); + } + $element['source'] = [ + '#type' => 'select', + '#title' => $this->t('Source field'), + '#default_value' => $this->getSetting('source'), + '#options' => $fields, + '#description' => $this->t('The field that should be used as a source for the machine name element.'), + ]; + + // @todo Add the rest of the settings. + + return $element; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = []; + + // @todo Add summaries for some of the settings, probably not all. + + return $summary; + } + + /** + * {@inheritdoc} + */ + public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { + $element['value'] = $element + [ + '#type' => 'machine_name', + '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL, + '#maxlength' => $this->getFieldSetting('max_length'), + '#machine_name' => [ + // @todo Generate the machine name configuration from the widget + // settings. Initially, the source field might look like this, but we + // need to generate it in an #after_build callback. See below. + //'source' => ['name', 'widget', 0, 'value'], + ], + ]; + + return $element; + } + + /** + * {@inheritdoc} + */ + public static function afterBuild(array $element, FormStateInterface $form_state) { + $element = parent::afterBuild($element, $form_state); + + $form = $form_state->getCompleteForm(); + + // @todo We need to override $element['value']['#machine_name']['source'] + // with the actual location of the source field in the form, taking into + // account that this could be a subform as part of a larger parent form + // (i.e. Inline Entity Form). + + return $element; + } + +} diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php index 342cbb9..abbf5c0 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php @@ -49,7 +49,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setReadOnly(TRUE) // In order to work around the InnoDB 191 character limit on utf8mb4 // primary keys, we set the character set for the field to ASCII. - ->setSetting('is_ascii', TRUE); + ->setSetting('is_ascii', TRUE) + ->setDisplayOptions('form', [ + 'type' => 'string_machine_name', + 'weight' => -1, + ]) + ->setDisplayConfigurable('form', TRUE); return $fields; }