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