FieldStorageConfigEditForm.php 9.52 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php

namespace Drupal\field_ui\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\Entity\FieldConfig;
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 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 */
class FieldStorageConfigEditForm extends EntityForm {

  /**
   * The entity being used by this form.
   *
   * @var \Drupal\field\FieldStorageConfigInterface
   */
  protected $entity;

  /**
   * {@inheritdoc}
   */
  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
    // The URL of this entity form contains only the ID of the field_config
    // but we are actually editing a field_storage_config entity.
    $field_config = FieldConfig::load($route_match->getRawParameter('field_config'));
34 35 36
    if (!$field_config) {
      throw new NotFoundHttpException();
    }
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

    return $field_config->getFieldStorageDefinition();
  }

  /**
   * {@inheritdoc}
   *
   * @param string $field_config
   *   The ID of the field config whose field storage config is being edited.
   */
  public function buildForm(array $form, FormStateInterface $form_state, $field_config = NULL) {
    if ($field_config) {
      $field = FieldConfig::load($field_config);
      $form_state->set('field_config', $field);

      $form_state->set('entity_type_id', $field->getTargetEntityTypeId());
      $form_state->set('bundle', $field->getTargetBundle());
    }

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);

    $field_label = $form_state->get('field_config')->label();
    $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 70 71 72 73 74 75 76 77

    // See if data already exists for this field.
    // If so, prevent changes to the field settings.
    if ($this->entity->hasData()) {
      $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'];
    }

    // Add settings provided by the field module. The field module is
    // responsible for not returning settings that cannot be changed if
    // the field already has data.
78
    $form['settings'] = [
79 80
      '#weight' => -10,
      '#tree' => TRUE,
81
    ];
82 83
    // Create an arbitrary entity object, so that we can have an instantiated
    // FieldItem.
84
    $ids = (object) [
85 86 87
      'entity_type' => $form_state->get('entity_type_id'),
      'bundle' => $form_state->get('bundle'),
      'entity_id' => NULL
88
    ];
89 90 91 92 93
    $entity = _field_create_entity_from_ids($ids);
    $items = $entity->get($this->entity->getName());
    $item = $items->first() ?: $items->appendItem();
    $form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData());

94 95 96 97 98 99 100 101 102 103 104 105 106 107
    // Add the cardinality sub-form.
    $form['cardinality_container'] = $this->getCardinalityForm();

    return $form;
  }

  /**
   * Builds the cardinality form.
   *
   * @return array
   *   The cardinality form render array.
   */
  protected function getCardinalityForm() {
    $form = [
108
      // Reset #parents so the additional container does not appear.
109
      '#parents' => [],
110 111
      '#type' => 'fieldset',
      '#title' => $this->t('Allowed number of values'),
112 113 114 115 116 117 118
      '#attributes' => [
        'class' => [
          'container-inline',
          'fieldgroup',
          'form-composite',
        ],
      ],
119
    ];
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

    if ($enforced_cardinality = $this->getEnforcedCardinality()) {
      if ($enforced_cardinality === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
        $markup = $this->t("This field cardinality is set to unlimited and cannot be configured.");
      }
      else {
        $markup = $this->t("This field cardinality is set to @cardinality and cannot be configured.", ['@cardinality' => $enforced_cardinality]);
      }
      $form['cardinality'] = ['#markup' => $markup];
    }
    else {
      $form['#element_validate'][] = '::validateCardinality';
      $cardinality = $this->entity->getCardinality();
      $form['cardinality'] = [
        '#type' => 'select',
        '#title' => $this->t('Allowed number of values'),
        '#title_display' => 'invisible',
        '#options' => [
          'number' => $this->t('Limited'),
          FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED => $this->t('Unlimited'),
140
        ],
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        '#default_value' => ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : 'number',
      ];
      $form['cardinality_number'] = [
        '#type' => 'number',
        '#default_value' => $cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED ? $cardinality : 1,
        '#min' => 1,
        '#title' => $this->t('Limit'),
        '#title_display' => 'invisible',
        '#size' => 2,
        '#states' => [
          'visible' => [
            ':input[name="cardinality"]' => ['value' => 'number'],
          ],
          'disabled' => [
            ':input[name="cardinality"]' => ['value' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED],
          ],
157
        ],
158 159
      ];
    }
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    $elements = parent::actions($form, $form_state);
    $elements['submit']['#value'] = $this->t('Save field settings');

    return $elements;
  }

  /**
175 176 177 178 179 180
   * Validates the cardinality.
   *
   * @param array $element
   *   The cardinality form render array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
181
   */
182
  public function validateCardinality(array &$element, FormStateInterface $form_state) {
183 184
    $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($this->entity->getTargetEntityTypeId());

185 186
    // Validate field cardinality.
    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 190 191 192 193 194 195 196 197 198 199 200
    // If a specific cardinality is used, validate that there are no entities
    // with a higher delta.
    elseif (!$this->entity->isNew() && isset($field_storage_definitions[$this->entity->getName()]) && $form_state->getValue('cardinality') != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {

      // Get a count of entities that have a value in a delta higher than the
      // one selected. Deltas start with 0, so the selected value does not
      // need to be incremented.
      $entities_with_higher_delta = \Drupal::entityQuery($this->entity->getTargetEntityTypeId())
        ->condition($this->entity->getName() . '.%delta', $form_state->getValue('cardinality'))
        ->count()
        ->execute();
      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 208 209 210
  }

  /**
   * {@inheritdoc}
   */
  public function buildEntity(array $form, FormStateInterface $form_state) {
    // Save field cardinality.
211
    if (!$this->getEnforcedCardinality() && $form_state->getValue('cardinality') === 'number' && $form_state->getValue('cardinality_number')) {
212 213 214 215 216 217 218 219 220 221 222 223 224
      $form_state->setValue('cardinality', $form_state->getValue('cardinality_number'));
    }

    return parent::buildEntity($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    $field_label = $form_state->get('field_config')->label();
    try {
      $this->entity->save();
225
      $this->messenger()->addStatus($this->t('Updated field %label field settings.', ['%label' => $field_label]));
226 227 228 229 230 231 232 233 234 235
      $request = $this->getRequest();
      if (($destinations = $request->query->get('destinations')) && $next_destination = FieldUI::getNextDestination($destinations)) {
        $request->query->remove('destinations');
        $form_state->setRedirectUrl($next_destination);
      }
      else {
        $form_state->setRedirectUrl(FieldUI::getOverviewRouteInfo($form_state->get('entity_type_id'), $form_state->get('bundle')));
      }
    }
    catch (\Exception $e) {
236
      $this->messenger()->addStatus($this->t('Attempt to update field %label failed: %message.', ['%label' => $field_label, '%message' => $e->getMessage()]));
237 238 239
    }
  }

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
  /**
   * Returns the cardinality enforced by the field type.
   *
   * Some field types choose to enforce a fixed cardinality. This method
   * returns that cardinality or NULL if no cardinality has been enforced.
   *
   * @return int|null
   */
  protected function getEnforcedCardinality() {
    /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
    $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
    $definition = $field_type_manager->getDefinition($this->entity->getType());
    return isset($definition['cardinality']) ? $definition['cardinality'] : NULL;
  }

255
}