1<?php
2
3namespace Drupal\Core\Field\Plugin\Field\FieldType;
4
5use Drupal\Core\Field\FieldDefinitionInterface;
6use Drupal\Core\Field\FieldStorageDefinitionInterface;
7use Drupal\Core\Field\FieldItemBase;
8use Drupal\Core\Language\LanguageInterface;
9use Drupal\Core\Session\AccountInterface;
10use Drupal\Core\TypedData\DataDefinition;
11use Drupal\Core\TypedData\DataReferenceDefinition;
12use Drupal\Core\TypedData\OptionsProviderInterface;
13
14/**
15 * Defines the 'language' entity field item.
16 *
17 * @FieldType(
18 *   id = "language",
19 *   label = @Translation("Language"),
20 *   description = @Translation("An entity field referencing a language."),
21 *   default_widget = "language_select",
22 *   default_formatter = "language",
23 *   no_ui = TRUE,
24 *   constraints = {
25 *     "ComplexData" = {
26 *       "value" = {
27 *         "Length" = {"max" = 12}
28 *       }
29 *     }
30 *   }
31 * )
32 */
33class LanguageItem extends FieldItemBase implements OptionsProviderInterface {
34
35  /**
36   * {@inheritdoc}
37   */
38  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
39    $properties['value'] = DataDefinition::create('string')
40      ->setLabel(t('Language code'))
41      ->setRequired(TRUE);
42
43    $properties['language'] = DataReferenceDefinition::create('language')
44      ->setLabel(t('Language object'))
45      ->setDescription(t('The referenced language'))
46      // The language object is retrieved via the language code.
47      ->setComputed(TRUE)
48      ->setReadOnly(FALSE);
49
50    return $properties;
51  }
52
53  /**
54   * {@inheritdoc}
55   */
56  public static function schema(FieldStorageDefinitionInterface $field_definition) {
57    return [
58      'columns' => [
59        'value' => [
60          'type' => 'varchar_ascii',
61          'length' => 12,
62        ],
63      ],
64    ];
65  }
66
67  /**
68   * {@inheritdoc}
69   */
70  public function setValue($values, $notify = TRUE) {
71    // Treat the values as property value of the language property, if no array
72    // is given as this handles language codes and objects.
73    if (isset($values) && !is_array($values)) {
74      $this->set('language', $values, $notify);
75    }
76    else {
77      // Make sure that the 'language' property gets set as 'value'.
78      if (isset($values['value']) && !isset($values['language'])) {
79        $values['language'] = $values['value'];
80      }
81      parent::setValue($values, $notify);
82    }
83  }
84
85  /**
86   * {@inheritdoc}
87   */
88  public function applyDefaultValue($notify = TRUE) {
89    // Default to the site's default language. When language module is enabled,
90    // this behavior is configurable, see language_field_info_alter().
91    $this->setValue(['value' => \Drupal::languageManager()->getDefaultLanguage()->getId()], $notify);
92    return $this;
93  }
94
95  /**
96   * {@inheritdoc}
97   */
98  public function onChange($property_name, $notify = TRUE) {
99    // Make sure that the value and the language property stay in sync.
100    if ($property_name == 'value') {
101      $this->writePropertyValue('language', $this->value);
102    }
103    elseif ($property_name == 'language') {
104      $this->writePropertyValue('value', $this->get('language')->getTargetIdentifier());
105    }
106    parent::onChange($property_name, $notify);
107  }
108
109  /**
110   * {@inheritdoc}
111   */
112  public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
113    // Defer to the callback in the item definition as it can be overridden.
114    $constraint = $field_definition->getItemDefinition()->getConstraint('ComplexData');
115    if (isset($constraint['value']['AllowedValues']['callback'])) {
116      $languages = call_user_func($constraint['value']['AllowedValues']['callback']);
117    }
118    else {
119      $languages = array_keys(\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_ALL));
120    }
121    $values['value'] = $languages[array_rand($languages)];
122    return $values;
123  }
124
125  /**
126   * {@inheritdoc}
127   */
128  public function getPossibleValues(AccountInterface $account = NULL) {
129    return array_keys(\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_ALL));
130  }
131
132  /**
133   * {@inheritdoc}
134   */
135  public function getPossibleOptions(AccountInterface $account = NULL) {
136    $languages = \Drupal::languageManager()->getLanguages(LanguageInterface::STATE_ALL);
137    return array_map(function (LanguageInterface $language) {
138      return $language->getName();
139    }, $languages);
140  }
141
142  /**
143   * {@inheritdoc}
144   */
145  public function getSettableValues(AccountInterface $account = NULL) {
146    return $this->getPossibleValues($account);
147  }
148
149  /**
150   * {@inheritdoc}
151   */
152  public function getSettableOptions(AccountInterface $account = NULL) {
153    return $this->getPossibleValues($account);
154  }
155
156}
157