/** * {@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()))); } } }
/** * @covers ::getType */ public function testGetType() { // Ensure that FieldConfig::getType() is not delegated to // FieldStorage. $this->entityManager->expects($this->never())->method('getFieldStorageDefinitions'); $this->fieldStorage->expects($this->never())->method('getType'); $field = new FieldConfig(array('field_name' => $this->fieldStorage->getName(), 'entity_type' => 'test_entity_type', 'bundle' => 'test_bundle', 'field_type' => 'test_field'), $this->entityTypeId); $this->assertEquals('test_field', $field->getType()); }
/** * @covers ::toArray() */ public function testToArray() { $values = array('field_name' => $this->fieldStorage->getName(), 'entity_type' => 'test_entity_type', 'bundle' => 'test_bundle'); $instance = new FieldInstanceConfig($values, $this->entityTypeId); $expected = array('id' => 'test_entity_type.test_bundle.field_test', 'uuid' => NULL, 'status' => TRUE, 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, 'field_name' => 'field_test', 'entity_type' => 'test_entity_type', 'bundle' => 'test_bundle', 'label' => '', 'description' => '', 'required' => FALSE, 'default_value' => array(), 'default_value_function' => '', 'settings' => array(), 'dependencies' => array(), 'field_type' => 'test_field'); $this->entityManager->expects($this->any())->method('getDefinition')->with($this->entityTypeId)->will($this->returnValue($this->entityType)); $this->entityType->expects($this->once())->method('getKey')->with('id')->will($this->returnValue('id')); $this->typedConfigManager->expects($this->once())->method('getDefinition')->will($this->returnValue(array('mapping' => array_fill_keys(array_keys($expected), '')))); $export = $instance->toArray(); $this->assertEquals($expected, $export); }
/** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { parent::validateForm($form, $form_state); $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($this->entity->getTargetEntityTypeId()); // Validate field cardinality. if ($form_state->getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) { $form_state->setErrorByName('cardinality_number', $this->t('Number of values is required.')); } 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) { $form_state->setErrorByName('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])); } } }
/** * Alter the Views data on a per field basis. * * The field module's implementation of hook_views_data_alter() invokes this for * each field storage, in the module that defines the field type. It is not * invoked in other modules. * * Unlike hook_field_views_data_alter(), this operates on the whole of the views * data. This allows a field type to add data that concerns its fields in * other tables, which would not yet be defined at the point when * hook_field_views_data() and hook_field_views_data_alter() are invoked. For * example, entityreference adds reverse relationships on the tables for the * entities which are referenced by entityreference fields. * * (Note: this is weirdly named so as not to conflict with * hook_field_views_data_alter().) * * @param array $data * The views data. * @param \Drupal\field\FieldStorageConfigInterface $field * The field storage config entity. * * @see hook_field_views_data() * @see hook_field_views_data_alter() * @see field_views_data_alter() */ function hook_field_views_data_views_data_alter(array &$data, \Drupal\field\FieldStorageConfigInterface $field) { $field_name = $field->getName(); $data_key = 'field_data_' . $field_name; $entity_type_id = $field->entity_type; $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id); $pseudo_field_name = 'reverse_' . $field_name . '_' . $entity_type_id; list($label) = field_views_field_label($entity_type_id, $field_name); // Views data for this field is in $data[$data_key]. $data[$data_key][$pseudo_field_name]['relationship'] = array('title' => t('@entity using @field', array('@entity' => $entity_type->getLabel(), '@field' => $label)), 'help' => t('Relate each @entity with a @field set to the term.', array('@entity' => $entity_type->getLabel(), '@field' => $label)), 'id' => 'entity_reverse', 'field_name' => $field_name, 'entity_type' => $entity_type_id, 'field table' => ContentEntityDatabaseStorage::_fieldTableName($field), 'field field' => $field_name . '_target_id', 'base' => $entity_type->getBaseTable(), 'base field' => $entity_type->getKey('id'), 'label' => t('!field_name', array('!field_name' => $field_name)), 'join_extra' => array(0 => array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE))); }
/** * {@inheritdoc} */ public function fieldGetPermissionType(FieldStorageConfigInterface $field) { $config = \Drupal::service('config.factory')->getEditable('field_permissions.field.settings'); $field_settings_perm = $config->get('permission_type_' . $field->getName()); return $field_settings_perm ? $field_settings_perm : FIELD_PERMISSIONS_PUBLIC; }