diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php index 09c818800081..7eb0d8ae6c97 100644 --- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php +++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Field\Entity\BaseFieldOverride; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\Core\TypedData\ListDataDefinition; +use Drupal\Core\TypedData\OptionsProviderInterface; /** * A class for defining entity fields. @@ -431,6 +432,19 @@ class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionI return $this; } + /** + * {@inheritdoc} + */ + public function getOptionsProvider($property_name, ContentEntityInterface $entity) { + // If the field item class implements the interface, proxy it through. + $item = $entity->get($this->getName())->first(); + if ($item instanceof OptionsProviderInterface) { + return $item; + } + // @todo: Allow setting custom options provider, see + // https://www.drupal.org/node/2002138. + } + /** * {@inheritdoc} */ diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php index 0b62fa0cf7c3..7df3c8359beb 100644 --- a/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Field; +use Drupal\Core\Entity\ContentEntityInterface; + /** * Defines an interface for entity field storage definitions. * @@ -130,6 +132,19 @@ interface FieldStorageDefinitionInterface { */ public function getDescription(); + /** + * Gets an options provider for the given field item property. + * + * @param string $property_name + * The name of the property to get options for; e.g., 'value'. + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity for which the options should be provided. + * + * @return \Drupal\Core\TypedData\OptionsProviderInterface|null + * An options provider, or NULL if no options are defined. + */ + public function getOptionsProvider($property_name, ContentEntityInterface $entity); + /** * Returns whether the field can contain multiple items. * diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index 7f9d5d93a210..c6e9bd1f61b3 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -10,9 +10,11 @@ namespace Drupal\field\Entity; use Drupal\Component\Utility\String; use Drupal\Component\Utility\Unicode; use Drupal\Core\Config\Entity\ConfigEntityBase; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldException; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\TypedData\OptionsProviderInterface; use Drupal\field\FieldStorageConfigInterface; /** @@ -580,6 +582,19 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI return FALSE; } + /** + * {@inheritdoc} + */ + public function getOptionsProvider($property_name, ContentEntityInterface $entity) { + // If the field item class implements the interface, proxy it through. + $item = $entity->get($this->getName())->first(); + if ($item instanceof OptionsProviderInterface) { + return $item; + } + // @todo: Allow setting custom options provider, see + // https://www.drupal.org/node/2002138. + } + /** * {@inheritdoc} */ diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php index d84854cf0dc1..906b8fd331ea 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php @@ -33,7 +33,7 @@ class ButtonsWidget extends OptionsWidgetBase { public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $element = parent::formElement($items, $delta, $element, $form, $form_state); - $options = $this->getOptions($items[$delta]); + $options = $this->getOptions($items->getEntity()); $selected = $this->getSelectedOptions($items); // If required and there is one single option, preselect it. diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php index ab9325003dac..6ed388e2f4c2 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php @@ -7,9 +7,9 @@ namespace Drupal\options\Plugin\Field\FieldWidget; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; -use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; @@ -114,16 +114,19 @@ abstract class OptionsWidgetBase extends WidgetBase { /** * Returns the array of options for the widget. * - * @param \Drupal\Core\Field\FieldItemInterface $item - * The field item. + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity for which to return options. * * @return array * The array of options for the widget. */ - protected function getOptions(FieldItemInterface $item) { + protected function getOptions(ContentEntityInterface $entity) { if (!isset($this->options)) { // Limit the settable options for the current user account. - $options = $item->getSettableOptions(\Drupal::currentUser()); + $options = $this->fieldDefinition + ->getFieldStorageDefinition() + ->getOptionsProvider($this->column, $entity) + ->getSettableOptions(\Drupal::currentUser()); // Add an empty option if the widget needs one. if ($empty_option = $this->getEmptyOption()) { @@ -143,7 +146,7 @@ abstract class OptionsWidgetBase extends WidgetBase { $module_handler = \Drupal::moduleHandler(); $context = array( 'fieldDefinition' => $this->fieldDefinition, - 'entity' => $item->getEntity(), + 'entity' => $entity, ); $module_handler->alter('options_list', $options, $context); @@ -173,7 +176,7 @@ abstract class OptionsWidgetBase extends WidgetBase { */ protected function getSelectedOptions(FieldItemListInterface $items, $delta = 0) { // We need to check against a flat list of options. - $flat_options = $this->flattenOptions($this->getOptions($items[$delta])); + $flat_options = $this->flattenOptions($this->getOptions($items->getEntity())); $selected_options = array(); foreach ($items as $item) { diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php index 2c27c3a7ba1a..09e9d37a63ca 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php @@ -35,7 +35,7 @@ class SelectWidget extends OptionsWidgetBase { $element += array( '#type' => 'select', - '#options' => $this->getOptions($items[$delta]), + '#options' => $this->getOptions($items->getEntity()), '#default_value' => $this->getSelectedOptions($items, $delta), // Do not display a 'multiple' select box if there is only one option. '#multiple' => $this->multiple && count($this->options) > 1,