Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / field_ui / src / Form / FieldStorageConfigEditForm.php
1 <?php
2
3 namespace Drupal\field_ui\Form;
4
5 use Drupal\Core\Entity\EntityForm;
6 use Drupal\Core\Field\FieldStorageDefinitionInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Routing\RouteMatchInterface;
9 use Drupal\field\Entity\FieldConfig;
10 use Drupal\field_ui\FieldUI;
11 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
12
13 /**
14  * Provides a form for the "field storage" edit page.
15  */
16 class FieldStorageConfigEditForm extends EntityForm {
17
18   /**
19    * The entity being used by this form.
20    *
21    * @var \Drupal\field\FieldStorageConfigInterface
22    */
23   protected $entity;
24
25   /**
26    * {@inheritdoc}
27    */
28   public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
29     // The URL of this entity form contains only the ID of the field_config
30     // but we are actually editing a field_storage_config entity.
31     $field_config = FieldConfig::load($route_match->getRawParameter('field_config'));
32     if (!$field_config) {
33       throw new NotFoundHttpException();
34     }
35
36     return $field_config->getFieldStorageDefinition();
37   }
38
39   /**
40    * {@inheritdoc}
41    *
42    * @param string $field_config
43    *   The ID of the field config whose field storage config is being edited.
44    */
45   public function buildForm(array $form, FormStateInterface $form_state, $field_config = NULL) {
46     if ($field_config) {
47       $field = FieldConfig::load($field_config);
48       $form_state->set('field_config', $field);
49
50       $form_state->set('entity_type_id', $field->getTargetEntityTypeId());
51       $form_state->set('bundle', $field->getTargetBundle());
52     }
53
54     return parent::buildForm($form, $form_state);
55   }
56
57   /**
58    * {@inheritdoc}
59    */
60   public function form(array $form, FormStateInterface $form_state) {
61     $form = parent::form($form, $form_state);
62
63     $field_label = $form_state->get('field_config')->label();
64     $form['#title'] = $field_label;
65     $form['#prefix'] = '<p>' . $this->t('These settings apply to the %field field everywhere it is used. These settings impact the way that data is stored in the database and cannot be changed once data has been created.', ['%field' => $field_label]) . '</p>';
66
67     // See if data already exists for this field.
68     // If so, prevent changes to the field settings.
69     if ($this->entity->hasData()) {
70       $form['#prefix'] = '<div class="messages messages--error">' . $this->t('There is data for this field in the database. The field settings can no longer be changed.') . '</div>' . $form['#prefix'];
71     }
72
73     // Add settings provided by the field module. The field module is
74     // responsible for not returning settings that cannot be changed if
75     // the field already has data.
76     $form['settings'] = [
77       '#weight' => -10,
78       '#tree' => TRUE,
79     ];
80     // Create an arbitrary entity object, so that we can have an instantiated
81     // FieldItem.
82     $ids = (object) [
83       'entity_type' => $form_state->get('entity_type_id'),
84       'bundle' => $form_state->get('bundle'),
85       'entity_id' => NULL
86     ];
87     $entity = _field_create_entity_from_ids($ids);
88     $items = $entity->get($this->entity->getName());
89     $item = $items->first() ?: $items->appendItem();
90     $form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData());
91
92     // Add the cardinality sub-form.
93     $form['cardinality_container'] = $this->getCardinalityForm();
94
95     return $form;
96   }
97
98   /**
99    * Builds the cardinality form.
100    *
101    * @return array
102    *   The cardinality form render array.
103    */
104   protected function getCardinalityForm() {
105     $form = [
106       // Reset #parents so the additional container does not appear.
107       '#parents' => [],
108       '#type' => 'fieldset',
109       '#title' => $this->t('Allowed number of values'),
110       '#attributes' => [
111         'class' => [
112           'container-inline',
113           'fieldgroup',
114           'form-composite',
115         ],
116       ],
117     ];
118
119     if ($enforced_cardinality = $this->getEnforcedCardinality()) {
120       if ($enforced_cardinality === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
121         $markup = $this->t("This field cardinality is set to unlimited and cannot be configured.");
122       }
123       else {
124         $markup = $this->t("This field cardinality is set to @cardinality and cannot be configured.", ['@cardinality' => $enforced_cardinality]);
125       }
126       $form['cardinality'] = ['#markup' => $markup];
127     }
128     else {
129       $form['#element_validate'][] = '::validateCardinality';
130       $cardinality = $this->entity->getCardinality();
131       $form['cardinality'] = [
132         '#type' => 'select',
133         '#title' => $this->t('Allowed number of values'),
134         '#title_display' => 'invisible',
135         '#options' => [
136           'number' => $this->t('Limited'),
137           FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED => $this->t('Unlimited'),
138         ],
139         '#default_value' => ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : 'number',
140       ];
141       $form['cardinality_number'] = [
142         '#type' => 'number',
143         '#default_value' => $cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED ? $cardinality : 1,
144         '#min' => 1,
145         '#title' => $this->t('Limit'),
146         '#title_display' => 'invisible',
147         '#size' => 2,
148         '#states' => [
149           'visible' => [
150             ':input[name="cardinality"]' => ['value' => 'number'],
151           ],
152           'disabled' => [
153             ':input[name="cardinality"]' => ['value' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED],
154           ],
155         ],
156       ];
157     }
158
159     return $form;
160   }
161
162   /**
163    * {@inheritdoc}
164    */
165   protected function actions(array $form, FormStateInterface $form_state) {
166     $elements = parent::actions($form, $form_state);
167     $elements['submit']['#value'] = $this->t('Save field settings');
168
169     return $elements;
170   }
171
172   /**
173    * Validates the cardinality.
174    *
175    * @param array $element
176    *   The cardinality form render array.
177    * @param \Drupal\Core\Form\FormStateInterface $form_state
178    *   The form state.
179    */
180   public function validateCardinality(array &$element, FormStateInterface $form_state) {
181     $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($this->entity->getTargetEntityTypeId());
182
183     // Validate field cardinality.
184     if ($form_state->getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) {
185       $form_state->setError($element['cardinality_number'], $this->t('Number of values is required.'));
186     }
187     // If a specific cardinality is used, validate that there are no entities
188     // with a higher delta.
189     elseif (!$this->entity->isNew() && isset($field_storage_definitions[$this->entity->getName()]) && $form_state->getValue('cardinality') != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
190
191       // Get a count of entities that have a value in a delta higher than the
192       // one selected. Deltas start with 0, so the selected value does not
193       // need to be incremented.
194       $entities_with_higher_delta = \Drupal::entityQuery($this->entity->getTargetEntityTypeId())
195         ->condition($this->entity->getName() . '.%delta', $form_state->getValue('cardinality'))
196         ->count()
197         ->execute();
198       if ($entities_with_higher_delta) {
199         $form_state->setError($element['cardinality_number'], $this->formatPlural($entities_with_higher_delta, 'There is @count entity with @delta or more values in this field.', 'There are @count entities with @delta or more values in this field.', ['@delta' => $form_state->getValue('cardinality') + 1]));
200       }
201     }
202   }
203
204   /**
205    * {@inheritdoc}
206    */
207   public function buildEntity(array $form, FormStateInterface $form_state) {
208     // Save field cardinality.
209     if (!$this->getEnforcedCardinality() && $form_state->getValue('cardinality') === 'number' && $form_state->getValue('cardinality_number')) {
210       $form_state->setValue('cardinality', $form_state->getValue('cardinality_number'));
211     }
212
213     return parent::buildEntity($form, $form_state);
214   }
215
216   /**
217    * {@inheritdoc}
218    */
219   public function save(array $form, FormStateInterface $form_state) {
220     $field_label = $form_state->get('field_config')->label();
221     try {
222       $this->entity->save();
223       drupal_set_message($this->t('Updated field %label field settings.', ['%label' => $field_label]));
224       $request = $this->getRequest();
225       if (($destinations = $request->query->get('destinations')) && $next_destination = FieldUI::getNextDestination($destinations)) {
226         $request->query->remove('destinations');
227         $form_state->setRedirectUrl($next_destination);
228       }
229       else {
230         $form_state->setRedirectUrl(FieldUI::getOverviewRouteInfo($form_state->get('entity_type_id'), $form_state->get('bundle')));
231       }
232     }
233     catch (\Exception $e) {
234       drupal_set_message($this->t('Attempt to update field %label failed: %message.', ['%label' => $field_label, '%message' => $e->getMessage()]), 'error');
235     }
236   }
237
238   /**
239    * Returns the cardinality enforced by the field type.
240    *
241    * Some field types choose to enforce a fixed cardinality. This method
242    * returns that cardinality or NULL if no cardinality has been enforced.
243    *
244    * @return int|null
245    */
246   protected function getEnforcedCardinality() {
247     /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
248     $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
249     $definition = $field_type_manager->getDefinition($this->entity->getType());
250     return isset($definition['cardinality']) ? $definition['cardinality'] : NULL;
251   }
252
253 }