summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2014-12-14 13:15:33 (GMT)
committerAlex Pott2014-12-14 13:15:33 (GMT)
commit4de09b6b8a2c6dffcdd1733f301a1659e5072233 (patch)
tree1abbe6a687257fa65f51e164f55b2cde804ff4f4
parentf41585c8d370124cf35549689a2d85f7ee3cf7f6 (diff)
Issue #2238085 by dawehner, yched, damiankloip, xjm, effulgentsia, vijaycs85, fago, tim.plunkett, cilefen, pcambra: [regression] options_allowed_values() signature doesn't allow for Views filter configuration
-rw-r--r--core/modules/options/options.api.php55
-rw-r--r--core/modules/options/options.module35
-rw-r--r--core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php40
-rw-r--r--core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php2
-rw-r--r--core/modules/options/src/Tests/OptionsDynamicValuesApiTest.php39
-rw-r--r--core/modules/options/src/Tests/OptionsDynamicValuesTestBase.php13
-rw-r--r--core/modules/options/tests/options_test/options_test.module34
7 files changed, 182 insertions, 36 deletions
diff --git a/core/modules/options/options.api.php b/core/modules/options/options.api.php
index 648d2dd..67d67a7 100644
--- a/core/modules/options/options.api.php
+++ b/core/modules/options/options.api.php
@@ -5,6 +5,9 @@
* Hooks provided by the Options module.
*/
+use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+
/**
* Alters the list of options to be displayed for a field.
*
@@ -32,3 +35,55 @@ function hook_options_list_alter(array &$options, array $context) {
$options['_none'] = t('== Empty ==');
}
}
+
+/**
+ * Provides the allowed values for an options field or widget.
+ *
+ * Callback for options_allowed_values().
+ *
+ * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
+ * The field storage definition.
+ * @param \Drupal\Core\Entity\FieldableEntityInterface|NULL $entity
+ * (optional) A specific entity to use for either restricting the values or
+ * customizing the labels for particular bundles and entities. NULL when
+ * there is not a specific entity available, such as for Views filters.
+ * @param bool $cacheable
+ * (optional) If $cacheable is FALSE, then the allowed values are not
+ * statically cached. See options_test_dynamic_values_callback() for an
+ * example of generating dynamic and uncached values. Defaults to TRUE.
+ *
+ * @return array
+ * The array of allowed values. Keys of the array are the raw stored values
+ * (number or text), values of the array are the display labels. If $entity
+ * is NULL, you should return the list of all the possible allowed values in
+ * any context so that other code (e.g. Views filters) can support the
+ * allowed values for all possible entities and bundles.
+ *
+ * @see options_allowed_values()
+ * @see options_test_allowed_values_callback()
+ * @see options_test_dynamic_values_callback()
+ */
+function callback_allowed_values_function(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, $cacheable = TRUE) {
+ if (isset($entity) && ($entity->bundle() == 'not_a_programmer')) {
+ $values = array(
+ 'Group 1' => array(
+ 1 => 'One',
+ ),
+ 'Group 2' => array(
+ 2 => 'Two',
+ ),
+ );
+ }
+ else {
+ $values = array(
+ 'Group 1' => array(
+ 0 => 'Zero',
+ ),
+ 'Group 2' => array(
+ 1 => 'One',
+ ),
+ );
+ }
+
+ return $values;
+}
diff --git a/core/modules/options/options.module b/core/modules/options/options.module
index ae6760d..54cf4b3 100644
--- a/core/modules/options/options.module
+++ b/core/modules/options/options.module
@@ -5,9 +5,9 @@
* Defines selection, check box and radio button widgets for text and numeric fields.
*/
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
-use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\FieldStorageConfigInterface;
@@ -54,30 +54,41 @@ function options_field_storage_config_delete(FieldStorageConfigInterface $field_
* sanitized through \Drupal\Core\Field\AllowedTagsXssTrait::fieldFilterXss()
* before being displayed.
*
- * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
- * The field definition.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
+ * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
+ * The field storage definition.
+ * @param \Drupal\Core\Entity\FieldableEntityInterface|NULL $entity
+ * (optional) The specific entity when this function is called from the
+ * context of a specific field on a specific entity. This allows custom
+ * 'allowed_values_function' callbacks to either restrict the values or
+ * customize the labels for particular bundles and entities. NULL when
+ * there is not a specific entity available, such as for Views filters.
*
- * @return
+ * @return array
* The array of allowed values. Keys of the array are the raw stored values
* (number or text), values of the array are the display labels.
+ *
+ * @see callback_allowed_values_function()
*/
-function options_allowed_values(FieldDefinitionInterface $field_definition, EntityInterface $entity) {
+function options_allowed_values(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) {
$allowed_values = &drupal_static(__FUNCTION__, array());
- $cache_id = implode(':', array($entity->getEntityTypeId(), $entity->bundle(), $field_definition->getName()));
+ $cache_keys = array($definition->getTargetEntityTypeId(), $definition->getName());
+ if ($entity) {
+ $cache_keys[] = 'entity';
+ }
+ $cache_id = implode(':', $cache_keys);
+
if (!isset($allowed_values[$cache_id])) {
- $function = $field_definition->getSetting('allowed_values_function');
+ $function = $definition->getSetting('allowed_values_function');
// If $cacheable is FALSE, then the allowed values are not statically
// cached. See options_test_dynamic_values_callback() for an example of
// generating dynamic and uncached values.
$cacheable = TRUE;
if (!empty($function)) {
- $values = $function($field_definition, $entity, $cacheable);
+ $values = $function($definition, $entity, $cacheable);
}
else {
- $values = $field_definition->getSetting('allowed_values');
+ $values = $definition->getSetting('allowed_values');
}
if ($cacheable) {
diff --git a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
index 61fb8b1..879e450 100644
--- a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
+++ b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php
@@ -34,21 +34,41 @@ class OptionsDefaultFormatter extends FormatterBase {
public function viewElements(FieldItemListInterface $items) {
$elements = array();
- $entity = $items->getEntity();
- $allowed_values = options_allowed_values($this->fieldDefinition, $entity);
+ // Only collect allowed options if there are actually items to display.
+ if ($items->count()) {
+ $provider = $items->getFieldDefinition()
+ ->getFieldStorageDefinition()
+ ->getOptionsProvider('value', $items->getEntity());
+ // Flatten the possible options, to support opt groups.
+ $options = $this->flattenOptions($provider->getPossibleOptions());
- foreach ($items as $delta => $item) {
- if (isset($allowed_values[$item->value])) {
- $output = $this->fieldFilterXss($allowed_values[$item->value]);
+ foreach ($items as $delta => $item) {
+ $value = $item->value;
+ // If the stored value is in the current set of allowed values, display
+ // the associated label, otherwise just display the raw value.
+ $output = isset($options[$value]) ? $options[$value] : $value;
+ $elements[$delta] = array('#markup' => $this->fieldFilterXss($output));
}
- else {
- // If no match was found in allowed values, fall back to the key.
- $output = $this->fieldFilterXss($item->value);
- }
- $elements[$delta] = array('#markup' => $output);
}
return $elements;
}
+ /**
+ * Flattens an array of allowed values.
+ *
+ * @param array $array
+ * A single or multidimensional array.
+ *
+ * @return array
+ * The flattened array.
+ *
+ * @todo Remove it once https://www.drupal.org/node/2392301 landed.
+ */
+ protected function flattenOptions(array $array) {
+ $result = array();
+ array_walk_recursive($array, function($a, $b) use (&$result) { $result[$b] = $a; });
+ return $result;
+ }
+
}
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index 19c4294..bdf063a 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -63,7 +63,7 @@ abstract class ListItemBase extends FieldItemBase implements OptionsProviderInte
* {@inheritdoc}
*/
public function getSettableOptions(AccountInterface $account = NULL) {
- $allowed_options = options_allowed_values($this->getFieldDefinition(), $this->getEntity());
+ $allowed_options = options_allowed_values($this->getFieldDefinition()->getFieldStorageDefinition(), $this->getEntity());
return $allowed_options;
}
diff --git a/core/modules/options/src/Tests/OptionsDynamicValuesApiTest.php b/core/modules/options/src/Tests/OptionsDynamicValuesApiTest.php
new file mode 100644
index 0000000..e1df82d
--- /dev/null
+++ b/core/modules/options/src/Tests/OptionsDynamicValuesApiTest.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\options\Tests\OptionsDynamicValuesApiTest.
+ */
+
+namespace Drupal\options\Tests;
+
+/**
+* Tests the options allowed values api.
+ *
+ * @group options
+*/
+class OptionsDynamicValuesApiTest extends OptionsDynamicValuesTestBase {
+
+ /**
+ * Tests options_allowed_values().
+ *
+ * @see options_test_dynamic_values_callback()
+ */
+ public function testOptionsAllowedValues() {
+ // Test allowed values without passed $items.
+ $values = options_allowed_values($this->fieldStorage);
+ $this->assertEqual([], $values);
+
+ $values = options_allowed_values($this->fieldStorage, $this->entity);
+
+ $expected_values = array(
+ $this->entity->label(),
+ $this->entity->url(),
+ $this->entity->uuid(),
+ $this->entity->bundle(),
+ );
+ $expected_values = array_combine($expected_values, $expected_values);
+ $this->assertEqual($expected_values, $values);
+ }
+
+}
diff --git a/core/modules/options/src/Tests/OptionsDynamicValuesTestBase.php b/core/modules/options/src/Tests/OptionsDynamicValuesTestBase.php
index 43d0bc9..20f49fd 100644
--- a/core/modules/options/src/Tests/OptionsDynamicValuesTestBase.php
+++ b/core/modules/options/src/Tests/OptionsDynamicValuesTestBase.php
@@ -28,11 +28,18 @@ abstract class OptionsDynamicValuesTestBase extends FieldTestBase {
*/
protected $entity;
+ /**
+ * The field storage.
+ *
+ * @var \Drupal\Core\Field\FieldStorageDefinitionInterface
+ */
+ protected $fieldStorage;
+
protected function setUp() {
parent::setUp();
$this->field_name = 'test_options';
- entity_create('field_storage_config', array(
+ $this->fieldStorage = entity_create('field_storage_config', array(
'field_name' => $this->field_name,
'entity_type' => 'entity_test_rev',
'type' => 'list_string',
@@ -40,7 +47,9 @@ abstract class OptionsDynamicValuesTestBase extends FieldTestBase {
'settings' => array(
'allowed_values_function' => 'options_test_dynamic_values_callback',
),
- ))->save();
+ ));
+ $this->fieldStorage->save();
+
$this->field = entity_create('field_config', array(
'field_name' => $this->field_name,
'entity_type' => 'entity_test_rev',
diff --git a/core/modules/options/tests/options_test/options_test.module b/core/modules/options/tests/options_test/options_test.module
index bfd4315..2d719d3 100644
--- a/core/modules/options/tests/options_test/options_test.module
+++ b/core/modules/options/tests/options_test/options_test.module
@@ -5,13 +5,15 @@
* Helper module for the List module tests.
*/
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
* Allowed values callback.
+ *
+ * @see options_allowed_values().
*/
-function options_test_allowed_values_callback(FieldDefinitionInterface $field_definition, EntityInterface $entity) {
+function options_test_allowed_values_callback(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) {
$values = array(
'Group 1' => array(
0 => 'Zero',
@@ -30,15 +32,25 @@ function options_test_allowed_values_callback(FieldDefinitionInterface $field_de
/**
* An entity-bound allowed values callback.
+ *
+ * @todo This function violates the recommendation in options_allowed_values()
+ * to return a list of all possible values in any context when $items is
+ * NULL. Since this is not yet used for testing Views integration, that is
+ * alright for now. Fix this in https://www.drupal.org/node/2012130.
+ *
+ * @see options_allowed_values().
*/
-function options_test_dynamic_values_callback(FieldDefinitionInterface $field_definition, EntityInterface $entity, &$cacheable) {
- $cacheable = FALSE;
- $values = array(
- $entity->label(),
- $entity->url(),
- $entity->uuid(),
- $entity->bundle(),
- );
+function options_test_dynamic_values_callback(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, &$cacheable = NULL) {
+ $values = array();
+ if (isset($entity)) {
+ $cacheable = FALSE;
+ $values = array(
+ $entity->label(),
+ $entity->url(),
+ $entity->uuid(),
+ $entity->bundle(),
+ );
+ }
// We need the values of the entity as keys.
return array_combine($values, $values);
}