Move into nested docroot
This commit is contained in:
parent
83a0d3a149
commit
c8b70abde9
13405 changed files with 0 additions and 0 deletions
157
web/core/modules/options/config/schema/options.schema.yml
Normal file
157
web/core/modules/options/config/schema/options.schema.yml
Normal file
|
@ -0,0 +1,157 @@
|
|||
# Schema for the configuration files of the Options module.
|
||||
|
||||
field.storage_settings.list_integer:
|
||||
type: mapping
|
||||
label: 'List (integer) settings'
|
||||
mapping:
|
||||
allowed_values:
|
||||
type: sequence
|
||||
label: 'Allowed values list'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Allowed value with label'
|
||||
mapping:
|
||||
value:
|
||||
type: integer
|
||||
label: 'Value'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
allowed_values_function:
|
||||
type: string
|
||||
label: 'Allowed values function'
|
||||
|
||||
field.field_settings.list_integer:
|
||||
label: 'List (integer) settings'
|
||||
type: mapping
|
||||
|
||||
field.value.list_integer:
|
||||
type: mapping
|
||||
label: 'Default value'
|
||||
mapping:
|
||||
value:
|
||||
type: integer
|
||||
label: 'Value'
|
||||
|
||||
field.storage_settings.list_float:
|
||||
type: mapping
|
||||
label: 'List (float) settings'
|
||||
mapping:
|
||||
allowed_values:
|
||||
type: sequence
|
||||
label: 'Allowed values list'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Allowed value with label'
|
||||
mapping:
|
||||
value:
|
||||
type: float
|
||||
label: 'Value'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
allowed_values_function:
|
||||
type: string
|
||||
label: 'Allowed values function'
|
||||
|
||||
field.field_settings.list_float:
|
||||
label: 'List (float) settings'
|
||||
type: mapping
|
||||
|
||||
field.value.list_float:
|
||||
type: mapping
|
||||
label: 'Default value'
|
||||
mapping:
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
|
||||
field.storage_settings.list_string:
|
||||
type: mapping
|
||||
label: 'List (text) settings'
|
||||
mapping:
|
||||
allowed_values:
|
||||
type: sequence
|
||||
label: 'Allowed values list'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Allowed value with label'
|
||||
mapping:
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
allowed_values_function:
|
||||
type: string
|
||||
label: 'Allowed values function'
|
||||
|
||||
field.field_settings.list_string:
|
||||
label: 'List (text) settings'
|
||||
type: mapping
|
||||
|
||||
field.value.list_string:
|
||||
type: mapping
|
||||
label: 'Default value'
|
||||
mapping:
|
||||
value:
|
||||
type: string
|
||||
label: 'Value'
|
||||
|
||||
field.formatter.settings.list_default:
|
||||
type: mapping
|
||||
label: 'Options list default display settings'
|
||||
|
||||
field.formatter.settings.list_key:
|
||||
type: mapping
|
||||
label: 'Key format settings'
|
||||
|
||||
field.widget.settings.options_buttons:
|
||||
type: mapping
|
||||
label: 'Check boxes/radio buttons format settings'
|
||||
|
||||
field.widget.settings.options_select:
|
||||
type: mapping
|
||||
label: 'Select list format settings'
|
||||
|
||||
views.argument.number_list_field:
|
||||
type: views.argument.numeric
|
||||
mapping:
|
||||
summary:
|
||||
type: mapping
|
||||
label: 'Display a summary'
|
||||
mapping:
|
||||
sort_order:
|
||||
type: string
|
||||
label: 'Sort order'
|
||||
number_of_records:
|
||||
type: integer
|
||||
label: 'Sort by'
|
||||
format:
|
||||
type: string
|
||||
label: 'Format'
|
||||
human:
|
||||
type: boolean
|
||||
|
||||
views.argument.string_list_field:
|
||||
type: views.argument.string
|
||||
mapping:
|
||||
summary:
|
||||
type: mapping
|
||||
label: 'Display a summary'
|
||||
mapping:
|
||||
sort_order:
|
||||
type: string
|
||||
label: 'Sort order'
|
||||
number_of_records:
|
||||
type: integer
|
||||
label: 'Sort by'
|
||||
format:
|
||||
type: string
|
||||
label: 'Format'
|
||||
human:
|
||||
type: boolean
|
||||
|
||||
views.filter.list_field:
|
||||
type: views.filter.many_to_one
|
102
web/core/modules/options/options.api.php
Normal file
102
web/core/modules/options/options.api.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* 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.
|
||||
*
|
||||
* This hook can notably be used to change the label of the empty option.
|
||||
*
|
||||
* @param array $options
|
||||
* The array of options for the field, as returned by
|
||||
* \Drupal\Core\TypedData\OptionsProviderInterface::getSettableOptions(). An
|
||||
* empty option (_none) might have been added, depending on the field
|
||||
* properties.
|
||||
* @param array $context
|
||||
* An associative array containing:
|
||||
* - fieldDefinition: The field definition
|
||||
* (\Drupal\Core\Field\FieldDefinitionInterface).
|
||||
* - entity: The entity object the field is attached to
|
||||
* (\Drupal\Core\Entity\EntityInterface).
|
||||
*
|
||||
* @ingroup hooks
|
||||
* @see hook_options_list()
|
||||
*/
|
||||
function hook_options_list_alter(array &$options, array $context) {
|
||||
// Check if this is the field we want to change.
|
||||
if ($context['fieldDefinition']->id() == 'field_option') {
|
||||
// Change the label of the empty option.
|
||||
$options['_none'] = t('== Empty ==');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the allowed values for a 'list_*' field.
|
||||
*
|
||||
* Callback for options_allowed_values().
|
||||
*
|
||||
* 'list_*' fields can specify a callback to define the set of their allowed
|
||||
* values using the 'allowed_values_function' storage setting.
|
||||
*
|
||||
* That function will be called:
|
||||
* - either in the context of a specific entity, which is then provided as the
|
||||
* $entity parameter,
|
||||
* - or for the field generally without the context of any specific entity or
|
||||
* entity bundle (typically, Views needing a list of values for an exposed
|
||||
* filter), in which case the $entity parameter is NULL.
|
||||
* This lets the callback restrict the set of allowed values or adjust the
|
||||
* labels depending on some conditions on the containing entity.
|
||||
*
|
||||
* For consistency, the set of values returned when an $entity is provided
|
||||
* should be a subset of the values returned when no $entity is provided.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
|
||||
* The field storage definition.
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface|null $entity
|
||||
* (optional) The entity context if known, or NULL if the allowed values are
|
||||
* being collected without the context of a specific entity.
|
||||
* @param bool &$cacheable
|
||||
* (optional) If an $entity is provided, the $cacheable parameter should be
|
||||
* modified by reference and set to FALSE if the set of allowed values
|
||||
* returned was specifically adjusted for that entity and cannot not be reused
|
||||
* for other entities. 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.
|
||||
*
|
||||
* @ingroup callbacks
|
||||
* @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(
|
||||
1 => 'One',
|
||||
2 => 'Two',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$values = array(
|
||||
'Group 1' => array(
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
),
|
||||
'Group 2' => array(
|
||||
2 => 'Two',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
9
web/core/modules/options/options.info.yml
Normal file
9
web/core/modules/options/options.info.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name: Options
|
||||
type: module
|
||||
description: 'Defines selection, check box and radio button widgets for text and numeric fields.'
|
||||
package: Field types
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- field
|
||||
- text
|
138
web/core/modules/options/options.module
Normal file
138
web/core/modules/options/options.module
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines selection, check box and radio button widgets for text and numeric fields.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function options_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.options':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Options module allows you to create fields where data values are selected from a fixed list of options. Usually these items are entered through a select list, checkboxes, or radio buttons. See the <a href=":field">Field module help</a> and the <a href=":field_ui">Field UI help</a> pages for general information on fields and how to create and manage them. For more information, see the <a href=":options_do">online documentation for the Options module</a>.', array(':field' => \Drupal::url('help.page', array('name' => 'field')), ':field_ui' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#', ':options_do' => 'https://www.drupal.org/documentation/modules/options')) . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Managing and displaying list fields') . '</dt>';
|
||||
$output .= '<dd>' . t('The <em>settings</em> and the <em>display</em> of the list fields can be configured separately. See the <a href=":field_ui">Field UI help</a> for more information on how to manage fields and their display.', array(':field_ui' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#')) . '</dd>';
|
||||
$output .= '<dt>' . t('Defining option keys and labels') . '</dt>';
|
||||
$output .= '<dd>' . t('When you define the list options you can define a key and a label for each option in the list. The label will be shown to the users while the key gets stored in the database.') . '</dd>';
|
||||
$output .= '<dt>' . t('Choosing list field type') . '</dt>';
|
||||
$output .= '<dd>' . t('There are three types of list fields, which store different types of data: <em>float</em>, <em>integer</em> or, <em>text</em>. The <em>float</em> type allows storing approximate decimal values. The <em>integer</em> type allows storing whole numbers, such as years (for example, 2012) or values (for example, 1, 2, 5, 305). The <em>text</em> list field type allows storing text values. No matter which type of list field you choose, you can define whatever labels you wish for data entry.') . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_update() for 'field_storage_config'.
|
||||
*/
|
||||
function options_field_storage_config_update(FieldStorageConfigInterface $field_storage) {
|
||||
drupal_static_reset('options_allowed_values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_delete() for 'field_storage_config'.
|
||||
*/
|
||||
function options_field_storage_config_delete(FieldStorageConfigInterface $field_storage) {
|
||||
drupal_static_reset('options_allowed_values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of allowed values for a list field.
|
||||
*
|
||||
* The strings are not safe for output. Keys and values of the array should be
|
||||
* sanitized through \Drupal\Core\Field\AllowedTagsXssTrait::fieldFilterXss()
|
||||
* before being displayed.
|
||||
*
|
||||
* @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 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(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) {
|
||||
$allowed_values = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
$cache_keys = array($definition->getTargetEntityTypeId(), $definition->getName());
|
||||
if ($entity) {
|
||||
$cache_keys[] = 'entity';
|
||||
}
|
||||
$cache_id = implode(':', $cache_keys);
|
||||
|
||||
if (!isset($allowed_values[$cache_id])) {
|
||||
$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($definition, $entity, $cacheable);
|
||||
}
|
||||
else {
|
||||
$values = $definition->getSetting('allowed_values');
|
||||
}
|
||||
|
||||
if ($cacheable) {
|
||||
$allowed_values[$cache_id] = $values;
|
||||
}
|
||||
else {
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
return $allowed_values[$cache_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_storage_config_update_forbid().
|
||||
*/
|
||||
function options_field_storage_config_update_forbid(FieldStorageConfigInterface $field_storage, FieldStorageConfigInterface $prior_field_storage) {
|
||||
if ($field_storage->getTypeProvider() == 'options' && $field_storage->hasData()) {
|
||||
// Forbid any update that removes allowed values with actual data.
|
||||
$allowed_values = $field_storage->getSetting('allowed_values');
|
||||
$prior_allowed_values = $prior_field_storage->getSetting('allowed_values');
|
||||
$lost_keys = array_keys(array_diff_key($prior_allowed_values, $allowed_values));
|
||||
if (_options_values_in_use($field_storage->getTargetEntityTypeId(), $field_storage->getName(), $lost_keys)) {
|
||||
throw new FieldStorageDefinitionUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field_storage->getName())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a list of values are being used in actual field values.
|
||||
*/
|
||||
function _options_values_in_use($entity_type, $field_name, $values) {
|
||||
if ($values) {
|
||||
$factory = \Drupal::service('entity.query');
|
||||
$result = $factory->get($entity_type)
|
||||
->condition($field_name . '.value', $values, 'IN')
|
||||
->count()
|
||||
->accessCheck(FALSE)
|
||||
->range(0, 1)
|
||||
->execute();
|
||||
if ($result) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
39
web/core/modules/options/options.views.inc
Normal file
39
web/core/modules/options/options.views.inc
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provide Views data for options.module.
|
||||
*
|
||||
* @ingroup views_module_handlers
|
||||
*/
|
||||
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_field_views_data().
|
||||
*
|
||||
* Views integration for list fields. Have a different filter handler and
|
||||
* argument handlers for list fields. This should allow to select values of
|
||||
* the list.
|
||||
*/
|
||||
function options_field_views_data(FieldStorageConfigInterface $field) {
|
||||
$data = views_field_default_views_data($field);
|
||||
|
||||
foreach ($data as $table_name => $table_data) {
|
||||
foreach ($table_data as $field_name => $field_data) {
|
||||
if (isset($field_data['filter']) && $field_name != 'delta') {
|
||||
$data[$table_name][$field_name]['filter']['id'] = 'list_field';
|
||||
}
|
||||
if (isset($field_data['argument']) && $field_name != 'delta') {
|
||||
if ($field->getType() == 'list_string') {
|
||||
$data[$table_name][$field_name]['argument']['id'] = 'string_list_field';
|
||||
}
|
||||
else {
|
||||
$data[$table_name][$field_name]['argument']['id'] = 'number_list_field';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Core\Field\FormatterBase;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'list_default' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "list_default",
|
||||
* label = @Translation("Default"),
|
||||
* field_types = {
|
||||
* "list_integer",
|
||||
* "list_float",
|
||||
* "list_string",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class OptionsDefaultFormatter extends FormatterBase {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$elements = array();
|
||||
|
||||
// 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 = OptGroup::flattenOptions($provider->getPossibleOptions());
|
||||
|
||||
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' => $output,
|
||||
'#allowed_tags' => FieldFilteredMarkup::allowedTags(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Core\Field\FormatterBase;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'list_key' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "list_key",
|
||||
* label = @Translation("Key"),
|
||||
* field_types = {
|
||||
* "list_integer",
|
||||
* "list_float",
|
||||
* "list_string",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class OptionsKeyFormatter extends FormatterBase {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$elements = array();
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
$elements[$delta] = array(
|
||||
'#markup' => $item->value,
|
||||
'#allowed_tags' => FieldFilteredMarkup::allowedTags(),
|
||||
);
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'list_float' field type.
|
||||
*
|
||||
* @FieldType(
|
||||
* id = "list_float",
|
||||
* label = @Translation("List (float)"),
|
||||
* description = @Translation("This field stores float values from a list of allowed 'value => label' pairs, i.e. 'Fraction': 0 => 0, .25 => 1/4, .75 => 3/4, 1 => 1."),
|
||||
* category = @Translation("Number"),
|
||||
* default_widget = "options_select",
|
||||
* default_formatter = "list_default",
|
||||
* )
|
||||
*/
|
||||
class ListFloatItem extends ListItemBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['value'] = DataDefinition::create('float')
|
||||
->setLabel(t('Float value'))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return array(
|
||||
'columns' => array(
|
||||
'value' => array(
|
||||
'type' => 'float',
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'value' => array('value'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function allowedValuesDescription() {
|
||||
$description = '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label.');
|
||||
$description .= '<br/>' . t('The key is the stored value, and must be numeric. The label will be used in displayed values and edit forms.');
|
||||
$description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
|
||||
$description .= '<br/>' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.');
|
||||
$description .= '</p>';
|
||||
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function extractAllowedValues($string, $has_data) {
|
||||
$values = parent::extractAllowedValues($string, $has_data);
|
||||
if ($values) {
|
||||
$keys = array_keys($values);
|
||||
$labels = array_values($values);
|
||||
$keys = array_map(function ($key) {
|
||||
// Float keys are represented as strings and need to be disambiguated
|
||||
// ('.5' is '0.5').
|
||||
return is_numeric($key) ? (string) (float) $key : $key;
|
||||
}, $keys);
|
||||
|
||||
return array_combine($keys, $labels);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function validateAllowedValue($option) {
|
||||
if (!is_numeric($option)) {
|
||||
return t('Allowed values list: each key must be a valid integer or decimal.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function simplifyAllowedValues(array $structured_values) {
|
||||
$values = array();
|
||||
foreach ($structured_values as $item) {
|
||||
// Nested elements are embedded in the label.
|
||||
if (is_array($item['label'])) {
|
||||
$item['label'] = static::simplifyAllowedValues($item['label']);
|
||||
}
|
||||
// Cast the value to a float first so that .5 and 0.5 are the same value
|
||||
// and then cast to a string so that values like 0.5 can be used as array
|
||||
// keys.
|
||||
// @see http://php.net/manual/language.types.array.php
|
||||
$values[(string) (float) $item['value']] = $item['label'];
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function castAllowedValue($value) {
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'list_integer' field type.
|
||||
*
|
||||
* @FieldType(
|
||||
* id = "list_integer",
|
||||
* label = @Translation("List (integer)"),
|
||||
* description = @Translation("This field stores integer values from a list of allowed 'value => label' pairs, i.e. 'Lifetime in days': 1 => 1 day, 7 => 1 week, 31 => 1 month."),
|
||||
* category = @Translation("Number"),
|
||||
* default_widget = "options_select",
|
||||
* default_formatter = "list_default",
|
||||
* )
|
||||
*/
|
||||
class ListIntegerItem extends ListItemBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['value'] = DataDefinition::create('integer')
|
||||
->setLabel(t('Integer value'))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return array(
|
||||
'columns' => array(
|
||||
'value' => array(
|
||||
'type' => 'int',
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'value' => array('value'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function allowedValuesDescription() {
|
||||
$description = '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label.');
|
||||
$description .= '<br/>' . t('The key is the stored value, and must be numeric. The label will be used in displayed values and edit forms.');
|
||||
$description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
|
||||
$description .= '<br/>' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.');
|
||||
$description .= '</p>';
|
||||
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function validateAllowedValue($option) {
|
||||
if (!preg_match('/^-?\d+$/', $option)) {
|
||||
return t('Allowed values list: keys must be integers.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function castAllowedValue($value) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TypedData\OptionsProviderInterface;
|
||||
|
||||
/**
|
||||
* Plugin base class inherited by the options field types.
|
||||
*/
|
||||
abstract class ListItemBase extends FieldItemBase implements OptionsProviderInterface {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultStorageSettings() {
|
||||
return array(
|
||||
'allowed_values' => array(),
|
||||
'allowed_values_function' => '',
|
||||
) + parent::defaultStorageSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPossibleValues(AccountInterface $account = NULL) {
|
||||
// Flatten options firstly, because Possible Options may contain group
|
||||
// arrays.
|
||||
$flatten_options = OptGroup::flattenOptions($this->getPossibleOptions($account));
|
||||
return array_keys($flatten_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPossibleOptions(AccountInterface $account = NULL) {
|
||||
return $this->getSettableOptions($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSettableValues(AccountInterface $account = NULL) {
|
||||
// Flatten options firstly, because Settable Options may contain group
|
||||
// arrays.
|
||||
$flatten_options = OptGroup::flattenOptions($this->getSettableOptions($account));
|
||||
return array_keys($flatten_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSettableOptions(AccountInterface $account = NULL) {
|
||||
$allowed_options = options_allowed_values($this->getFieldDefinition()->getFieldStorageDefinition(), $this->getEntity());
|
||||
return $allowed_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
|
||||
$allowed_options = options_allowed_values($field_definition->getFieldStorageDefinition());
|
||||
$values['value'] = array_rand($allowed_options);
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isEmpty() {
|
||||
return empty($this->value) && (string) $this->value !== '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
|
||||
$allowed_values = $this->getSetting('allowed_values');
|
||||
$allowed_values_function = $this->getSetting('allowed_values_function');
|
||||
|
||||
$element['allowed_values'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Allowed values list'),
|
||||
'#default_value' => $this->allowedValuesString($allowed_values),
|
||||
'#rows' => 10,
|
||||
'#access' => empty($allowed_values_function),
|
||||
'#element_validate' => array(array(get_class($this), 'validateAllowedValues')),
|
||||
'#field_has_data' => $has_data,
|
||||
'#field_name' => $this->getFieldDefinition()->getName(),
|
||||
'#entity_type' => $this->getEntity()->getEntityTypeId(),
|
||||
'#allowed_values' => $allowed_values,
|
||||
);
|
||||
|
||||
$element['allowed_values']['#description'] = $this->allowedValuesDescription();
|
||||
|
||||
$element['allowed_values_function'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Allowed values list'),
|
||||
'#markup' => t('The value of this field is being determined by the %function function and may not be changed.', array('%function' => $allowed_values_function)),
|
||||
'#access' => !empty($allowed_values_function),
|
||||
'#value' => $allowed_values_function,
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the field type specific allowed values form element #description.
|
||||
*
|
||||
* @return string
|
||||
* The field type allowed values form specific description.
|
||||
*/
|
||||
abstract protected function allowedValuesDescription();
|
||||
|
||||
/**
|
||||
* #element_validate callback for options field allowed values.
|
||||
*
|
||||
* @param $element
|
||||
* An associative array containing the properties and children of the
|
||||
* generic form element.
|
||||
* @param $form_state
|
||||
* The current state of the form for the form this element belongs to.
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\FormElement::processPattern()
|
||||
*/
|
||||
public static function validateAllowedValues($element, FormStateInterface $form_state) {
|
||||
$values = static::extractAllowedValues($element['#value'], $element['#field_has_data']);
|
||||
|
||||
if (!is_array($values)) {
|
||||
$form_state->setError($element, t('Allowed values list: invalid input.'));
|
||||
}
|
||||
else {
|
||||
// Check that keys are valid for the field type.
|
||||
foreach ($values as $key => $value) {
|
||||
if ($error = static::validateAllowedValue($key)) {
|
||||
$form_state->setError($element, $error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent removing values currently in use.
|
||||
if ($element['#field_has_data']) {
|
||||
$lost_keys = array_keys(array_diff_key($element['#allowed_values'], $values));
|
||||
if (_options_values_in_use($element['#entity_type'], $element['#field_name'], $lost_keys)) {
|
||||
$form_state->setError($element, t('Allowed values list: some values are being removed while currently in use.'));
|
||||
}
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element, $values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the allowed values array from the allowed_values element.
|
||||
*
|
||||
* @param string $string
|
||||
* The raw string to extract values from.
|
||||
* @param bool $has_data
|
||||
* The current field already has data inserted or not.
|
||||
*
|
||||
* @return array|null
|
||||
* The array of extracted key/value pairs, or NULL if the string is invalid.
|
||||
*
|
||||
* @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::allowedValuesString()
|
||||
*/
|
||||
protected static function extractAllowedValues($string, $has_data) {
|
||||
$values = array();
|
||||
|
||||
$list = explode("\n", $string);
|
||||
$list = array_map('trim', $list);
|
||||
$list = array_filter($list, 'strlen');
|
||||
|
||||
$generated_keys = $explicit_keys = FALSE;
|
||||
foreach ($list as $position => $text) {
|
||||
// Check for an explicit key.
|
||||
$matches = array();
|
||||
if (preg_match('/(.*)\|(.*)/', $text, $matches)) {
|
||||
// Trim key and value to avoid unwanted spaces issues.
|
||||
$key = trim($matches[1]);
|
||||
$value = trim($matches[2]);
|
||||
$explicit_keys = TRUE;
|
||||
}
|
||||
// Otherwise see if we can use the value as the key.
|
||||
elseif (!static::validateAllowedValue($text)) {
|
||||
$key = $value = $text;
|
||||
$explicit_keys = TRUE;
|
||||
}
|
||||
// Otherwise see if we can generate a key from the position.
|
||||
elseif (!$has_data) {
|
||||
$key = (string) $position;
|
||||
$value = $text;
|
||||
$generated_keys = TRUE;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
$values[$key] = $value;
|
||||
}
|
||||
|
||||
// We generate keys only if the list contains no explicit key at all.
|
||||
if ($explicit_keys && $generated_keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a candidate allowed value is valid.
|
||||
*
|
||||
* @param string $option
|
||||
* The option value entered by the user.
|
||||
*
|
||||
* @return string
|
||||
* The error message if the specified value is invalid, NULL otherwise.
|
||||
*/
|
||||
protected static function validateAllowedValue($option) { }
|
||||
|
||||
/**
|
||||
* Generates a string representation of an array of 'allowed values'.
|
||||
*
|
||||
* This string format is suitable for edition in a textarea.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of values, where array keys are values and array values are
|
||||
* labels.
|
||||
*
|
||||
* @return string
|
||||
* The string representation of the $values array:
|
||||
* - Values are separated by a carriage return.
|
||||
* - Each value is in the format "value|label" or "value".
|
||||
*/
|
||||
protected function allowedValuesString($values) {
|
||||
$lines = array();
|
||||
foreach ($values as $key => $value) {
|
||||
$lines[] = "$key|$value";
|
||||
}
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function storageSettingsToConfigData(array $settings) {
|
||||
if (isset($settings['allowed_values'])) {
|
||||
$settings['allowed_values'] = static::structureAllowedValues($settings['allowed_values']);
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function storageSettingsFromConfigData(array $settings) {
|
||||
if (isset($settings['allowed_values'])) {
|
||||
$settings['allowed_values'] = static::simplifyAllowedValues($settings['allowed_values']);
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies allowed values to a key-value array from the structured array.
|
||||
*
|
||||
* @param array $structured_values
|
||||
* Array of items with a 'value' and 'label' key each for the allowed
|
||||
* values.
|
||||
*
|
||||
* @return array
|
||||
* Allowed values were the array key is the 'value' value, the value is
|
||||
* the 'label' value.
|
||||
*
|
||||
* @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::structureAllowedValues()
|
||||
*/
|
||||
protected static function simplifyAllowedValues(array $structured_values) {
|
||||
$values = array();
|
||||
foreach ($structured_values as $item) {
|
||||
if (is_array($item['label'])) {
|
||||
// Nested elements are embedded in the label.
|
||||
$item['label'] = static::simplifyAllowedValues($item['label']);
|
||||
}
|
||||
$values[$item['value']] = $item['label'];
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a structured array of allowed values from a key-value array.
|
||||
*
|
||||
* @param array $values
|
||||
* Allowed values were the array key is the 'value' value, the value is
|
||||
* the 'label' value.
|
||||
*
|
||||
* @return array
|
||||
* Array of items with a 'value' and 'label' key each for the allowed
|
||||
* values.
|
||||
*
|
||||
* @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::simplifyAllowedValues()
|
||||
*/
|
||||
protected static function structureAllowedValues(array $values) {
|
||||
$structured_values = array();
|
||||
foreach ($values as $value => $label) {
|
||||
if (is_array($label)) {
|
||||
$label = static::structureAllowedValues($label);
|
||||
}
|
||||
$structured_values[] = array(
|
||||
'value' => static::castAllowedValue($value),
|
||||
'label' => $label,
|
||||
);
|
||||
}
|
||||
return $structured_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value to the correct type.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The value to cast.
|
||||
*
|
||||
* @return mixed
|
||||
* The casted value.
|
||||
*/
|
||||
protected static function castAllowedValue($value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'list_string' field type.
|
||||
*
|
||||
* @FieldType(
|
||||
* id = "list_string",
|
||||
* label = @Translation("List (text)"),
|
||||
* description = @Translation("This field stores text values from a list of allowed 'value => label' pairs, i.e. 'US States': IL => Illinois, IA => Iowa, IN => Indiana."),
|
||||
* category = @Translation("Text"),
|
||||
* default_widget = "options_select",
|
||||
* default_formatter = "list_default",
|
||||
* )
|
||||
*/
|
||||
class ListStringItem extends ListItemBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties['value'] = DataDefinition::create('string')
|
||||
->setLabel(t('Text value'))
|
||||
->addConstraint('Length', array('max' => 255))
|
||||
->setRequired(TRUE);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function schema(FieldStorageDefinitionInterface $field_definition) {
|
||||
return array(
|
||||
'columns' => array(
|
||||
'value' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'value' => array('value'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function allowedValuesDescription() {
|
||||
$description = '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label.');
|
||||
$description .= '<br/>' . t('The key is the stored value. The label will be used in displayed values and edit forms.');
|
||||
$description .= '<br/>' . t('The label is optional: if a line contains a single string, it will be used as key and label.');
|
||||
$description .= '</p>';
|
||||
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function validateAllowedValue($option) {
|
||||
if (Unicode::strlen($option) > 255) {
|
||||
return t('Allowed values list: each key must be a string at most 255 characters long.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function castAllowedValue($value) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\views\argument;
|
||||
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\FieldAPIHandlerTrait;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\argument\NumericArgument;
|
||||
|
||||
/**
|
||||
* Argument handler for list field to show the human readable name in the
|
||||
* summary.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("number_list_field")
|
||||
*/
|
||||
class NumberListField extends NumericArgument {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
use FieldAPIHandlerTrait;
|
||||
|
||||
/**
|
||||
* Stores the allowed values of this field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowedValues = NULL;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$field_storage = $this->getFieldStorageDefinition();
|
||||
$this->allowedValues = options_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['summary']['contains']['human'] = ['default' => FALSE];
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['summary']['human'] = [
|
||||
'#title' => $this->t('Display list value as human readable'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->options['summary']['human'],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="options[default_action]"]' => ['value' => 'summary'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summaryName($data) {
|
||||
$value = $data->{$this->name_alias};
|
||||
// If the list element has a human readable name show it.
|
||||
if (isset($this->allowedValues[$value]) && !empty($this->options['summary']['human'])) {
|
||||
return FieldFilteredMarkup::create($this->allowedValues[$value]);
|
||||
}
|
||||
// Else, fallback to the key.
|
||||
else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\views\argument;
|
||||
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\FieldAPIHandlerTrait;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\argument\StringArgument;
|
||||
|
||||
/**
|
||||
* Argument handler for list field to show the human readable name in summary.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("string_list_field")
|
||||
*/
|
||||
class StringListField extends StringArgument {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
use FieldAPIHandlerTrait;
|
||||
|
||||
/**
|
||||
* Stores the allowed values of this field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowedValues = NULL;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$field_storage = $this->getFieldStorageDefinition();
|
||||
$this->allowedValues = options_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$options['summary']['contains']['human'] = ['default' => FALSE];
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$form['summary']['human'] = [
|
||||
'#title' => $this->t('Display list value as human readable'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->options['summary']['human'],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="options[default_action]"]' => ['value' => 'summary'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summaryName($data) {
|
||||
$value = $data->{$this->name_alias};
|
||||
// If the list element has a human readable name show it.
|
||||
if (isset($this->allowedValues[$value]) && !empty($this->options['summary']['human'])) {
|
||||
$value = $this->allowedValues[$value];
|
||||
}
|
||||
return FieldFilteredMarkup::create($this->caseTransform($value, $this->options['case']));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Plugin\views\filter;
|
||||
|
||||
use Drupal\views\FieldAPIHandlerTrait;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\filter\ManyToOne;
|
||||
use Drupal\views\ViewExecutable;
|
||||
|
||||
/**
|
||||
* Filter handler which uses list-fields as options.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("list_field")
|
||||
*/
|
||||
class ListField extends ManyToOne {
|
||||
|
||||
use FieldAPIHandlerTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$field_storage = $this->getFieldStorageDefinition();
|
||||
// Set valueOptions here so getValueOptions() will just return it.
|
||||
$this->valueOptions = options_allowed_values($field_storage);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Tests\FieldTestBase;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\entity_test\Entity\EntityTestRev;
|
||||
|
||||
/**
|
||||
* Base class for testing allowed values of options fields.
|
||||
*/
|
||||
abstract class OptionsDynamicValuesTestBase extends FieldTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['options', 'entity_test', 'options_test'];
|
||||
|
||||
/**
|
||||
* The created entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Entity
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The field storage.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$field_name = 'test_options';
|
||||
$this->fieldStorage = FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test_rev',
|
||||
'type' => 'list_string',
|
||||
'cardinality' => 1,
|
||||
'settings' => [
|
||||
'allowed_values_function' => 'options_test_dynamic_values_callback',
|
||||
],
|
||||
]);
|
||||
$this->fieldStorage->save();
|
||||
|
||||
$this->field = FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test_rev',
|
||||
'bundle' => 'entity_test_rev',
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
entity_get_form_display('entity_test_rev', 'entity_test_rev', 'default')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'options_select',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create an entity and prepare test data that will be used by
|
||||
// options_test_dynamic_values_callback().
|
||||
$values = [
|
||||
'user_id' => mt_rand(1, 10),
|
||||
'name' => $this->randomMachineName(),
|
||||
];
|
||||
$this->entity = EntityTestRev::create($values);
|
||||
$this->entity->save();
|
||||
$this->test = [
|
||||
'label' => $this->entity->label(),
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'bundle' => $this->entity->bundle(),
|
||||
'uri' => $this->entity->url(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
/**
|
||||
* Tests the Options field allowed values function.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsDynamicValuesValidationTest extends OptionsDynamicValuesTestBase {
|
||||
/**
|
||||
* Test that allowed values function gets the entity.
|
||||
*/
|
||||
function testDynamicAllowedValues() {
|
||||
// Verify that validation passes against every value we had.
|
||||
foreach ($this->test as $key => $value) {
|
||||
$this->entity->test_options->value = $value;
|
||||
$violations = $this->entity->test_options->validate();
|
||||
$this->assertEqual(count($violations), 0, "$key is a valid value");
|
||||
}
|
||||
|
||||
// Now verify that validation does not pass against anything else.
|
||||
foreach ($this->test as $key => $value) {
|
||||
$this->entity->test_options->value = is_numeric($value) ? (100 - $value) : ('X' . $value);
|
||||
$violations = $this->entity->test_options->validate();
|
||||
$this->assertEqual(count($violations), 1, "$key is not a valid value");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
354
web/core/modules/options/src/Tests/OptionsFieldUITest.php
Normal file
354
web/core/modules/options/src/Tests/OptionsFieldUITest.php
Normal file
|
@ -0,0 +1,354 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Tests\FieldTestBase;
|
||||
|
||||
/**
|
||||
* Tests the Options field UI functionality.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsFieldUITest extends FieldTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'options', 'field_test', 'taxonomy', 'field_ui');
|
||||
|
||||
/**
|
||||
* The name of the created content type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $typeName;
|
||||
|
||||
/**
|
||||
* Machine name of the created content type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Name of the option field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* Admin path to manage field storage settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $adminPath;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user.
|
||||
$admin_user = $this->drupalCreateUser(['access content', 'administer taxonomy', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'bypass node access', 'administer node fields', 'administer node display']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create content type, with underscores.
|
||||
$this->typeName = 'test_' . strtolower($this->randomMachineName());
|
||||
$type = $this->drupalCreateContentType(['name' => $this->typeName, 'type' => $this->typeName]);
|
||||
$this->type = $type->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Options (integer) : test 'allowed values' input.
|
||||
*/
|
||||
function testOptionsAllowedValuesInteger() {
|
||||
$this->fieldName = 'field_options_integer';
|
||||
$this->createOptionsField('list_integer');
|
||||
|
||||
// Flat list of textual values.
|
||||
$string = "Zero\nOne";
|
||||
$array = array('0' => 'Zero', '1' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
||||
// Explicit integer keys.
|
||||
$string = "0|Zero\n2|Two";
|
||||
$array = array('0' => 'Zero', '2' => 'Two');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
|
||||
// Check that values can be added and removed.
|
||||
$string = "0|Zero\n1|One";
|
||||
$array = array('0' => 'Zero', '1' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
||||
// Non-integer keys.
|
||||
$this->assertAllowedValuesInput("1.1|One", 'keys must be integers', 'Non integer keys are rejected.');
|
||||
$this->assertAllowedValuesInput("abc|abc", 'keys must be integers', 'Non integer keys are rejected.');
|
||||
// Mixed list of keyed and unkeyed values.
|
||||
$this->assertAllowedValuesInput("Zero\n1|One", 'invalid input', 'Mixed lists are rejected.');
|
||||
|
||||
// Create a node with actual data for the field.
|
||||
$settings = array(
|
||||
'type' => $this->type,
|
||||
$this->fieldName => array(array('value' => 1)),
|
||||
);
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Check that a flat list of values is rejected once the field has data.
|
||||
$this->assertAllowedValuesInput( "Zero\nOne", 'invalid input', 'Unkeyed lists are rejected once the field has data.');
|
||||
|
||||
// Check that values can be added but values in use cannot be removed.
|
||||
$string = "0|Zero\n1|One\n2|Two";
|
||||
$array = array('0' => 'Zero', '1' => 'One', '2' => 'Two');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
||||
$string = "0|Zero\n1|One";
|
||||
$array = array('0' => 'Zero', '1' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
$this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
||||
|
||||
// Delete the node, remove the value.
|
||||
$node->delete();
|
||||
$string = "0|Zero";
|
||||
$array = array('0' => 'Zero');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
|
||||
// Check that the same key can only be used once.
|
||||
$string = "0|Zero\n0|One";
|
||||
$array = array('0' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Options (float) : test 'allowed values' input.
|
||||
*/
|
||||
function testOptionsAllowedValuesFloat() {
|
||||
$this->fieldName = 'field_options_float';
|
||||
$this->createOptionsField('list_float');
|
||||
|
||||
// Flat list of textual values.
|
||||
$string = "Zero\nOne";
|
||||
$array = array('0' => 'Zero', '1' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
||||
// Explicit numeric keys.
|
||||
$string = "0|Zero\n.5|Point five";
|
||||
$array = array('0' => 'Zero', '0.5' => 'Point five');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
|
||||
// Check that values can be added and removed.
|
||||
$string = "0|Zero\n.5|Point five\n1.0|One";
|
||||
$array = array('0' => 'Zero', '0.5' => 'Point five', '1' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
||||
// Non-numeric keys.
|
||||
$this->assertAllowedValuesInput("abc|abc\n", 'each key must be a valid integer or decimal', 'Non numeric keys are rejected.');
|
||||
// Mixed list of keyed and unkeyed values.
|
||||
$this->assertAllowedValuesInput("Zero\n1|One\n", 'invalid input', 'Mixed lists are rejected.');
|
||||
|
||||
// Create a node with actual data for the field.
|
||||
$settings = array(
|
||||
'type' => $this->type,
|
||||
$this->fieldName => array(array('value' => .5)),
|
||||
);
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Check that a flat list of values is rejected once the field has data.
|
||||
$this->assertAllowedValuesInput("Zero\nOne", 'invalid input', 'Unkeyed lists are rejected once the field has data.');
|
||||
|
||||
// Check that values can be added but values in use cannot be removed.
|
||||
$string = "0|Zero\n.5|Point five\n2|Two";
|
||||
$array = array('0' => 'Zero', '0.5' => 'Point five', '2' => 'Two');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
||||
$string = "0|Zero\n.5|Point five";
|
||||
$array = array('0' => 'Zero', '0.5' => 'Point five');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
$this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
||||
|
||||
// Delete the node, remove the value.
|
||||
$node->delete();
|
||||
$string = "0|Zero";
|
||||
$array = array('0' => 'Zero');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
|
||||
// Check that the same key can only be used once.
|
||||
$string = "0.5|Point five\n0.5|Half";
|
||||
$array = array('0.5' => 'Half');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
||||
|
||||
// Check that different forms of the same float value cannot be used.
|
||||
$string = "0|Zero\n.5|Point five\n0.5|Half";
|
||||
$array = array('0' => 'Zero', '0.5' => 'Half');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Different forms of the same value cannot be used.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Options (text) : test 'allowed values' input.
|
||||
*/
|
||||
function testOptionsAllowedValuesText() {
|
||||
$this->fieldName = 'field_options_text';
|
||||
$this->createOptionsField('list_string');
|
||||
|
||||
// Flat list of textual values.
|
||||
$string = "Zero\nOne";
|
||||
$array = array('Zero' => 'Zero', 'One' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
||||
// Explicit keys.
|
||||
$string = "zero|Zero\none|One";
|
||||
$array = array('zero' => 'Zero', 'one' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted.');
|
||||
// Check that values can be added and removed.
|
||||
$string = "zero|Zero\ntwo|Two";
|
||||
$array = array('zero' => 'Zero', 'two' => 'Two');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
||||
// Mixed list of keyed and unkeyed values.
|
||||
$string = "zero|Zero\nOne\n";
|
||||
$array = array('zero' => 'Zero', 'One' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Mixed lists are accepted.');
|
||||
// Overly long keys.
|
||||
$this->assertAllowedValuesInput("zero|Zero\n" . $this->randomMachineName(256) . "|One", 'each key must be a string at most 255 characters long', 'Overly long keys are rejected.');
|
||||
|
||||
// Create a node with actual data for the field.
|
||||
$settings = array(
|
||||
'type' => $this->type,
|
||||
$this->fieldName => array(array('value' => 'One')),
|
||||
);
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Check that flat lists of values are still accepted once the field has
|
||||
// data.
|
||||
$string = "Zero\nOne";
|
||||
$array = array('Zero' => 'Zero', 'One' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are still accepted once the field has data.');
|
||||
|
||||
// Check that values can be added but values in use cannot be removed.
|
||||
$string = "Zero\nOne\nTwo";
|
||||
$array = array('Zero' => 'Zero', 'One' => 'One', 'Two' => 'Two');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
||||
$string = "Zero\nOne";
|
||||
$array = array('Zero' => 'Zero', 'One' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
$this->assertAllowedValuesInput("Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
||||
|
||||
// Delete the node, remove the value.
|
||||
$node->delete();
|
||||
$string = "Zero";
|
||||
$array = array('Zero' => 'Zero');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
||||
|
||||
// Check that string values with dots can be used.
|
||||
$string = "Zero\nexample.com|Example";
|
||||
$array = array('Zero' => 'Zero', 'example.com' => 'Example');
|
||||
$this->assertAllowedValuesInput($string, $array, 'String value with dot is supported.');
|
||||
|
||||
// Check that the same key can only be used once.
|
||||
$string = "zero|Zero\nzero|One";
|
||||
$array = array('zero' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Options (text) : test 'trimmed values' input.
|
||||
*/
|
||||
function testOptionsTrimmedValuesText() {
|
||||
$this->fieldName = 'field_options_trimmed_text';
|
||||
$this->createOptionsField('list_string');
|
||||
|
||||
// Explicit keys.
|
||||
$string = "zero |Zero\none | One";
|
||||
$array = array('zero' => 'Zero', 'one' => 'One');
|
||||
$this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted and trimmed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create list field of a given type.
|
||||
*
|
||||
* @param string $type
|
||||
* 'list_integer', 'list_float' or 'list_string'
|
||||
*/
|
||||
protected function createOptionsField($type) {
|
||||
// Create a field.
|
||||
FieldStorageConfig::create(array(
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
'type' => $type,
|
||||
))->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => $this->type,
|
||||
])->save();
|
||||
|
||||
entity_get_form_display('node', $this->type, 'default')->setComponent($this->fieldName)->save();
|
||||
|
||||
$this->adminPath = 'admin/structure/types/manage/' . $this->type . '/fields/node.' . $this->type . '.' . $this->fieldName . '/storage';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a string input for the 'allowed values' form element.
|
||||
*
|
||||
* @param $input_string
|
||||
* The input string, in the pipe-linefeed format expected by the form
|
||||
* element.
|
||||
* @param $result
|
||||
* Either an expected resulting array in
|
||||
* $field->getSetting('allowed_values'), or an expected error message.
|
||||
* @param $message
|
||||
* Message to display.
|
||||
*/
|
||||
function assertAllowedValuesInput($input_string, $result, $message) {
|
||||
$edit = array('settings[allowed_values]' => $input_string);
|
||||
$this->drupalPostForm($this->adminPath, $edit, t('Save field settings'));
|
||||
$this->assertNoRaw('&lt;', 'The page does not have double escaped HTML tags.');
|
||||
|
||||
if (is_string($result)) {
|
||||
$this->assertText($result, $message);
|
||||
}
|
||||
else {
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $this->fieldName);
|
||||
$this->assertIdentical($field_storage->getSetting('allowed_values'), $result, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests normal and key formatter display on node display.
|
||||
*/
|
||||
function testNodeDisplay() {
|
||||
$this->fieldName = strtolower($this->randomMachineName());
|
||||
$this->createOptionsField('list_integer');
|
||||
$node = $this->drupalCreateNode(array('type' => $this->type));
|
||||
|
||||
$on = $this->randomMachineName();
|
||||
$off = $this->randomMachineName();
|
||||
$edit = array(
|
||||
'settings[allowed_values]' =>
|
||||
"1|$on
|
||||
0|$off",
|
||||
);
|
||||
|
||||
$this->drupalPostForm($this->adminPath, $edit, t('Save field settings'));
|
||||
$this->assertText(format_string('Updated field @field_name field settings.', array('@field_name' => $this->fieldName)), "The 'On' and 'Off' form fields work for boolean fields.");
|
||||
|
||||
// Select a default value.
|
||||
$edit = array(
|
||||
$this->fieldName => '1',
|
||||
);
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
|
||||
|
||||
// Check the node page and see if the values are correct.
|
||||
$file_formatters = array('list_default', 'list_key');
|
||||
foreach ($file_formatters as $formatter) {
|
||||
$edit = array(
|
||||
"fields[$this->fieldName][type]" => $formatter,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->typeName . '/display', $edit, t('Save'));
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
|
||||
if ($formatter == 'list_default') {
|
||||
$output = $on;
|
||||
}
|
||||
else {
|
||||
$output = '1';
|
||||
}
|
||||
|
||||
$elements = $this->xpath('//div[text()="' . $output . '"]');
|
||||
$this->assertEqual(count($elements), 1, 'Correct options found.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Tests\FieldTestBase;
|
||||
|
||||
/**
|
||||
* Tests option fields can be updated and created through config synchronization.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsFloatFieldImportTest extends FieldTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'options', 'field_ui', 'config', 'options_config_install_test');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create test user.
|
||||
$admin_user = $this->drupalCreateUser(array('synchronize configuration', 'access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'bypass node access', 'administer node fields', 'administer node display'));
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that importing list_float fields works.
|
||||
*/
|
||||
public function testImport() {
|
||||
$field_name = 'field_options_float';
|
||||
$type = 'options_install_test';
|
||||
|
||||
// Test the results on installing options_config_install_test. All the
|
||||
// necessary configuration for this test is created by installing that
|
||||
// module.
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '0.5' => 'Point five'));
|
||||
|
||||
$admin_path = 'admin/structure/types/manage/' . $type . '/fields/node.' . $type . '.' . $field_name . '/storage';
|
||||
|
||||
// Export active config to sync.
|
||||
$this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
|
||||
|
||||
// Set the active to not use dots in the allowed values key names.
|
||||
$edit = array('settings[allowed_values]' => "0|Zero\n1|One");
|
||||
$this->drupalPostForm($admin_path, $edit, t('Save field settings'));
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '1' => 'One'));
|
||||
|
||||
// Import configuration with dots in the allowed values key names. This
|
||||
// tests \Drupal\Core\Config\Entity\ConfigEntityStorage::importUpdate().
|
||||
$this->drupalGet('admin/config/development/configuration');
|
||||
$this->drupalPostForm(NULL, array(), t('Import all'));
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '0.5' => 'Point five'));
|
||||
|
||||
// Delete field to test creation. This tests
|
||||
// \Drupal\Core\Config\Entity\ConfigEntityStorage::importCreate().
|
||||
FieldConfig::loadByName('node', $type, $field_name)->delete();
|
||||
|
||||
$this->drupalGet('admin/config/development/configuration');
|
||||
$this->drupalPostForm(NULL, array(), t('Import all'));
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$this->assertIdentical($field_storage->getSetting('allowed_values'), $array = array('0' => 'Zero', '0.5' => 'Point five'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
/**
|
||||
* Tests an options select with a dynamic allowed values function.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsSelectDynamicValuesTest extends OptionsDynamicValuesTestBase {
|
||||
/**
|
||||
* Tests the 'options_select' widget (single select).
|
||||
*/
|
||||
function testSelectListDynamic() {
|
||||
// Create an entity.
|
||||
$this->entity->save();
|
||||
|
||||
// Create a web user.
|
||||
$web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Display form.
|
||||
$this->drupalGet('entity_test_rev/manage/' . $this->entity->id() . '/edit');
|
||||
$options = $this->xpath('//select[@id="edit-test-options"]/option');
|
||||
$this->assertEqual(count($options), count($this->test) + 1);
|
||||
foreach ($options as $option) {
|
||||
$value = (string) $option['value'];
|
||||
if ($value != '_none') {
|
||||
$this->assertTrue(array_search($value, $this->test));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
494
web/core/modules/options/src/Tests/OptionsWidgetsTest.php
Normal file
494
web/core/modules/options/src/Tests/OptionsWidgetsTest.php
Normal file
|
@ -0,0 +1,494 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\options\Tests;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Tests\FieldTestBase;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests the Options widgets.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsWidgetsTest extends FieldTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'options', 'entity_test', 'options_test', 'taxonomy', 'field_ui'];
|
||||
|
||||
/**
|
||||
* A field storage with cardinality 1 to use in this test class.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $card1;
|
||||
|
||||
/**
|
||||
* A field storage with cardinality 2 to use in this test class.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $card2;
|
||||
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Field storage with cardinality 1.
|
||||
$this->card1 = FieldStorageConfig::create([
|
||||
'field_name' => 'card_1',
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'list_integer',
|
||||
'cardinality' => 1,
|
||||
'settings' => [
|
||||
'allowed_values' => [
|
||||
// Make sure that 0 works as an option.
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
// Make sure that option text is properly sanitized.
|
||||
2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
|
||||
// Make sure that HTML entities in option text are not double-encoded.
|
||||
3 => 'Some HTML encoded markup with < & >',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->card1->save();
|
||||
|
||||
// Field storage with cardinality 2.
|
||||
$this->card2 = FieldStorageConfig::create([
|
||||
'field_name' => 'card_2',
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'list_integer',
|
||||
'cardinality' => 2,
|
||||
'settings' => [
|
||||
'allowed_values' => [
|
||||
// Make sure that 0 works as an option.
|
||||
0 => 'Zero',
|
||||
1 => 'One',
|
||||
// Make sure that option text is properly sanitized.
|
||||
2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->card2->save();
|
||||
|
||||
// Create a web user.
|
||||
$this->drupalLogin($this->drupalCreateUser(['view test entity', 'administer entity_test content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the 'options_buttons' widget (single select).
|
||||
*/
|
||||
function testRadioButtons() {
|
||||
// Create an instance of the 'single value' field.
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $this->card1,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$field->save();
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card1->getName(), [
|
||||
'type' => 'options_buttons',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create an entity.
|
||||
$entity = EntityTest::create([
|
||||
'user_id' => 1,
|
||||
'name' => $this->randomMachineName(),
|
||||
]);
|
||||
$entity->save();
|
||||
$entity_init = clone $entity;
|
||||
|
||||
// With no field data, no buttons are checked.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertNoFieldChecked('edit-card-1-0');
|
||||
$this->assertNoFieldChecked('edit-card-1-1');
|
||||
$this->assertNoFieldChecked('edit-card-1-2');
|
||||
$this->assertRaw('Some dangerous & unescaped <strong>markup</strong>', 'Option text was properly filtered.');
|
||||
$this->assertRaw('Some HTML encoded markup with < & >');
|
||||
|
||||
// Select first option.
|
||||
$edit = array('card_1' => 0);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array(0));
|
||||
|
||||
// Check that the selected button is checked.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-card-1-0');
|
||||
$this->assertNoFieldChecked('edit-card-1-1');
|
||||
$this->assertNoFieldChecked('edit-card-1-2');
|
||||
|
||||
// Unselect option.
|
||||
$edit = array('card_1' => '_none');
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array());
|
||||
|
||||
// Check that required radios with one option is auto-selected.
|
||||
$this->card1->setSetting('allowed_values', [99 => 'Only allowed value']);
|
||||
$this->card1->save();
|
||||
$field->setRequired(TRUE);
|
||||
$field->save();
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-card-1-99');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the 'options_buttons' widget (multiple select).
|
||||
*/
|
||||
function testCheckBoxes() {
|
||||
// Create an instance of the 'multiple values' field.
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $this->card2,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$field->save();
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card2->getName(), array(
|
||||
'type' => 'options_buttons',
|
||||
))
|
||||
->save();
|
||||
|
||||
// Create an entity.
|
||||
$entity = EntityTest::create(array(
|
||||
'user_id' => 1,
|
||||
'name' => $this->randomMachineName(),
|
||||
));
|
||||
$entity->save();
|
||||
$entity_init = clone $entity;
|
||||
|
||||
// Display form: with no field data, nothing is checked.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertNoFieldChecked('edit-card-2-0');
|
||||
$this->assertNoFieldChecked('edit-card-2-1');
|
||||
$this->assertNoFieldChecked('edit-card-2-2');
|
||||
$this->assertRaw('Some dangerous & unescaped <strong>markup</strong>', 'Option text was properly filtered.');
|
||||
|
||||
// Submit form: select first and third options.
|
||||
$edit = array(
|
||||
'card_2[0]' => TRUE,
|
||||
'card_2[1]' => FALSE,
|
||||
'card_2[2]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0, 2));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-card-2-0');
|
||||
$this->assertNoFieldChecked('edit-card-2-1');
|
||||
$this->assertFieldChecked('edit-card-2-2');
|
||||
|
||||
// Submit form: select only first option.
|
||||
$edit = array(
|
||||
'card_2[0]' => TRUE,
|
||||
'card_2[1]' => FALSE,
|
||||
'card_2[2]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-card-2-0');
|
||||
$this->assertNoFieldChecked('edit-card-2-1');
|
||||
$this->assertNoFieldChecked('edit-card-2-2');
|
||||
|
||||
// Submit form: select the three options while the field accepts only 2.
|
||||
$edit = array(
|
||||
'card_2[0]' => TRUE,
|
||||
'card_2[1]' => TRUE,
|
||||
'card_2[2]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText('this field cannot hold more than 2 values', 'Validation error was displayed.');
|
||||
|
||||
// Submit form: uncheck all options.
|
||||
$edit = array(
|
||||
'card_2[0]' => FALSE,
|
||||
'card_2[1]' => FALSE,
|
||||
'card_2[2]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
// Check that the value was saved.
|
||||
$this->assertFieldValues($entity_init, 'card_2', array());
|
||||
|
||||
// Required checkbox with one option is auto-selected.
|
||||
$this->card2->setSetting('allowed_values', [99 => 'Only allowed value']);
|
||||
$this->card2->save();
|
||||
$field->setRequired(TRUE);
|
||||
$field->save();
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-card-2-99');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the 'options_select' widget (single select).
|
||||
*/
|
||||
function testSelectListSingle() {
|
||||
// Create an instance of the 'single value' field.
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $this->card1,
|
||||
'bundle' => 'entity_test',
|
||||
'required' => TRUE,
|
||||
]);
|
||||
$field->save();
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card1->getName(), array(
|
||||
'type' => 'options_select',
|
||||
))
|
||||
->save();
|
||||
|
||||
// Create an entity.
|
||||
$entity = EntityTest::create(array(
|
||||
'user_id' => 1,
|
||||
'name' => $this->randomMachineName(),
|
||||
));
|
||||
$entity->save();
|
||||
$entity_init = clone $entity;
|
||||
|
||||
// Display form.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
// A required field without any value has a "none" option.
|
||||
$this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1', ':label' => t('- Select a value -'))), 'A required select list has a "Select a value" choice.');
|
||||
|
||||
// With no field data, nothing is selected.
|
||||
$this->assertNoOptionSelected('edit-card-1', '_none');
|
||||
$this->assertNoOptionSelected('edit-card-1', 0);
|
||||
$this->assertNoOptionSelected('edit-card-1', 1);
|
||||
$this->assertNoOptionSelected('edit-card-1', 2);
|
||||
$this->assertRaw('Some dangerous & unescaped markup', 'Option text was properly filtered.');
|
||||
|
||||
// Submit form: select invalid 'none' option.
|
||||
$edit = array('card_1' => '_none');
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertRaw(t('@title field is required.', array('@title' => $field->getName())), 'Cannot save a required field when selecting "none" from the select list.');
|
||||
|
||||
// Submit form: select first option.
|
||||
$edit = array('card_1' => 0);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array(0));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
// A required field with a value has no 'none' option.
|
||||
$this->assertFalse($this->xpath('//select[@id=:id]//option[@value="_none"]', array(':id' => 'edit-card-1')), 'A required select list with an actual value has no "none" choice.');
|
||||
$this->assertOptionSelected('edit-card-1', 0);
|
||||
$this->assertNoOptionSelected('edit-card-1', 1);
|
||||
$this->assertNoOptionSelected('edit-card-1', 2);
|
||||
|
||||
// Make the field non required.
|
||||
$field->setRequired(FALSE);
|
||||
$field->save();
|
||||
|
||||
// Display form.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
// A non-required field has a 'none' option.
|
||||
$this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1', ':label' => t('- None -'))), 'A non-required select list has a "None" choice.');
|
||||
// Submit form: Unselect the option.
|
||||
$edit = array('card_1' => '_none');
|
||||
$this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array());
|
||||
|
||||
// Test optgroups.
|
||||
|
||||
$this->card1->setSetting('allowed_values', []);
|
||||
$this->card1->setSetting('allowed_values_function', 'options_test_allowed_values_callback');
|
||||
$this->card1->save();
|
||||
|
||||
// Display form: with no field data, nothing is selected
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertNoOptionSelected('edit-card-1', 0);
|
||||
$this->assertNoOptionSelected('edit-card-1', 1);
|
||||
$this->assertNoOptionSelected('edit-card-1', 2);
|
||||
$this->assertRaw('Some dangerous & unescaped markup', 'Option text was properly filtered.');
|
||||
$this->assertRaw('More <script>dangerous</script> markup', 'Option group text was properly filtered.');
|
||||
$this->assertRaw('Group 1', 'Option groups are displayed.');
|
||||
|
||||
// Submit form: select first option.
|
||||
$edit = array('card_1' => 0);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array(0));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertOptionSelected('edit-card-1', 0);
|
||||
$this->assertNoOptionSelected('edit-card-1', 1);
|
||||
$this->assertNoOptionSelected('edit-card-1', 2);
|
||||
|
||||
// Submit form: Unselect the option.
|
||||
$edit = array('card_1' => '_none');
|
||||
$this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_1', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the 'options_select' widget (multiple select).
|
||||
*/
|
||||
function testSelectListMultiple() {
|
||||
// Create an instance of the 'multiple values' field.
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $this->card2,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$field->save();
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card2->getName(), array(
|
||||
'type' => 'options_select',
|
||||
))
|
||||
->save();
|
||||
|
||||
// Create an entity.
|
||||
$entity = EntityTest::create(array(
|
||||
'user_id' => 1,
|
||||
'name' => $this->randomMachineName(),
|
||||
));
|
||||
$entity->save();
|
||||
$entity_init = clone $entity;
|
||||
|
||||
// Display form: with no field data, nothing is selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertOptionSelected("edit-card-2", '_none');
|
||||
$this->assertNoOptionSelected('edit-card-2', 0);
|
||||
$this->assertNoOptionSelected('edit-card-2', 1);
|
||||
$this->assertNoOptionSelected('edit-card-2', 2);
|
||||
$this->assertRaw('Some dangerous & unescaped markup', 'Option text was properly filtered.');
|
||||
|
||||
// Submit form: select first and third options.
|
||||
$edit = array('card_2[]' => array(0 => 0, 2 => 2));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0, 2));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertOptionSelected('edit-card-2', 0);
|
||||
$this->assertNoOptionSelected('edit-card-2', 1);
|
||||
$this->assertOptionSelected('edit-card-2', 2);
|
||||
|
||||
// Submit form: select only first option.
|
||||
$edit = array('card_2[]' => array(0 => 0));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertOptionSelected('edit-card-2', 0);
|
||||
$this->assertNoOptionSelected('edit-card-2', 1);
|
||||
$this->assertNoOptionSelected('edit-card-2', 2);
|
||||
|
||||
// Submit form: select the three options while the field accepts only 2.
|
||||
$edit = array('card_2[]' => array(0 => 0, 1 => 1, 2 => 2));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText('this field cannot hold more than 2 values', 'Validation error was displayed.');
|
||||
|
||||
// Submit form: uncheck all options.
|
||||
$edit = array('card_2[]' => array());
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array());
|
||||
|
||||
// Test the 'None' option.
|
||||
|
||||
// Check that the 'none' option has no effect if actual options are selected
|
||||
// as well.
|
||||
$edit = array('card_2[]' => array('_none' => '_none', 0 => 0));
|
||||
$this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0));
|
||||
|
||||
// Check that selecting the 'none' option empties the field.
|
||||
$edit = array('card_2[]' => array('_none' => '_none'));
|
||||
$this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array());
|
||||
|
||||
// A required select list does not have an empty key.
|
||||
$field->setRequired(TRUE);
|
||||
$field->save();
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-2')), 'A required select list does not have an empty key.');
|
||||
|
||||
// We do not have to test that a required select list with one option is
|
||||
// auto-selected because the browser does it for us.
|
||||
|
||||
// Test optgroups.
|
||||
|
||||
// Use a callback function defining optgroups.
|
||||
$this->card2->setSetting('allowed_values', []);
|
||||
$this->card2->setSetting('allowed_values_function', 'options_test_allowed_values_callback');
|
||||
$this->card2->save();
|
||||
$field->setRequired(FALSE);
|
||||
$field->save();
|
||||
|
||||
// Display form: with no field data, nothing is selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertNoOptionSelected('edit-card-2', 0);
|
||||
$this->assertNoOptionSelected('edit-card-2', 1);
|
||||
$this->assertNoOptionSelected('edit-card-2', 2);
|
||||
$this->assertRaw('Some dangerous & unescaped markup', 'Option text was properly filtered.');
|
||||
$this->assertRaw('More <script>dangerous</script> markup', 'Option group text was properly filtered.');
|
||||
$this->assertRaw('Group 1', 'Option groups are displayed.');
|
||||
|
||||
// Submit form: select first option.
|
||||
$edit = array('card_2[]' => array(0 => 0));
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array(0));
|
||||
|
||||
// Display form: check that the right options are selected.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertOptionSelected('edit-card-2', 0);
|
||||
$this->assertNoOptionSelected('edit-card-2', 1);
|
||||
$this->assertNoOptionSelected('edit-card-2', 2);
|
||||
|
||||
// Submit form: Unselect the option.
|
||||
$edit = array('card_2[]' => array('_none' => '_none'));
|
||||
$this->drupalPostForm('entity_test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertFieldValues($entity_init, 'card_2', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the 'options_select' and 'options_button' widget for empty value.
|
||||
*/
|
||||
function testEmptyValue() {
|
||||
// Create an instance of the 'single value' field.
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $this->card1,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
// Change it to the check boxes/radio buttons widget.
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card1->getName(), [
|
||||
'type' => 'options_buttons',
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create an entity.
|
||||
$entity = EntityTest::create([
|
||||
'user_id' => 1,
|
||||
'name' => $this->randomMachineName(),
|
||||
]);
|
||||
$entity->save();
|
||||
|
||||
// Display form: check that _none options are present and has label.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
$this->assertTrue($this->xpath('//div[@id=:id]//input[@value=:value]', array(':id' => 'edit-card-1', ':value' => '_none')), 'A test radio button has a "None" choice.');
|
||||
$this->assertTrue($this->xpath('//div[@id=:id]//label[@for=:for and text()=:label]', array(':id' => 'edit-card-1', ':for' => 'edit-card-1-none', ':label' => 'N/A')), 'A test radio button has a "N/A" choice.');
|
||||
|
||||
// Change it to the select widget.
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->card1->getName(), array(
|
||||
'type' => 'options_select',
|
||||
))
|
||||
->save();
|
||||
|
||||
// Display form: check that _none options are present and has label.
|
||||
$this->drupalGet('entity_test/manage/' . $entity->id() . '/edit');
|
||||
// A required field without any value has a "none" option.
|
||||
$this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1', ':label' => t('- None -'))), 'A test select has a "None" choice.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.options_install_test.body
|
||||
- node.type.options_install_test
|
||||
module:
|
||||
- text
|
||||
id: node.options_install_test.default
|
||||
targetEntityType: node
|
||||
bundle: options_install_test
|
||||
mode: default
|
||||
content:
|
||||
title:
|
||||
type: string_textfield
|
||||
weight: -5
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
uid:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 5
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
created:
|
||||
type: datetime_timestamp
|
||||
weight: 10
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
promote:
|
||||
type: boolean_checkbox
|
||||
settings:
|
||||
display_label: true
|
||||
weight: 15
|
||||
third_party_settings: { }
|
||||
sticky:
|
||||
type: boolean_checkbox
|
||||
settings:
|
||||
display_label: true
|
||||
weight: 16
|
||||
third_party_settings: { }
|
||||
body:
|
||||
type: text_textarea_with_summary
|
||||
weight: 26
|
||||
settings:
|
||||
rows: 9
|
||||
summary_rows: 3
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
hidden: { }
|
||||
third_party_settings: { }
|
|
@ -0,0 +1,25 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.options_install_test.body
|
||||
- node.type.options_install_test
|
||||
module:
|
||||
- text
|
||||
- user
|
||||
id: node.options_install_test.default
|
||||
targetEntityType: node
|
||||
bundle: options_install_test
|
||||
mode: default
|
||||
content:
|
||||
links:
|
||||
weight: 100
|
||||
body:
|
||||
label: hidden
|
||||
type: text_default
|
||||
weight: 101
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
hidden:
|
||||
langcode: true
|
||||
third_party_settings: { }
|
|
@ -0,0 +1,27 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- core.entity_view_mode.node.teaser
|
||||
- field.field.node.options_install_test.body
|
||||
- node.type.options_install_test
|
||||
module:
|
||||
- text
|
||||
- user
|
||||
id: node.options_install_test.teaser
|
||||
targetEntityType: node
|
||||
bundle: options_install_test
|
||||
mode: teaser
|
||||
content:
|
||||
links:
|
||||
weight: 100
|
||||
body:
|
||||
label: hidden
|
||||
type: text_summary_or_trimmed
|
||||
weight: 101
|
||||
settings:
|
||||
trim_length: 600
|
||||
third_party_settings: { }
|
||||
hidden:
|
||||
langcode: true
|
||||
third_party_settings: { }
|
|
@ -0,0 +1,20 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.body
|
||||
- node.type.options_install_test
|
||||
id: node.options_install_test.body
|
||||
field_name: body
|
||||
entity_type: node
|
||||
bundle: options_install_test
|
||||
label: Body
|
||||
description: ''
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
display_summary: true
|
||||
third_party_settings: { }
|
||||
field_type: text_with_summary
|
|
@ -0,0 +1,19 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_options_float
|
||||
- node.type.options_install_test
|
||||
id: node.options_install_test.field_options_float
|
||||
field_name: field_options_float
|
||||
entity_type: node
|
||||
bundle: options_install_test
|
||||
label: field_options_float
|
||||
description: ''
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
field_type: list_float
|
|
@ -0,0 +1,26 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- options
|
||||
id: node.field_options_float
|
||||
field_name: field_options_float
|
||||
entity_type: node
|
||||
type: list_float
|
||||
settings:
|
||||
allowed_values:
|
||||
-
|
||||
value: !!float 0
|
||||
label: Zero
|
||||
-
|
||||
value: 0.5
|
||||
label: 'Point five'
|
||||
allowed_values_function: ''
|
||||
module: options
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
|
@ -0,0 +1,11 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
name: options_install_test
|
||||
type: options_install_test
|
||||
description: null
|
||||
help: null
|
||||
new_revision: false
|
||||
preview_mode: 1
|
||||
display_submitted: true
|
||||
third_party_settings: { }
|
|
@ -0,0 +1,9 @@
|
|||
name: 'Options config install test'
|
||||
type: module
|
||||
description: 'Support module for the Options module tests.'
|
||||
core: 8.x
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- node
|
||||
- options
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Options test'
|
||||
type: module
|
||||
description: 'Support module for the Options module tests.'
|
||||
core: 8.x
|
||||
package: Testing
|
||||
version: VERSION
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the List module tests.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Implements callback_allowed_values_function().
|
||||
*
|
||||
* @see options_allowed_values()
|
||||
*/
|
||||
function options_test_allowed_values_callback(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) {
|
||||
$values = array(
|
||||
'Group 1' => array(
|
||||
0 => 'Zero',
|
||||
),
|
||||
1 => 'One',
|
||||
'Group 2' => array(
|
||||
2 => 'Some <script>dangerous</script> & unescaped <strong>markup</strong>',
|
||||
),
|
||||
'More <script>dangerous</script> markup' => array(
|
||||
3 => 'Three',
|
||||
),
|
||||
);
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_allowed_values_function().
|
||||
*
|
||||
* @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(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);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
name: 'Options test views'
|
||||
type: module
|
||||
description: 'Provides default views for views options tests.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- options
|
||||
- views
|
|
@ -0,0 +1,200 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_options_list_argument_numeric
|
||||
label: 'test options list argument (numeric)'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 1
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value:
|
||||
article: article
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: '0'
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: nid
|
||||
field: nid
|
||||
order: DESC
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
plugin_id: standard
|
||||
title: 'test options list argument'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments:
|
||||
field_test_list_integer_value:
|
||||
id: field_test_list_integer_value
|
||||
table: field_data_field_test_list_integer
|
||||
field: field_test_list_integer_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: empty
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
items_per_page: 25
|
||||
count: false
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
human: true
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
break_phrase: false
|
||||
not: false
|
||||
plugin_id: number_list_field
|
||||
display_extenders: { }
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
|
@ -0,0 +1,199 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_options_list_argument_string
|
||||
label: 'test options list argument (string)'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 1
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value:
|
||||
article: article
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: '0'
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: nid
|
||||
field: nid
|
||||
order: DESC
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
plugin_id: standard
|
||||
title: 'test options list argument'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments:
|
||||
field_test_list_string_value:
|
||||
id: field_test_list_string_value
|
||||
table: field_data_field_test_list_string
|
||||
field: field_test_list_string_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: empty
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: false
|
||||
title: ''
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
items_per_page: 25
|
||||
count: false
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
human: true
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
break_phrase: false
|
||||
plugin_id: string_list_field
|
||||
display_extenders: { }
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
|
@ -0,0 +1,204 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.article
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_options_list_filter
|
||||
label: test_options_list_filter
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 1
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: node_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
field_test_list_string_value:
|
||||
id: field_test_list_string_value
|
||||
table: field_data_field_test_list_string
|
||||
field: field_test_list_string_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value:
|
||||
man: man
|
||||
woman: woman
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
reduce_duplicates: false
|
||||
plugin_id: list_field
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: in
|
||||
value:
|
||||
article: article
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
nid:
|
||||
id: nid
|
||||
table: nid
|
||||
field: nid
|
||||
order: DESC
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
plugin_id: standard
|
||||
title: test_options_list_filter
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: Block
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
100
web/core/modules/options/tests/src/Kernel/OptionsFieldTest.php
Normal file
100
web/core/modules/options/tests/src/Kernel/OptionsFieldTest.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel;
|
||||
|
||||
use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests for the 'Options' field types.
|
||||
*
|
||||
* @group options
|
||||
*/
|
||||
class OptionsFieldTest extends OptionsFieldUnitTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('options');
|
||||
|
||||
/**
|
||||
* Test that allowed values can be updated.
|
||||
*/
|
||||
function testUpdateAllowedValues() {
|
||||
// All three options appear.
|
||||
$entity = EntityTest::create();
|
||||
$form = \Drupal::service('entity.form_builder')->getForm($entity);
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists');
|
||||
|
||||
// Use one of the values in an actual entity, and check that this value
|
||||
// cannot be removed from the list.
|
||||
$entity = EntityTest::create();
|
||||
$entity->{$this->fieldName}->value = 1;
|
||||
$entity->save();
|
||||
$this->fieldStorage->setSetting('allowed_values', [2 => 'Two']);
|
||||
try {
|
||||
$this->fieldStorage->save();
|
||||
$this->fail(t('Cannot update a list field storage to not include keys with existing data.'));
|
||||
}
|
||||
catch (FieldStorageDefinitionUpdateForbiddenException $e) {
|
||||
$this->pass(t('Cannot update a list field storage to not include keys with existing data.'));
|
||||
}
|
||||
// Empty the value, so that we can actually remove the option.
|
||||
unset($entity->{$this->fieldName});
|
||||
$entity->save();
|
||||
|
||||
// Removed options do not appear.
|
||||
$this->fieldStorage->setSetting('allowed_values', [2 => 'Two']);
|
||||
$this->fieldStorage->save();
|
||||
$entity = EntityTest::create();
|
||||
$form = \Drupal::service('entity.form_builder')->getForm($entity);
|
||||
$this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
|
||||
$this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist');
|
||||
|
||||
// Completely new options appear.
|
||||
$this->fieldStorage->setSetting('allowed_values', [10 => 'Update', 20 => 'Twenty']);
|
||||
$this->fieldStorage->save();
|
||||
// The entity holds an outdated field object with the old allowed values
|
||||
// setting, so we need to reinitialize the entity object.
|
||||
$entity = EntityTest::create();
|
||||
$form = \Drupal::service('entity.form_builder')->getForm($entity);
|
||||
$this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist');
|
||||
$this->assertTrue(empty($form[$this->fieldName]['widget'][2]), 'Option 2 does not exist');
|
||||
$this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][10]), 'Option 10 exists');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][20]), 'Option 20 exists');
|
||||
|
||||
// Options are reset when a new field with the same name is created.
|
||||
$this->fieldStorage->delete();
|
||||
FieldStorageConfig::create($this->fieldStorageDefinition)->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->fieldName, array(
|
||||
'type' => 'options_buttons',
|
||||
))
|
||||
->save();
|
||||
$entity = EntityTest::create();
|
||||
$form = \Drupal::service('entity.form_builder')->getForm($entity);
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
|
||||
$this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists');
|
||||
|
||||
// Test the generateSampleValue() method.
|
||||
$entity = EntityTest::create();
|
||||
$entity->{$this->fieldName}->generateSampleItems();
|
||||
$this->entityValidateAndSave($entity);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Base class for Options module integration tests.
|
||||
*/
|
||||
abstract class OptionsFieldUnitTestBase extends FieldKernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('options');
|
||||
|
||||
/**
|
||||
* The field name used in the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName = 'test_options';
|
||||
|
||||
/**
|
||||
* The field storage definition used to created the field storage.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldStorageDefinition;
|
||||
|
||||
/**
|
||||
* The list field storage used in the test.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
/**
|
||||
* The list field used in the test.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldConfig
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
|
||||
$this->fieldStorageDefinition = array(
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'list_integer',
|
||||
'cardinality' => 1,
|
||||
'settings' => array(
|
||||
'allowed_values' => array(1 => 'One', 2 => 'Two', 3 => 'Three'),
|
||||
),
|
||||
);
|
||||
$this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition);
|
||||
$this->fieldStorage->save();
|
||||
|
||||
$this->field = FieldConfig::create([
|
||||
'field_storage' => $this->fieldStorage,
|
||||
'bundle' => 'entity_test',
|
||||
]);
|
||||
$this->field->save();
|
||||
|
||||
entity_get_form_display('entity_test', 'entity_test', 'default')
|
||||
->setComponent($this->fieldName, array(
|
||||
'type' => 'options_buttons',
|
||||
))
|
||||
->save();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
|
||||
/**
|
||||
* Tests the Options field type formatters.
|
||||
*
|
||||
* @group options
|
||||
* @see \Drupal\options\Plugin\Field\FieldFormatter\OptionsDefaultFormatter
|
||||
* @see \Drupal\options\Plugin\Field\FieldFormatter\OptionsKeyFormatter
|
||||
*/
|
||||
class OptionsFormattersTest extends OptionsFieldUnitTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the formatters.
|
||||
*/
|
||||
public function testFormatter() {
|
||||
$entity = EntityTest::create();
|
||||
$entity->{$this->fieldName}->value = 1;
|
||||
|
||||
$items = $entity->get($this->fieldName);
|
||||
|
||||
$build = $items->view();
|
||||
$this->assertEqual($build['#formatter'], 'list_default', 'Ensure to fall back to the default formatter.');
|
||||
$this->assertEqual($build[0]['#markup'], 'One');
|
||||
|
||||
$build = $items->view(array('type' => 'list_key'));
|
||||
$this->assertEqual($build['#formatter'], 'list_key', 'The chosen formatter is used.');
|
||||
$this->assertEqual((string) $build[0]['#markup'], 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel\Views;
|
||||
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests file views data.
|
||||
*
|
||||
* @group file
|
||||
*/
|
||||
class FileViewsDataTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('file', 'views', 'entity_test', 'user', 'field');
|
||||
|
||||
/**
|
||||
* Tests views data generated for file field relationship.
|
||||
*
|
||||
* @see file_field_views_data()
|
||||
* @see file_field_views_data_views_data_alter()
|
||||
*/
|
||||
public function testRelationshipViewsData() {
|
||||
// Create file field to entity_test.
|
||||
FieldStorageConfig::create(array(
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'field_base_file',
|
||||
'type' => 'file',
|
||||
))->save();
|
||||
FieldConfig::create(array(
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'field_base_file',
|
||||
'bundle' => 'entity_test',
|
||||
))->save();
|
||||
// Check the generated views data.
|
||||
$views_data = Views::viewsData()->get('entity_test__field_base_file');
|
||||
$relationship = $views_data['field_base_file_target_id']['relationship'];
|
||||
$this->assertEqual($relationship['id'], 'standard');
|
||||
$this->assertEqual($relationship['base'], 'file_managed');
|
||||
$this->assertEqual($relationship['base field'], 'fid');
|
||||
$this->assertEqual($relationship['entity type'], 'file');
|
||||
// Check the backwards reference.
|
||||
$views_data = Views::viewsData()->get('file_managed');
|
||||
$relationship = $views_data['reverse_field_base_file_entity_test']['relationship'];
|
||||
$this->assertEqual($relationship['id'], 'entity_reverse');
|
||||
$this->assertEqual($relationship['base'], 'entity_test');
|
||||
$this->assertEqual($relationship['base field'], 'id');
|
||||
$this->assertEqual($relationship['field table'], 'entity_test__field_base_file');
|
||||
$this->assertEqual($relationship['field field'], 'field_base_file_target_id');
|
||||
$this->assertEqual($relationship['field_name'], 'field_base_file');
|
||||
$this->assertEqual($relationship['entity_type'], 'entity_test');
|
||||
$this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
|
||||
|
||||
// Create file field to entity_test_mul.
|
||||
FieldStorageConfig::create(array(
|
||||
'entity_type' => 'entity_test_mul',
|
||||
'field_name' => 'field_data_file',
|
||||
'type' => 'file',
|
||||
))->save();
|
||||
FieldConfig::create(array(
|
||||
'entity_type' => 'entity_test_mul',
|
||||
'field_name' => 'field_data_file',
|
||||
'bundle' => 'entity_test_mul',
|
||||
))->save();
|
||||
// Check the generated views data.
|
||||
$views_data = Views::viewsData()->get('entity_test_mul__field_data_file');
|
||||
$relationship = $views_data['field_data_file_target_id']['relationship'];
|
||||
$this->assertEqual($relationship['id'], 'standard');
|
||||
$this->assertEqual($relationship['base'], 'file_managed');
|
||||
$this->assertEqual($relationship['base field'], 'fid');
|
||||
$this->assertEqual($relationship['entity type'], 'file');
|
||||
// Check the backwards reference.
|
||||
$views_data = Views::viewsData()->get('file_managed');
|
||||
$relationship = $views_data['reverse_field_data_file_entity_test_mul']['relationship'];
|
||||
$this->assertEqual($relationship['id'], 'entity_reverse');
|
||||
$this->assertEqual($relationship['base'], 'entity_test_mul_property_data');
|
||||
$this->assertEqual($relationship['base field'], 'id');
|
||||
$this->assertEqual($relationship['field table'], 'entity_test_mul__field_data_file');
|
||||
$this->assertEqual($relationship['field field'], 'field_data_file_target_id');
|
||||
$this->assertEqual($relationship['field_name'], 'field_data_file');
|
||||
$this->assertEqual($relationship['entity_type'], 'entity_test_mul');
|
||||
$this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests options list argument for views.
|
||||
*
|
||||
* @see \Drupal\options\Plugin\views\argument\NumberListField.
|
||||
* @group views
|
||||
*/
|
||||
class OptionsListArgumentTest extends OptionsTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_options_list_argument_numeric', 'test_options_list_argument_string'];
|
||||
|
||||
/**
|
||||
* Tests the options field argument.
|
||||
*/
|
||||
public function testViewsTestOptionsListArgument() {
|
||||
$view = Views::getView('test_options_list_argument_numeric');
|
||||
$this->executeView($view, [1]);
|
||||
|
||||
$resultset = [
|
||||
['nid' => $this->nodes[0]->nid->value],
|
||||
['nid' => $this->nodes[1]->nid->value],
|
||||
];
|
||||
|
||||
$column_map = ['nid' => 'nid'];
|
||||
$this->assertIdenticalResultset($view, $resultset, $column_map);
|
||||
|
||||
$view = Views::getView('test_options_list_argument_string');
|
||||
$this->executeView($view, ['man', 'woman']);
|
||||
|
||||
$resultset = [
|
||||
['nid' => $this->nodes[0]->nid->value],
|
||||
['nid' => $this->nodes[1]->nid->value],
|
||||
];
|
||||
|
||||
$column_map = ['nid' => 'nid'];
|
||||
$this->assertIdenticalResultset($view, $resultset, $column_map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests options list filter for views.
|
||||
*
|
||||
* @see \Drupal\field\Plugin\views\filter\ListField.
|
||||
* @group views
|
||||
*/
|
||||
class OptionsListFilterTest extends OptionsTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_options_list_filter'];
|
||||
|
||||
/**
|
||||
* Tests options list field filter.
|
||||
*/
|
||||
public function testViewsTestOptionsListFilter() {
|
||||
$view = Views::getView('test_options_list_filter');
|
||||
$this->executeView($view);
|
||||
|
||||
$resultset = [
|
||||
['nid' => $this->nodes[0]->nid->value],
|
||||
['nid' => $this->nodes[1]->nid->value],
|
||||
];
|
||||
|
||||
$column_map = ['nid' => 'nid'];
|
||||
$this->assertIdenticalResultset($view, $resultset, $column_map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel\Views;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Base class for options views tests.
|
||||
*/
|
||||
abstract class OptionsTestBase extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['options', 'options_test_views', 'node', 'user', 'field'];
|
||||
|
||||
/**
|
||||
* Stores the nodes used for the different tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nodes = [];
|
||||
|
||||
/**
|
||||
* Stores the field values used for the different tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldValues = [];
|
||||
|
||||
/**
|
||||
* The used field names.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fieldNames;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
$this->mockStandardInstall();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['options_test_views']);
|
||||
|
||||
$settings = [];
|
||||
$settings['type'] = 'article';
|
||||
$settings['title'] = $this->randomString();
|
||||
$settings['field_test_list_string'][]['value'] = $this->fieldValues[0];
|
||||
$settings['field_test_list_integer'][]['value'] = 0;
|
||||
|
||||
$node = Node::create($settings);
|
||||
$node->save();
|
||||
|
||||
$this->nodes[] = $node;
|
||||
$node = $node->createDuplicate();
|
||||
$node->save();
|
||||
$this->nodes[] = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a workaround for the inability to use the standard profile.
|
||||
*
|
||||
* @see https://www.drupal.org/node/1708692
|
||||
*/
|
||||
protected function mockStandardInstall() {
|
||||
$this->installEntitySchema('user');
|
||||
$this->installEntitySchema('node');
|
||||
|
||||
NodeType::create(
|
||||
['type' => 'article']
|
||||
)->save();
|
||||
$this->fieldValues = [
|
||||
$this->randomMachineName(),
|
||||
$this->randomMachineName(),
|
||||
];
|
||||
|
||||
$this->fieldNames = ['field_test_list_string', 'field_test_list_integer'];
|
||||
|
||||
// Create two field entities.
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldNames[0],
|
||||
'entity_type' => 'node',
|
||||
'type' => 'list_string',
|
||||
'cardinality' => 1,
|
||||
'settings' => [
|
||||
'allowed_values' => [
|
||||
$this->fieldValues[0] => $this->fieldValues[0],
|
||||
$this->fieldValues[1] => $this->fieldValues[1],
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldNames[1],
|
||||
'entity_type' => 'node',
|
||||
'type' => 'list_integer',
|
||||
'cardinality' => 1,
|
||||
'settings' => [
|
||||
'allowed_values' => [
|
||||
$this->fieldValues[0],
|
||||
$this->fieldValues[1],
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
foreach ($this->fieldNames as $field_name) {
|
||||
FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'label' => 'Test options list field',
|
||||
'bundle' => 'article',
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\options\Kernel\Views;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Test to ensure views data is properly created for the Options module.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class ViewsDataTest extends OptionsTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['options', 'options_test', 'entity_test', 'views'];
|
||||
|
||||
/**
|
||||
* The field storage.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp();
|
||||
|
||||
$field_name = 'test_options';
|
||||
$this->fieldStorage = FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'list_string',
|
||||
'cardinality' => 1,
|
||||
'settings' => [
|
||||
'allowed_values_function' => 'options_test_dynamic_values_callback',
|
||||
],
|
||||
]);
|
||||
$this->fieldStorage->save();
|
||||
|
||||
$this->field = FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the option module's implementation of hook_field_views_data().
|
||||
*/
|
||||
public function testOptionsFieldViewsData() {
|
||||
$field_data = \Drupal::service('views.views_data')->get('entity_test__test_options');
|
||||
|
||||
// Check that the options module has properly overridden default views data.
|
||||
$test_options_field = $field_data['test_options_value'];
|
||||
$this->assertEqual($test_options_field['argument']['id'], 'string_list_field', 'Argument handler is properly set for fields with allowed value callbacks.');
|
||||
$this->assertEqual($test_options_field['filter']['id'], 'list_field', 'Filter handler is properly set for fields with allowed value callbacks.');
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue