/** * {@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; $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.', array('%field' => $field_label)) . '</p>'; // 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. $form['settings'] = array('#weight' => -10, '#tree' => TRUE); // Create an arbitrary entity object, so that we can have an instantiated // FieldItem. $ids = (object) array('entity_type' => $form_state->get('entity_type_id'), 'bundle' => $form_state->get('bundle'), 'entity_id' => NULL); $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()); // Build the configurable field values. $cardinality = $this->entity->getCardinality(); $form['cardinality_container'] = array('#parents' => array(), '#type' => 'fieldset', '#title' => $this->t('Allowed number of values'), '#attributes' => array('class' => array('container-inline', 'fieldgroup', 'form-composite'))); $form['cardinality_container']['cardinality'] = array('#type' => 'select', '#title' => $this->t('Allowed number of values'), '#title_display' => 'invisible', '#options' => array('number' => $this->t('Limited'), FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED => $this->t('Unlimited')), '#default_value' => $cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : 'number'); $form['cardinality_container']['cardinality_number'] = array('#type' => 'number', '#default_value' => $cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED ? $cardinality : 1, '#min' => 1, '#title' => $this->t('Limit'), '#title_display' => 'invisible', '#size' => 2, '#states' => array('visible' => array(':input[name="cardinality"]' => array('value' => 'number')), 'disabled' => array(':input[name="cardinality"]' => array('value' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)))); return $form; }
/** * Forbid a field storage update from occurring. * * Any module may forbid any update for any reason. For example, the * field's storage module might forbid an update if it would change * the storage schema while data for the field exists. A field type * module might forbid an update if it would change existing data's * semantics, or if there are external dependencies on field settings * that cannot be updated. * * To forbid the update from occurring, throw a * \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException. * * @param \Drupal\field\FieldStorageConfigInterface $field_storage * The field storage as it will be post-update. * @param \Drupal\field\FieldStorageConfigInterface $prior_field_storage * The field storage as it is pre-update. * * @see entity_crud */ function hook_field_storage_config_update_forbid(\Drupal\field\FieldStorageConfigInterface $field_storage, \Drupal\field\FieldStorageConfigInterface $prior_field_storage) { if ($field_storage->module == 'options' && $field_storage->hasData()) { // Forbid any update that removes allowed values with actual data. $allowed_values = $field_storage->getSetting('allowed_values'); $prior_allowed_values = $prior_field_storage->getSetting('allowed_values'); $lost_keys = array_keys(array_diff_key($prior_allowed_values, $allowed_values)); if (_options_values_in_use($field_storage->getTargetEntityTypeId(), $field_storage->getName(), $lost_keys)) { throw new \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field_storage->getName()))); } } }
/** * Forbid a field storage update from occurring. * * Any module may forbid any update for any reason. For example, the * field's storage module might forbid an update if it would change * the storage schema while data for the field exists. A field type * module might forbid an update if it would change existing data's * semantics, or if there are external dependencies on field settings * that cannot be updated. * * To forbid the update from occurring, throw a * \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException. * * @param \Drupal\field\FieldStorageConfigInterface $field_storage * The field storage as it will be post-update. * @param \Drupal\field\FieldStorageConfigInterface $prior_field_storage * The field storage as it is pre-update. * * @see entity_crud */ function hook_field_storage_config_update_forbid(\Drupal\field\FieldStorageConfigInterface $field_storage, \Drupal\field\FieldStorageConfigInterface $prior_field_storage) { // A 'list' field stores integer keys mapped to display values. If // the new field will have fewer values, and any data exists for the // abandoned keys, the field will have no way to display them. So, // forbid such an update. if ($field_storage->hasData() && count($field_storage['settings']['allowed_values']) < count($prior_field_storage['settings']['allowed_values'])) { // Identify the keys that will be lost. $lost_keys = array_diff(array_keys($field_storage['settings']['allowed_values']), array_keys($prior_field_storage['settings']['allowed_values'])); // If any data exist for those keys, forbid the update. $query = new EntityFieldQuery(); $found = $query->fieldCondition($prior_field_storage['field_name'], 'value', $lost_keys)->range(0, 1)->execute(); if ($found) { throw new \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException("Cannot update a list field storage not to include keys with existing data"); } } }