diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index 41332e3..c8c69af 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -566,7 +566,7 @@ field.field_settings.entity_reference: type: string label: 'Reference method' handler_settings: - type: entity_reference.[%parent.handler].handler_settings + type: entity_reference.handler_settings.[plugin_id] label: 'Reference method settings' field.value.entity_reference: diff --git a/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/SelectionBase.php b/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/SelectionBase.php index 07ec8cd..614f4af 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/SelectionBase.php +++ b/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/SelectionBase.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection; +use Drupal\Component\Plugin\ConfigurablePluginInterface; +use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Database\Query\SelectInterface; @@ -39,7 +41,7 @@ * deriver = "Drupal\Core\Entity\Plugin\Derivative\SelectionBase" * ) */ -class SelectionBase extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface { +class SelectionBase extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface, ConfigurablePluginInterface { /** * The entity manager. @@ -80,7 +82,7 @@ class SelectionBase extends PluginBase implements SelectionInterface, ContainerF */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) { parent::__construct($configuration, $plugin_id, $plugin_definition); - + $this->setConfiguration($configuration); $this->entityManager = $entity_manager; $this->moduleHandler = $module_handler; $this->currentUser = $current_user; @@ -109,15 +111,6 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta $entity_type = $this->entityManager->getDefinition($entity_type_id); $bundles = $this->entityManager->getBundleInfo($entity_type_id); - // Merge-in default values. - $selection_handler_settings += array( - 'target_bundles' => array(), - 'sort' => array( - 'field' => '_none', - ), - 'auto_create' => FALSE, - ); - if ($entity_type->hasKey('bundle')) { $bundle_options = array(); foreach ($bundles as $bundle_name => $bundle_info) { @@ -388,4 +381,47 @@ protected function reAlterQuery(AlterableInterface $query, $tag, $base_table) { $query->alterMetaData = $old_metadata; } + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + $this->configuration = NestedArray::mergeDeep( + $this->defaultConfiguration(), + $configuration + ); + } + /** + * Returns default configuration for this plugin. + * + * @return array + * An associative array with the default configuration. + */ + public function defaultConfiguration() { + return [ + 'handler_settings' => [ + 'plugin_id' => $this->getPluginId(), + 'target_bundles' => [], + 'sort' => [ + 'field' => '_none', + ], + 'auto_create' => FALSE, + ] + ]; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return $this->configuration; + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + // @todo add dependency on target bundles. + return []; + } + } diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php index 1d2bf6d..78c41f2 100644 --- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php +++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php @@ -63,7 +63,7 @@ public static function create($type) { // settings for the field type. // @todo Cleanup in https://drupal.org/node/2116341. $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - $default_settings = $field_type_manager->getDefaultStorageSettings($type) + $field_type_manager->getDefaultFieldSettings($type); + $default_settings = $field_type_manager->getDefaultStorageSettings($type) + $field_type_manager->getDefaultFieldSettings($type, $field_definition); $field_definition->itemDefinition->setSettings($default_settings); return $field_definition; } diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php index b6b2a3c..7f4a18d 100644 --- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php +++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php @@ -158,7 +158,7 @@ public function preSave(EntityStorageInterface $storage) { // that a complete field definition is passed to the various hooks and // written to config. $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - $default_settings = $field_type_manager->getDefaultFieldSettings($this->getType()); + $default_settings = $field_type_manager->getDefaultFieldSettings($this->getType(), $this); $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings; // Call the parent's presave method to perform validate and calculate diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php index e355985..1e5283e 100644 --- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php +++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php @@ -61,11 +61,11 @@ public function getDefaultStorageSettings($type) { /** * {@inheritdoc} */ - public function getDefaultFieldSettings($type) { + public function getDefaultFieldSettings($type, FieldDefinitionInterface $field = NULL) { $plugin_definition = $this->getDefinition($type, FALSE); if (!empty($plugin_definition['class'])) { $plugin_class = DefaultFactory::getPluginClass($type, $plugin_definition); - return $plugin_class::defaultFieldSettings(); + return $plugin_class::defaultFieldSettings($field); } return array(); } diff --git a/core/modules/entity_reference/config/schema/entity_reference.schema.yml b/core/modules/entity_reference/config/schema/entity_reference.schema.yml index ec291fa..9648db9 100644 --- a/core/modules/entity_reference/config/schema/entity_reference.schema.yml +++ b/core/modules/entity_reference/config/schema/entity_reference.schema.yml @@ -1,9 +1,12 @@ # Schema for the configuration files of the Entity Reference module. -entity_reference.default.handler_settings: +entity_reference.handler_settings: type: mapping label: 'View handler settings' mapping: + plugin_id: + type: string + label: 'Entity reference selection plugin ID' target_bundles: type: sequence label: 'types' @@ -20,19 +23,9 @@ entity_reference.default.handler_settings: direction: type: string label: 'Sort direction' - filter: - type: mapping - label: 'Filter settings' - mapping: - type: - type: string - label: 'Filter by' - role: - type: sequence - label: 'Restrict to the selected roles' - sequence: - - type: string - label: 'Role' auto_create: type: boolean label: 'Create referenced entities if they don''t already exist' + +entity_reference.handler_settings.*: + type: entity_reference.handler_settings diff --git a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php index 5f0f75d..fd106cd 100644 --- a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php +++ b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php @@ -7,8 +7,10 @@ namespace Drupal\entity_reference; +use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; -use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\OptGroup; @@ -45,10 +47,25 @@ public static function defaultStorageSettings() { /** * {@inheritdoc} */ - public static function defaultFieldSettings() { - return array( - 'handler_settings' => array(), - ) + parent::defaultFieldSettings(); + public static function defaultFieldSettings(FieldDefinitionInterface $field = NULL) { + $defaults = ['handler_settings' => []]; + $defaults = NestedArray::mergeDeep($defaults, parent::defaultFieldSettings(), $field->getSettings()); + if ($field instanceof BaseFieldDefinition) { + $field->setSettings($defaults); + } + else { + $field->settings = $defaults; + } + // Get the default settings from the entity reference selection plugin if + // possible. + if ($field->getFieldStorageDefinition()->getSetting('target_type')) { + $handler = \Drupal::service('plugin.manager.entity_reference_selection')->getSelectionHandler($field); + $defaults = NestedArray::mergeDeep($defaults, $handler->defaultConfiguration()); + } + // The target type is handled by the 'target_type' property in the field + // storage settings. + unset($defaults['target_type']); + return $defaults; } /** @@ -194,7 +211,10 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) { $handler = \Drupal::service('plugin.manager.entity_reference_selection')->getSelectionHandler($field); $form['handler']['handler_settings'] += $handler->buildConfigurationForm(array(), $form_state); - + $form['handler']['handler_settings']['plugin_id'] = array( + '#type' => 'value', + '#value' => $handler->getPluginId(), + ); return $form; } diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php index 802bc1b..e6c5df1 100644 --- a/core/modules/field/src/Entity/FieldConfig.php +++ b/core/modules/field/src/Entity/FieldConfig.php @@ -7,6 +7,7 @@ namespace Drupal\field\Entity; +use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldConfigBase; @@ -141,8 +142,8 @@ public function preSave(EntityStorageInterface $storage) { // Filter out unknown settings and make sure all settings are present, so // that a complete field definition is passed to the various hooks and // written to config. - $default_settings = $field_type_manager->getDefaultFieldSettings($storage_definition->getType()); - $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings; + $default_settings = $field_type_manager->getDefaultFieldSettings($storage_definition->getType(), $this); + $this->settings = NestedArray::mergeDeep($default_settings, array_intersect_key($this->settings, $default_settings)); if ($this->isNew()) { // Notify the entity storage. diff --git a/core/modules/field/src/Tests/FieldCrudTest.php b/core/modules/field/src/Tests/FieldCrudTest.php index 33ace63..4dbf87a 100644 --- a/core/modules/field/src/Tests/FieldCrudTest.php +++ b/core/modules/field/src/Tests/FieldCrudTest.php @@ -87,7 +87,7 @@ function testCreateField() { $this->assertIdentical($config['description'], '', 'Description defaults to empty string.'); // Check that default settings are set. - $this->assertEqual($config['settings'], $field_type_manager->getDefaultFieldSettings($this->fieldStorageDefinition['type']) , 'Default field settings have been written.'); + $this->assertEqual($config['settings'], $field_type_manager->getDefaultFieldSettings($this->fieldStorageDefinition['type'], $field) , 'Default field settings have been written.'); // Check that the denormalized 'field_type' was properly written. $this->assertEqual($config['field_type'], $this->fieldStorageDefinition['type']); diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml index 772deea..279521c 100644 --- a/core/modules/user/config/schema/user.schema.yml +++ b/core/modules/user/config/schema/user.schema.yml @@ -174,3 +174,20 @@ condition.plugin.user_role: type: sequence sequence: - type: string + +entity_reference.handler_settings.default:user: + type: entity_reference.handler_settings + mapping: + filter: + type: mapping + label: 'Filter settings' + mapping: + type: + type: string + label: 'Filter by' + role: + type: sequence + label: 'Restrict to the selected roles' + sequence: + - type: string + label: 'Role' diff --git a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php index 8d2e701..e7dab16 100644 --- a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php +++ b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php @@ -189,4 +189,12 @@ public function entityQueryAlter(SelectInterface $query) { } } + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + // @todo add dependency on roles. + return parent::calculateDependencies(); + } + } diff --git a/core/modules/views/config/schema/views.entity_reference.schema.yml b/core/modules/views/config/schema/views.entity_reference.schema.yml index 3067041..51704a1 100644 --- a/core/modules/views/config/schema/views.entity_reference.schema.yml +++ b/core/modules/views/config/schema/views.entity_reference.schema.yml @@ -1,9 +1,12 @@ # Schema for the views entity reference selection plugins. -entity_reference.views.handler_settings: +entity_reference.handler_settings.views: type: mapping label: 'View handler settings' mapping: + plugin_id: + type: string + label: 'Entity reference selection plugin ID' view: type: mapping label: 'View used to select the entities' diff --git a/core/modules/views/src/Plugin/EntityReferenceSelection/ViewsSelection.php b/core/modules/views/src/Plugin/EntityReferenceSelection/ViewsSelection.php index 4c0d889..7c4036d 100644 --- a/core/modules/views/src/Plugin/EntityReferenceSelection/ViewsSelection.php +++ b/core/modules/views/src/Plugin/EntityReferenceSelection/ViewsSelection.php @@ -7,6 +7,8 @@ namespace Drupal\views\Plugin\EntityReferenceSelection; +use Drupal\Component\Plugin\ConfigurablePluginInterface; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Database\Query\SelectInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; @@ -27,7 +29,7 @@ * weight = 0 * ) */ -class ViewsSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface { +class ViewsSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface, ConfigurablePluginInterface { /** * The entity manager. @@ -57,7 +59,7 @@ class ViewsSelection extends PluginBase implements SelectionInterface, Container */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition); - + $this->setConfiguration($configuration); $this->entityManager = $entity_manager; } @@ -269,4 +271,41 @@ public function settingsFormValidate($element, FormStateInterface $form_state, $ $form_state->setValueForElement($element, $value); } + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + $this->configuration = NestedArray::mergeDeep( + $this->defaultConfiguration(), + $configuration + ); + } + /** + * Returns default configuration for this plugin. + * + * @return array + * An associative array with the default configuration. + */ + public function defaultConfiguration() { + return [ + 'handler_settings' => [ + 'plugin_id' => $this->getPluginId(), + ] + ]; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return $this->configuration; + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + return []; + } + }