diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php index 80b69b6..b1949de 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php @@ -148,6 +148,27 @@ public function instanceSettingsForm(array $form, array &$form_state) { } /** + * {@inheritdoc} + */ + public function defaultValuesForm(array &$form, array &$form_state) { + return array(); + } + + /** + * {@inheritdoc} + */ + public function defaultValuesFormValidate(array $element, array &$form, array &$form_state) { + return array(); + } + + /** + * {@inheritdoc} + */ + public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) { + return array(); + } + + /** * Returns the legacy callback for a given field type "hook". * * Copied from \Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem, diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php index 743ad5c..66df59d 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemBase.php @@ -8,6 +8,7 @@ namespace Drupal\field\Plugin\Type\FieldType; use Drupal\Core\Entity\Field\FieldItemBase; +use Drupal\Core\Language\Language; /** * Base class for 'configurable field type' plugin implementations. @@ -45,4 +46,101 @@ public function instanceSettingsForm(array $form, array &$form_state) { return array(); } + /** + * {@inheritdoc} + */ + public function defaultValuesForm(array &$form, array &$form_state) { + $entity = $this->getParent()->getParent(); + $default_value = $this->getFieldDefinition()->default_value; + $field_name = $this->getFieldDefinition()->getFieldName(); + $widget = $this->defaultValueWidget($form_state); + + $this->getFieldDefinition()->required = 0; + + // Insert the widget. Since we do not use the "official" instance definition, + // the whole flow cannot use field_invoke_method(). + $items = $entity->getNGEntity()->{$field_name}; + if (!empty($default_value)) { + $items->setValue($default_value); + } + + $element = array( + '#type' => 'details', + '#title' => t('Default value'), + '#tree' => TRUE, + '#description' => t('The default value for this field, used when creating new content.'), + // Stick to an empty 'parents' on this form in order not to breaks widgets + // that do not use field_widget_[field|instance]() and still access + // $form_state['field'] directly. + '#parents' => array(), + ); + + return $element += $widget->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + } + + /** + * {@inheritdoc} + */ + public function defaultValuesFormValidate(array $element, array &$form, array &$form_state) { + $entity = $this->getParent()->getParent(); + $widget = $this->defaultValueWidget($form_state); + $field_name = $this->getFieldDefinition()->getFieldName(); + + // Extract the 'default value'. + $items = $entity->getNGEntity()->{$field_name}; + $widget->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + $violations = $items->validate(); + + // Report errors. + if (count($violations)) { + $field_state = field_form_get_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state); + // Store reported errors in $form_state. + $field_state['constraint_violations'] = $violations; + field_form_set_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state, $field_state); + + // Assign reported errors to the correct form element. + $widget->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + } + } + /** + * {@inheritdoc} + */ + public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) { + $entity = $this->getParent()->getParent(); + $widget = $this->defaultValueWidget($form_state); + $field_name = $this->getFieldDefinition()->getFieldName(); + + // Extract field values. + $items = $entity->getNGEntity()->{$field_name}; + $widget->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + + return $items->getValue() ?: NULL; + } + + /** + * Returns the widget object used in default value form. + * + * @param array $form_state + * The form_state array. + * + * @return \Drupal\field\Plugin\Type\Widget\WidgetInterface + * A Widget object. + */ + protected function defaultValueWidget(array &$form_state) { + if (!isset($form_state['default_value_widget'])) { + $field_name = $this->getFieldDefinition()->getFieldName(); + $entity = $this->getParent()->getParent(); + $entity_form_display = entity_get_form_display($entity->entityType(), $entity->bundle(), 'default'); + + $widget = $entity_form_display->getRenderer($field_name); + // When field is hidden, use the default widget and store it in the form. + if (!$widget) { + $widget = \Drupal::service('plugin.manager.field.widget')->getInstance(array('field_definition' => $this->getFieldDefinition())); + } + $form_state['default_value_widget'] = $widget; + } + + return $form_state['default_value_widget']; + } + } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php index f37afa0..e6aceee 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigFieldItemInterface.php @@ -89,4 +89,56 @@ public function settingsForm(array $form, array &$form_state); */ public function instanceSettingsForm(array $form, array &$form_state); + /** + * Builds the default value widget for a given field instance. + * + * Invoked from \Drupal\field_ui\Form\FieldInstanceEditForm to allow + * administrators to configure instance-level default value. + * + * @param array $form + * The form where the settings form is being included in. + * @param array $form_state + * The form state of the (entire) configuration form. + * + * @return array + * The form definition for the field instance default value. + */ + public function defaultValuesForm(array &$form, array &$form_state); + + /** + * Validates the default value widget for a given field instance. + * + * Invoked from \Drupal\field_ui\Form\FieldInstanceEditForm to allow + * administrators to configure instance-level default value. + * + * @param array $element + * The default value form base element + * @param array $form + * The form where the settings form is being included in. + * @param array $form_state + * The form state of the (entire) configuration form. + * + * @return array + * The field instance default value. + */ + public function defaultValuesFormValidate(array $element, array &$form, array &$form_state); + + /** + * Submits the default value widget for a given field instance. + * + * Invoked from \Drupal\field_ui\Form\FieldInstanceEditForm to allow + * administrators to configure instance-level default value. + * + * @param array $element + * The default value form base element + * @param array $form + * The form where the settings form is being included in. + * @param array $form_state + * The form state of the (entire) configuration form. + * + * @return array + * The field instance default value. + */ + public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state); + } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php index 12bb296..0fe4be9 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php @@ -87,12 +87,18 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac * A Widget object. */ public function getInstance(array $options) { + // Fill in defaults for missing properties. + $options += array( + 'configuration' => array(), + 'prepare' => TRUE, + ); + $configuration = $options['configuration']; $field_definition = $options['field_definition']; $field_type = $field_definition->getFieldType(); // Fill in default configuration if needed. - if (!isset($options['prepare']) || $options['prepare'] == TRUE) { + if ($options['prepare']) { $configuration = $this->prepareConfiguration($field_type, $configuration); } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php index 046e012..4c69088 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php @@ -32,13 +32,6 @@ class FieldInstanceEditForm implements FormInterface, ControllerInterface { protected $instance; /** - * The field widget plugin manager. - * - * @var \Drupal\field\Plugin\Type\Widget\WidgetPluginManager - */ - protected $widgetManager; - - /** * The entity manager. * * @var \Drupal\Core\Entity\EntityManager @@ -46,26 +39,13 @@ class FieldInstanceEditForm implements FormInterface, ControllerInterface { protected $entityManager; /** - * The field type manager. - * - * @var \Drupal\Core\Entity\Field\FieldTypePluginManager - */ - protected $fieldTypeManager; - - /** * Constructs a new field instance form. * * @param \Drupal\Core\Entity\EntityManager $entity_manager * The entity manager. - * @param \Drupal\field\Plugin\Type\Widget\WidgetPluginManager $widget_manager - * The field widget plugin manager. - * @param \Drupal\Core\Entity\Field\FieldTypePluginManager $field_type_manager - * The field type manager. */ - public function __construct(EntityManager $entity_manager, WidgetPluginManager $widget_manager, FieldTypePluginManager $field_type_manager) { + public function __construct(EntityManager $entity_manager) { $this->entityManager = $entity_manager; - $this->widgetManager = $widget_manager; - $this->fieldTypeManager = $field_type_manager; } /** @@ -73,9 +53,7 @@ public function __construct(EntityManager $entity_manager, WidgetPluginManager $ */ public static function create(ContainerInterface $container) { return new static( - $container->get('plugin.manager.entity'), - $container->get('plugin.manager.field.widget'), - $container->get('plugin.manager.entity.field.field_type') + $container->get('plugin.manager.entity') ); } @@ -95,7 +73,6 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac $bundle = $this->instance['bundle']; $entity_type = $this->instance['entity_type']; $field = $this->instance->getField(); - $entity_form_display = entity_get_form_display($entity_type, $bundle, 'default'); $bundles = entity_get_bundles(); drupal_set_title(t('%instance settings for %bundle', array( @@ -104,11 +81,9 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac )), PASS_THROUGH); $form['#field'] = $field; - $form['#entity_form_display'] = $entity_form_display; // Create an arbitrary entity object (used by the 'default value' widget). $ids = (object) array('entity_type' => $this->instance['entity_type'], 'bundle' => $this->instance['bundle'], 'entity_id' => NULL); $form['#entity'] = _field_create_entity_from_ids($ids); - $form['#entity']->field_ui_default_value = TRUE; if (!empty($field['locked'])) { $form['locked'] = array( @@ -165,10 +140,8 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac $form['instance']['settings'] = $this->getFieldItem($form['#entity'], $this->instance['field_name'])->instanceSettingsForm($form, $form_state); $form['instance']['settings']['#weight'] = 10; - // Add handling for default value if not provided by any other module. - if (field_behaviors_widget('default_value', $this->instance) == FIELD_BEHAVIOR_DEFAULT && empty($this->instance['default_value_function'])) { - $form['instance']['default_value_widget'] = $this->getDefaultValueWidget($field, $form, $form_state); - } + // Add handling for default value. + $form['instance']['default_value_widget'] = $this->getFieldItem($form['#entity'], $this->instance['field_name'])->defaultValuesForm($form, $form_state); $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array( @@ -187,51 +160,15 @@ public function buildForm(array $form, array &$form_state, FieldInstanceInterfac * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { - // Take the incoming values as the $this->instance definition, so that the 'default - // value' gets validated using the instance settings being submitted. - $field_name = $this->instance['field_name']; - $entity = $form['#entity']; - $entity_form_display = $form['#entity_form_display']; - - if (isset($form['instance']['default_value_widget'])) { - $element = $form['instance']['default_value_widget']; - - // Extract the 'default value'. - $items = $entity->getNGEntity()->{$field_name}; - $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); - $violations = $items->validate(); - - // Report errors. - if (count($violations)) { - $field_state = field_form_get_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state); - // Store reported errors in $form_state. - $field_state['constraint_violations'] = $violations; - field_form_set_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state, $field_state); - - // Assign reported errors to the correct form element. - $entity_form_display->getRenderer($this->instance->getField()->id)->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); - } - } + $this->getFieldItem($form['#entity'], $this->instance['field_name'])->defaultValuesFormValidate($form['instance']['default_value_widget'], $form, $form_state); } /** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { - $field_name = $this->instance['field_name']; - $entity = $form['#entity']; - $entity_form_display = $form['#entity_form_display']; - // Handle the default value. - if (isset($form['instance']['default_value_widget'])) { - $element = $form['instance']['default_value_widget']; - - // Extract field values. - $items = $entity->getNGEntity()->{$field_name}; - $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); - - $this->instance['default_value'] = $items->getValue() ?: NULL; - } + $this->instance['default_value'] = $this->getFieldItem($form['#entity'], $this->instance['field_name'])->defaultValuesFormSubmit($form['instance']['default_value_widget'], $form, $form_state); // Merge incoming values into the instance. foreach ($form_state['values']['instance'] as $key => $value) { @@ -257,55 +194,6 @@ public function delete(array &$form, array &$form_state) { } /** - * Builds the default value widget for a given field instance. - */ - protected function getDefaultValueWidget($field, array &$form, &$form_state) { - $entity = $form['#entity']; - $entity_form_display = $form['#entity_form_display']; - - $element = array( - '#type' => 'details', - '#title' => t('Default value'), - '#tree' => TRUE, - '#description' => t('The default value for this field, used when creating new content.'), - // Stick to an empty 'parents' on this form in order not to breaks widgets - // that do not use field_widget_[field|instance]() and still access - // $form_state['field'] directly. - '#parents' => array(), - ); - - // Adjust the instance definition used for the form element. We want a - // non-required input and no description. - $this->instance['required'] = FALSE; - $this->instance['description'] = ''; - - // Adjust the instance definition to use the default widget of this field type - // instead of the hidden widget. - // @todo Clean this up since we don't have $this->instance['widget'] anymore. - // see https://drupal.org/node/2028759 - if ($this->instance['widget']['type'] == 'hidden') { - $field_type = $this->fieldTypeManager->getDefinition($field['type']); - $default_widget = $this->widgetManager->getDefinition($field_type['default_widget']); - - $this->instance['widget'] = array( - 'type' => $default_widget['id'], - 'settings' => $default_widget['settings'], - 'weight' => 0, - ); - } - - // Insert the widget. Since we do not use the "official" instance definition, - // the whole flow cannot use field_invoke_method(). - $items = $entity->getNGEntity()->{$this->instance->getField()->id}; - if (!empty($this->instance['default_value'])) { - $items->setValue((array) $this->instance['default_value']); - } - $element += $entity_form_display->getRenderer($this->instance->getField()->id)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); - - return $element; - } - - /** * Returns a FieldItem object for an entity. * * @todo Remove when all entity types extend EntityNG. diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php index 69be9ec..b651118 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php @@ -321,16 +321,6 @@ function testDefaultValue() { field_info_cache_clear(); $instance = field_info_instance('node', $field_name, $this->type); $this->assertEqual($instance['default_value'], NULL, 'The default value was correctly saved.'); - - // Change the widget to TestFieldWidgetNoDefault. - entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default') - ->setComponent($field_name, array( - 'type' => 'test_field_widget_no_default', - )) - ->save(); - - $this->drupalGet($admin_path); - $this->assertNoFieldById($element_id, '', 'No default value was possible for widget that disables default value.'); } /**