diff --git a/core/lib/Drupal/Core/Field/ConfigEntityReferenceItemBase.php b/core/lib/Drupal/Core/Field/ConfigEntityReferenceItemBase.php index bbd1747..61e6a5e 100644 --- a/core/lib/Drupal/Core/Field/ConfigEntityReferenceItemBase.php +++ b/core/lib/Drupal/Core/Field/ConfigEntityReferenceItemBase.php @@ -8,80 +8,14 @@ namespace Drupal\Core\Field; use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; -use Drupal\Core\TypedData\DataDefinition; -use Drupal\field\FieldInstanceInterface; -use Drupal\field\FieldInterface; /** * A common base class for configurable entity reference fields. * - * Extends the Core 'entity_reference' entity field item with properties for - * revision ids, labels (for autocreate) and access. - * - * Required settings (below the definition's 'settings' key) are: - * - target_type: The entity type to reference. + * Extends the Core 'entity_reference' entity field item with common methods + * used in general configurable entity reference field. */ -class ConfigEntityReferenceItemBase extends EntityReferenceItem implements ConfigFieldItemInterface { - - /** - * Definitions of the contained properties. - * - * @see ConfigurableEntityReferenceItem::getPropertyDefinitions() - * - * @var array - */ - static $propertyDefinitions; - - /** - * {@inheritdoc} - */ - public function getPropertyDefinitions() { - $settings = $this->definition->getSettings(); - $target_type = $settings['target_type']; - - // Definitions vary by entity type and bundle, so key them accordingly. - $key = $target_type . ':'; - $key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : ''; - - if (!isset(static::$propertyDefinitions[$key])) { - // Call the parent to define the target_id and entity properties. - parent::getPropertyDefinitions(); - - // Only add the revision ID property if the target entity type supports - // revisions. - $target_type_info = \Drupal::entityManager()->getDefinition($target_type); - if (!empty($target_type_info['entity_keys']['revision']) && !empty($target_type_info['revision_table'])) { - static::$propertyDefinitions[$key]['revision_id'] = DataDefinition::create('integer') - ->setLabel(t('Revision ID')) - ->setConstraints(array('Range' => array('min' => 0))); - } - - static::$propertyDefinitions[$key]['label'] = DataDefinition::create('string') - ->setLabel(t('Label (auto-create)')) - ->setComputed(TRUE); - - static::$propertyDefinitions[$key]['access'] = DataDefinition::create('boolean') - ->setLabel(t('Access')) - ->setComputed(TRUE); - } - return static::$propertyDefinitions[$key]; - } - - /** - * {@inheritdoc} - * - * Copied from \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem, - * since we cannot extend it. - */ - public static function schema(FieldInterface $field) { - $definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field->type); - $module = $definition['provider']; - module_load_install($module); - $callback = "{$module}_field_schema"; - if (function_exists($callback)) { - return $callback($field); - } - } +class ConfigEntityReferenceItemBase extends EntityReferenceItem { /** * {@inheritdoc} @@ -101,75 +35,14 @@ public function isEmpty() { /** * {@inheritdoc} - * - * Copied from \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem, - * since we cannot extend it. - */ - public function settingsForm(array $form, array &$form_state, $has_data) { - if ($callback = $this->getLegacyCallback('settings_form')) { - $instance = $this->getFieldDefinition(); - if (!($instance instanceof FieldInstanceInterface)) { - throw new \UnexpectedValueException('ConfigEntityReferenceItemBase::settingsForm() called for a field whose definition is not a field instance.'); - } - // hook_field_settings_form() used to receive the $instance (not actually - // needed), and the value of field_has_data(). - return $callback($instance->getField(), $instance, $has_data); - } - return array(); - } - - /** - * {@inheritdoc} - * - * Copied from \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem, - * since we cannot extend it. */ - public function instanceSettingsForm(array $form, array &$form_state) { - if ($callback = $this->getLegacyCallback('instance_settings_form')) { - $instance = $this->getFieldDefinition(); - if (!($instance instanceof FieldInstanceInterface)) { - throw new \UnexpectedValueException('ConfigEntityReferenceItemBase::instanceSettingsForm() called for a field whose definition is not a field instance.'); - } - return $callback($instance->getField(), $instance, $form_state); - } - return array(); - } + public function preSave() { + $entity = $this->get('entity')->getValue(); + $target_id = $this->get('target_id')->getValue(); - /** - * Returns options provided via the legacy callback hook_options_list(). - * - * @todo: Convert all legacy callback implementations to methods. - * - * @see \Drupal\Core\TypedData\AllowedValuesInterface - */ - public function getSettableOptions() { - $definition = $this->getPluginDefinition(); - $callback = "{$definition['provider']}_options_list"; - if (function_exists($callback)) { - // We are at the field item level, so we need to go two levels up to get - // to the entity object. - return $callback($this->getFieldDefinition(), $this->getEntity()); - } - } - - /** - * Returns the legacy callback for a given field type "hook". - * - * Copied from \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem, - * since we cannot extend it. - * - * @param string $hook - * The name of the hook, e.g. 'settings_form', 'is_empty'. - * - * @return string|null - * The name of the legacy callback, or NULL if it does not exist. - */ - protected function getLegacyCallback($hook) { - $definition = $this->getPluginDefinition(); - $module = $definition['provider']; - $callback = "{$module}_field_{$hook}"; - if (function_exists($callback)) { - return $callback; + if (!$target_id && !empty($entity) && $entity->isNew()) { + $entity->save(); + $this->set('target_id', $entity->id()); } } diff --git a/core/lib/Drupal/Core/Field/FieldItemBase.php b/core/lib/Drupal/Core/Field/FieldItemBase.php index 147de5f..08b2f59 100644 --- a/core/lib/Drupal/Core/Field/FieldItemBase.php +++ b/core/lib/Drupal/Core/Field/FieldItemBase.php @@ -211,4 +211,11 @@ public function delete() { } */ public function deleteRevision() { } + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return 'value'; + } + } diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php index 5524cb4..2cdd0c3 100644 --- a/core/lib/Drupal/Core/Field/FieldItemInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php @@ -136,4 +136,20 @@ public function delete(); */ public function deleteRevision(); + /** + * Returns the name of the main property, if any. + * + * Some field items consist mainly of one main property, e.g. the value of a + * text field or the @code target_id @endcode of an entity reference. If the + * field item has no main property, the method returns NULL. + * + * @return string|null + * The name of the value property, or NULL if there is none. + * + * @todo: Move this to ComplexDataInterface once we improved Typed data to do + * not enforce having all methods on the data objects. + * https://drupal.org/node/2002134 + */ + public function getMainPropertyName(); + } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php index f773ffd..655f4fd 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php @@ -141,4 +141,12 @@ public function onChange($property_name) { } parent::onChange($property_name); } + + /** + * {@inheritdoc} + */ + public function getMainPropertyName() { + return 'target_id'; + } + } diff --git a/core/lib/Drupal/Core/TypedData/AllowedValuesInterface.php b/core/lib/Drupal/Core/TypedData/AllowedValuesInterface.php index 9abe52d..5c782ae 100644 --- a/core/lib/Drupal/Core/TypedData/AllowedValuesInterface.php +++ b/core/lib/Drupal/Core/TypedData/AllowedValuesInterface.php @@ -24,6 +24,11 @@ * as structured options arrays that can be used in an Options widget such as a * select box or checkboxes. * + * Note that this interface is mostly applicable for primitive data values, but + * can be used on complex data structures if a (primitive) main property is + * specified. In that case, the allowed values and options apply to the main + * property only. + * * @see \Drupal\options\Plugin\Field\FieldWidget\OptionsWidgetBase */ interface AllowedValuesInterface { diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index c31f939..f2bd59f 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -362,7 +362,7 @@ public function getConstraints(DataDefinitionInterface $definition) { $class = $type_definition['class']; } // Check if the class provides allowed values. - if (array_key_exists('Drupal\Core\TypedData\AllowedValuesInterface', class_implements($class))) { + if (is_subclass_of($class,'Drupal\Core\TypedData\AllowedValuesInterface')) { $constraints[] = $validation_manager->create('AllowedValues', array()); } diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php index 32178bf..af0e38e 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Validation\Plugin\Validation\Constraint; use Drupal\Core\TypedData\AllowedValuesInterface; +use Drupal\Core\TypedData\ComplexDataInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\ChoiceValidator; @@ -20,14 +21,32 @@ class AllowedValuesConstraintValidator extends ChoiceValidator { * {@inheritdoc} */ public function validate($value, Constraint $constraint) { - if (!isset($value)) { - return; - } - if ($this->context->getMetadata()->getTypedData() instanceof AllowedValuesInterface) { + $typed_data = $this->context->getMetadata()->getTypedData(); + + if ($typed_data instanceof AllowedValuesInterface) { $account = \Drupal::currentUser(); - $allowed_values = $this->context->getMetadata()->getTypedData()->getSettableValues($account); + $allowed_values = $typed_data->getSettableValues($account); $constraint->choices = $allowed_values; + + // If the data is complex, we have to validate its main property. + if ($typed_data instanceof ComplexDataInterface) { + $name = $typed_data->getMainPropertyName(); + if (!isset($name)) { + throw new \LogicException('Cannot validate allowed values for complex data without a main property.'); + } + $value = $typed_data->get($name)->getValue(); + } } - return parent::validate($value, $constraint); + + // The parent implementation ignores values that are not set, but makes + // sure some choices are available firstly. However, we want to support + // empty choices for undefined values, e.g. if a term reference field + // points to an empty vocabulary. + if (!isset($value)) { + return; + } + + parent::validate($value, $constraint); } + } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php index 15c625c..533610d 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/ConfigurableEntityReferenceItem.php @@ -7,6 +7,7 @@ namespace Drupal\entity_reference; +use Drupal\Core\TypedData\DataDefinition; use Drupal\field\FieldInterface; use Drupal\Core\Field\ConfigEntityReferenceItemBase; use Drupal\Core\Field\ConfigFieldItemInterface; @@ -17,12 +18,52 @@ * Replaces the Core 'entity_reference' entity field type implementation, this * supports configurable fields, auto-creation of referenced entities and more. * + * Required settings (below the definition's 'settings' key) are: + * - target_type: The entity type to reference. + * * @see entity_reference_field_info_alter(). * */ class ConfigurableEntityReferenceItem extends ConfigEntityReferenceItemBase implements ConfigFieldItemInterface { /** + * Definitions of the contained properties. + * + * @see ConfigurableEntityReferenceItem::getPropertyDefinitions() + * + * @var array + */ + static $propertyDefinitions; + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + $settings = $this->definition->getSettings(); + $target_type = $settings['target_type']; + + // Definitions vary by entity type and bundle, so key them accordingly. + $key = $target_type . ':'; + $key .= isset($settings['target_bundle']) ? $settings['target_bundle'] : ''; + + if (!isset(static::$propertyDefinitions[$key])) { + // Call the parent to define the target_id and entity properties. + parent::getPropertyDefinitions(); + + // Only add the revision ID property if the target entity type supports + // revisions. + $target_type_info = \Drupal::entityManager()->getDefinition($target_type); + if (!empty($target_type_info['entity_keys']['revision']) && !empty($target_type_info['revision_table'])) { + static::$propertyDefinitions[$key]['revision_id'] = DataDefinition::create('integer') + ->setLabel(t('Revision ID')) + ->setConstraints(array('Range' => array('min' => 0))); + } + } + + return static::$propertyDefinitions[$key]; + } + + /** * {@inheritdoc} */ public static function schema(FieldInterface $field) { @@ -68,19 +109,6 @@ public static function schema(FieldInterface $field) { /** * {@inheritdoc} */ - public function preSave() { - $entity = $this->get('entity')->getValue(); - $target_id = $this->get('target_id')->getValue(); - - if (!$target_id && !empty($entity) && $entity->isNew()) { - $entity->save(); - $this->set('target_id', $entity->id()); - } - } - - /** - * {@inheritdoc} - */ public function settingsForm(array $form, array &$form_state, $has_data) { $element['target_type'] = array( '#type' => 'select', diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php index fd942d9..dbfe4d1 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php @@ -27,7 +27,7 @@ public function prepareView(array $entities_items) { foreach ($entities_items as $items) { foreach ($items as $item) { // Force the array key to prevent duplicates. - if ($item->target_id !== 0) { + if ($item->target_id != NULL) { $tids[$item->target_id] = $item->target_id; } } @@ -48,7 +48,7 @@ public function prepareView(array $entities_items) { $item->entity = $terms[$item->target_id]; } // Terms to be created are not in $terms, but are still legitimate. - elseif ($item->target_id === 0 && isset($item->entity)) { + elseif ($item->target_id === NULL && isset($item->entity)) { // Leave the item in place. } // Otherwise, unset the instance value, since the term does not exist. diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php index 137a7e4..42f6ee8 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php @@ -7,12 +7,12 @@ namespace Drupal\taxonomy\Plugin\Field\FieldType; -use Drupal\Core\Field\Plugin\Field\FieldType\LegacyConfigFieldItemList; +use Drupal\Core\Field\ConfigFieldItemList; /** - * Represents a configurable taxonomy_term_reference entity field. + * Represents a configurable taxonomy_term_reference entity field item list. */ -class TaxonomyTermReferenceFieldItemList extends LegacyConfigFieldItemList { +class TaxonomyTermReferenceFieldItemList extends ConfigFieldItemList { /** * {@inheritdoc} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php new file mode 100644 index 0000000..fb0e537 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php @@ -0,0 +1,199 @@ +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 = $this->flattenOptions($this->getSettableOptions($account)); + return array_keys($flatten_options); + } + + /** + * {@inheritdoc} + */ + public function getSettableOptions(AccountInterface $account = NULL) { + $instance = $this->getFieldDefinition(); + $entity = $this->getParent()->getParent(); + $function = $this->getFieldSetting('options_list_callback') ? $this->getFieldSetting('options_list_callback') : array($this, 'getDefaultOptions'); + return call_user_func_array($function, array($instance, $entity)); + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions() { + $this->definition['settings']['target_type'] = 'taxonomy_term'; + return parent::getPropertyDefinitions(); + } + + /** + * {@inheritdoc} + */ + public static function schema(FieldInterface $field) { + return array( + 'columns' => array( + 'target_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + ), + ), + 'indexes' => array( + 'target_id' => array('target_id'), + ), + 'foreign keys' => array( + 'target_id' => array( + 'table' => 'taxonomy_term_data', + 'columns' => array('target_id' => 'tid'), + ), + ), + ); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, array &$form_state, $has_data) { + // Get proper values for 'allowed_values_function', which is a core setting. + $vocabularies = entity_load_multiple('taxonomy_vocabulary'); + $options = array(); + foreach ($vocabularies as $vocabulary) { + $options[$vocabulary->id()] = $vocabulary->name; + } + + $settings = $this->getFieldSettings(); + $element = array(); + $element['#tree'] = TRUE; + + foreach ($settings['allowed_values'] as $delta => $tree) { + $element['allowed_values'][$delta]['vocabulary'] = array( + '#type' => 'select', + '#title' => t('Vocabulary'), + '#default_value' => $tree['vocabulary'], + '#options' => $options, + '#required' => TRUE, + '#description' => t('The vocabulary which supplies the options for this field.'), + '#disabled' => $has_data, + ); + $element['allowed_values'][$delta]['parent'] = array( + '#type' => 'value', + '#value' => $tree['parent'], + ); + } + + return $element; + } + + /** + * {@inheritdoc} + */ + public function instanceSettingsForm(array $form, array &$form_state) { + return array(); + } + + /** + * Flattens an array of allowed values. + * + * @todo Define this function somewhere else, so we don't have to redefine it + * when other field type classes, e.g. list option, need it too. + * https://drupal.org/node/2138803 + * + * @param array $array + * A single or multidimensional array. + * + * @return array + * The flattened array. + */ + protected function flattenOptions(array $array) { + $result = array(); + array_walk_recursive($array, function($a, $b) use (&$result) { $result[$b] = $a; }); + return $result; + } + + /** + * Returns default set of valid terms for a taxonomy field. + * + * Contrib code could make use of field setting's "options_list_callback" to + * provide custom options for taxonomy term reference field. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object the field is attached to. + * + * @return array + * The array of valid terms for this field, keyed by term id. + */ + public function getDefaultOptions(FieldDefinitionInterface $field_definition, EntityInterface $entity) { + $options = array(); + foreach ($field_definition->getSetting('allowed_values') as $tree) { + if ($vocabulary = entity_load('taxonomy_vocabulary', $tree['vocabulary'])) { + if ($terms = taxonomy_get_tree($vocabulary->id(), $tree['parent'], NULL, TRUE)) { + foreach ($terms as $term) { + $options[$term->id()] = str_repeat('-', $term->depth) . $term->label(); + } + } + } + } + return $options; + } + +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php index 0b3c2ad..e8e446b 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php @@ -114,7 +114,7 @@ public function massageFormValues(array $values, array $form, array &$form_state 'vid' => $vocabulary->id(), 'name' => $value, )); - $item = array('target_id' => 0, 'entity' => $term); + $item = array('target_id' => NULL, 'entity' => $term); } $items[] = $item; } diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install index f7abc20..7b247c9 100644 --- a/core/modules/taxonomy/taxonomy.install +++ b/core/modules/taxonomy/taxonomy.install @@ -165,30 +165,6 @@ function taxonomy_schema() { } /** - * Implements hook_field_schema(). - */ -function taxonomy_field_schema($field) { - return array( - 'columns' => array( - 'target_id' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => FALSE, - ), - ), - 'indexes' => array( - 'target_id' => array('target_id'), - ), - 'foreign keys' => array( - 'target_id' => array( - 'table' => 'taxonomy_term_data', - 'columns' => array('target_id' => 'tid'), - ), - ), - ); -} - -/** * Implements hook_update_dependencies(). */ function taxonomy_update_dependencies() { diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 4bc189f..978ac62 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -7,9 +7,6 @@ use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\field\FieldInterface; -use Drupal\field\FieldInstanceInterface; use Drupal\file\FileInterface; use Drupal\node\Entity\Node; use Drupal\taxonomy\Entity\Term; @@ -801,39 +798,6 @@ function taxonomy_implode_tags($tags, $vid = NULL) { } /** - * Implements hook_field_info(). - * - * Field settings: - * - allowed_values: a list array of one or more vocabulary trees: - * - vocabulary: a vocabulary machine name. - * - parent: a term ID of a term whose children are allowed. This should be - * '0' if all terms in a vocabulary are allowed. The allowed values do not - * include the parent term. - * - */ -function taxonomy_field_info() { - return array( - 'taxonomy_term_reference' => array( - 'label' => t('Term reference'), - 'description' => t('This field stores a reference to a taxonomy term.'), - 'default_widget' => 'options_select', - 'default_formatter' => 'taxonomy_term_reference_link', - 'class' => 'Drupal\taxonomy\Type\TaxonomyTermReferenceItem', - 'settings' => array( - 'options_list_callback' => NULL, - 'allowed_values' => array( - array( - 'vocabulary' => '', - 'parent' => '0', - ), - ), - ), - 'list_class' => '\Drupal\taxonomy\Plugin\Field\FieldType\TaxonomyTermReferenceFieldItemList', - ), - ); -} - -/** * Implements hook_field_widget_info_alter(). */ function taxonomy_field_widget_info_alter(&$info) { @@ -842,105 +806,6 @@ function taxonomy_field_widget_info_alter(&$info) { } /** - * Implements hook_options_list(). - */ -function taxonomy_options_list(FieldDefinitionInterface $field_definition, EntityInterface $entity) { - $function = $field_definition->getSetting('options_list_callback') ?: 'taxonomy_allowed_values'; - return $function($field_definition, $entity); -} - -/** - * Implements hook_field_validate(). - * - * Taxonomy field settings allow for either a single vocabulary ID, multiple - * vocabulary IDs, or sub-trees of a vocabulary to be specified as allowed - * values, although only the first of these is supported via the field UI. - * Confirm that terms entered as values meet at least one of these conditions. - * - * Possible error codes: - * - 'taxonomy_term_illegal_value': The value is not part of the list of allowed values. - */ -function taxonomy_field_validate(EntityInterface $entity = NULL, FieldInterface $field, FieldInstanceInterface $instance, $langcode, $items, &$errors) { - // Build an array of existing term IDs so they can be loaded with - // entity_load_multiple('taxonomy_term'); - foreach ($items as $delta => $item) { - if (!empty($item['target_id']) && $item['target_id'] != 'autocreate') { - $tids[] = $item['target_id']; - } - } - if (!empty($tids)) { - $terms = entity_load_multiple('taxonomy_term', $tids); - - // Check each existing item to ensure it can be found in the - // allowed values for this field. - foreach ($items as $delta => $item) { - $validate = TRUE; - if (!empty($item['target_id']) && $item['target_id'] != 'autocreate') { - $validate = FALSE; - foreach ($instance->getSetting('allowed_values') as $settings) { - // If no parent is specified, check if the term is in the vocabulary. - if (isset($settings['vocabulary']) && empty($settings['parent'])) { - if ($settings['vocabulary'] == $terms[$item['target_id']]->bundle()) { - $validate = TRUE; - break; - } - } - // If a parent is specified, then to validate it must appear in the - // array returned by taxonomy_term_load_parents_all(). - elseif (!empty($settings['parent'])) { - $ancestors = taxonomy_term_load_parents_all($item['target_id']); - foreach ($ancestors as $ancestor) { - if ($ancestor->id() == $settings['parent']) { - $validate = TRUE; - break 2; - } - } - } - } - } - if (!$validate) { - $errors[$instance->getName()][$langcode][$delta][] = array( - 'error' => 'taxonomy_term_reference_illegal_value', - 'message' => t('%name: illegal value.', array('%name' => $instance->getLabel())), - ); - } - } - } -} - -/** - * Implements hook_field_is_empty(). - */ -function taxonomy_field_is_empty($item, $field_type) { - return !is_array($item) || (empty($item['target_id']) && empty($item['entity'])); -} - -/** - * Returns the set of valid terms for a taxonomy field. - * - * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition - * The field definition. - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object the field is attached to. - * - * @return - * The array of valid terms for this field, keyed by term id. - */ -function taxonomy_allowed_values(FieldDefinitionInterface $field_definition, EntityInterface $entity) { - $options = array(); - foreach ($field_definition->getSetting('allowed_values') as $tree) { - if ($vocabulary = entity_load('taxonomy_vocabulary', $tree['vocabulary'])) { - if ($terms = taxonomy_get_tree($vocabulary->id(), $tree['parent'], NULL, TRUE)) { - foreach ($terms as $term) { - $options[$term->id()] = str_repeat('-', $term->depth) . $term->label(); - } - } - } - } - return $options; -} - -/** * Title callback for term pages. * * @param \Drupal\taxonomy\Entity\Term $term @@ -967,39 +832,6 @@ function taxonomy_autocomplete_validate($element, &$form_state) { } /** - * Implements hook_field_settings_form(). - */ -function taxonomy_field_settings_form($field, $instance) { - // Get proper values for 'allowed_values_function', which is a core setting. - $vocabularies = entity_load_multiple('taxonomy_vocabulary'); - $options = array(); - foreach ($vocabularies as $vocabulary) { - $options[$vocabulary->id()] = $vocabulary->name; - } - $form['allowed_values'] = array( - '#tree' => TRUE, - ); - - foreach ($field->getSetting('allowed_values') as $delta => $tree) { - $form['allowed_values'][$delta]['vocabulary'] = array( - '#type' => 'select', - '#title' => t('Vocabulary'), - '#default_value' => $tree['vocabulary'], - '#options' => $options, - '#required' => TRUE, - '#description' => t('The vocabulary which supplies the options for this field.'), - '#disabled' => $field->hasData(), - ); - $form['allowed_values'][$delta]['parent'] = array( - '#type' => 'value', - '#value' => $tree['parent'], - ); - } - - return $form; -} - -/** * @defgroup taxonomy_index Taxonomy indexing * @{ * Functions to maintain taxonomy indexing. @@ -1018,20 +850,6 @@ function taxonomy_field_settings_form($field, $instance) { */ /** - * Implements hook_field_presave(). - * - * Create any new terms defined in a freetagging vocabulary. - */ -function taxonomy_field_presave(EntityInterface $entity, $field, $instance, $langcode, &$items) { - foreach ($items as $delta => $item) { - if (!$item['target_id'] && isset($item['target_id'])) { - $item['entity']->save(); - $items[$delta]['target_id'] = $item['entity']->id(); - } - } -} - -/** * Implements hook_node_insert(). */ function taxonomy_node_insert(EntityInterface $node) {