Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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']));
}
}

View file

@ -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);
}
}