Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
6.67% |
1 / 15 |
CRAP | |
9.68% |
9 / 93 |
FieldConfig | |
0.00% |
0 / 1 |
|
6.67% |
1 / 15 |
1341.83 | |
9.68% |
9 / 93 |
__construct | |
0.00% |
0 / 1 |
14.79 | |
37.50% |
6 / 16 |
|||
postCreate | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
preSave | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 16 |
|||
calculateDependencies | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
preDelete | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 11 |
|||
postDelete | |
0.00% |
0 / 1 |
90 | |
0.00% |
0 / 15 |
|||
linkTemplates | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 8 |
|||
urlRouteParameters | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
isDeleted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getFieldStorageDefinition | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 8 |
|||
isDisplayConfigurable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getDisplayOptions | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isReadOnly | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isComputed | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
loadByName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\field\Entity\FieldConfig. | |
*/ | |
namespace Drupal\field\Entity; | |
use Drupal\Core\Entity\EntityStorageInterface; | |
use Drupal\Core\Field\FieldConfigBase; | |
use Drupal\Core\Field\FieldException; | |
use Drupal\field\FieldStorageConfigInterface; | |
use Drupal\field\FieldConfigInterface; | |
/** | |
* Defines the Field entity. | |
* | |
* @ConfigEntityType( | |
* id = "field_config", | |
* label = @Translation("Field"), | |
* handlers = { | |
* "access" = "Drupal\field\FieldConfigAccessControlHandler", | |
* "storage" = "Drupal\field\FieldConfigStorage" | |
* }, | |
* config_prefix = "field", | |
* entity_keys = { | |
* "id" = "id", | |
* "label" = "label" | |
* }, | |
* config_export = { | |
* "id", | |
* "field_name", | |
* "entity_type", | |
* "bundle", | |
* "label", | |
* "description", | |
* "required", | |
* "translatable", | |
* "default_value", | |
* "default_value_callback", | |
* "settings", | |
* "field_type", | |
* } | |
* ) | |
*/ | |
class FieldConfig extends FieldConfigBase implements FieldConfigInterface { | |
/** | |
* Flag indicating whether the field is deleted. | |
* | |
* The delete() method marks the field as "deleted" and removes the | |
* corresponding entry from the config storage, but keeps its definition in | |
* the state storage while field data is purged by a separate | |
* garbage-collection process. | |
* | |
* Deleted fields stay out of the regular entity lifecycle (notably, their | |
* values are not populated in loaded entities, and are not saved back). | |
* | |
* @var bool | |
*/ | |
protected $deleted = FALSE; | |
/** | |
* The associated FieldStorageConfig entity. | |
* | |
* @var \Drupal\field\Entity\FieldStorageConfig | |
*/ | |
protected $fieldStorage; | |
/** | |
* Constructs a FieldConfig object. | |
* | |
* In most cases, Field entities are created via | |
* entity_create('field_config', $values), where $values is the same | |
* parameter as in this constructor. | |
* | |
* @param array $values | |
* An array of field properties, keyed by property name. The | |
* storage associated with the field can be specified either with: | |
* - field_storage: the FieldStorageConfigInterface object, | |
* or by referring to an existing field storage in the current configuration | |
* with: | |
* - field_name: The field name. | |
* - entity_type: The entity type. | |
* Additionally, a 'bundle' property is required to indicate the entity | |
* bundle to which the field is attached to. Other array elements will be | |
* used to set the corresponding properties on the class; see the class | |
* property documentation for details. | |
* | |
* @see entity_create() | |
*/ | |
public function __construct(array $values, $entity_type = 'field_config') { | |
// Allow either an injected FieldStorageConfig object, or a field_name and | |
// entity_type. | |
if (isset($values['field_storage'])) { | |
if (!$values['field_storage'] instanceof FieldStorageConfigInterface) { | |
throw new FieldException('Attempt to create a configurable field for a non-configurable field storage.'); | |
} | |
$field_storage = $values['field_storage']; | |
$values['field_name'] = $field_storage->getName(); | |
$values['entity_type'] = $field_storage->getTargetEntityTypeId(); | |
// The internal property is fieldStorage, not field_storage. | |
unset($values['field_storage']); | |
$values['fieldStorage'] = $field_storage; | |
} | |
else { | |
if (empty($values['field_name'])) { | |
throw new FieldException('Attempt to create a field without a field_name.'); | |
} | |
if (empty($values['entity_type'])) { | |
throw new FieldException("Attempt to create a field '{$values['field_name']}' without an entity_type."); | |
} | |
} | |
// 'bundle' is required in either case. | |
if (empty($values['bundle'])) { | |
throw new FieldException("Attempt to create a field '{$values['field_name']}' without a bundle."); | |
} | |
parent::__construct($values, $entity_type); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function postCreate(EntityStorageInterface $storage) { | |
parent::postCreate($storage); | |
// Validate that we have a valid storage for this field. This throws an | |
// exception if the storage is invalid. | |
$this->getFieldStorageDefinition(); | |
// 'Label' defaults to the field name (mostly useful for fields created in | |
// tests). | |
if (empty($this->label)) { | |
$this->label = $this->getName(); | |
} | |
} | |
/** | |
* Overrides \Drupal\Core\Entity\Entity::preSave(). | |
* | |
* @throws \Drupal\Core\Field\FieldException | |
* If the field definition is invalid. | |
* @throws \Drupal\Core\Entity\EntityStorageException | |
* In case of failures at the configuration storage level. | |
*/ | |
public function preSave(EntityStorageInterface $storage) { | |
$entity_manager = \Drupal::entityManager(); | |
$field_type_manager = \Drupal::service('plugin.manager.field.field_type'); | |
$storage_definition = $this->getFieldStorageDefinition(); | |
// Filter out unknown settings and make sure all settings are present, so | |
// that a complete field definition is passed to the various hooks and | |
// written to config. | |
$default_settings = $field_type_manager->getDefaultFieldSettings($storage_definition->getType()); | |
$this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings; | |
if ($this->isNew()) { | |
// Notify the entity storage. | |
$entity_manager->onFieldDefinitionCreate($this); | |
} | |
else { | |
// Some updates are always disallowed. | |
if ($this->entity_type != $this->original->entity_type) { | |
throw new FieldException("Cannot change an existing field's entity_type."); | |
} | |
if ($this->bundle != $this->original->bundle) { | |
throw new FieldException("Cannot change an existing field's bundle."); | |
} | |
if ($storage_definition->uuid() != $this->original->getFieldStorageDefinition()->uuid()) { | |
throw new FieldException("Cannot change an existing field's storage."); | |
} | |
// Notify the entity storage. | |
$entity_manager->onFieldDefinitionUpdate($this, $this->original); | |
} | |
parent::preSave($storage); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function calculateDependencies() { | |
parent::calculateDependencies(); | |
// Mark the field_storage_config as a dependency. | |
$this->addDependency('config', $this->getFieldStorageDefinition()->getConfigDependencyName()); | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function preDelete(EntityStorageInterface $storage, array $fields) { | |
$state = \Drupal::state(); | |
parent::preDelete($storage, $fields); | |
// Keep the field definitions in the state storage so we can use them | |
// later during field_purge_batch(). | |
$deleted_fields = $state->get('field.field.deleted') ?: array(); | |
foreach ($fields as $field) { | |
if (!$field->deleted) { | |
$config = $field->toArray(); | |
$config['deleted'] = TRUE; | |
$config['field_storage_uuid'] = $field->getFieldStorageDefinition()->uuid(); | |
$deleted_fields[$field->uuid()] = $config; | |
} | |
} | |
$state->set('field.field.deleted', $deleted_fields); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function postDelete(EntityStorageInterface $storage, array $fields) { | |
// Clear the cache upfront, to refresh the results of getBundles(). | |
\Drupal::entityManager()->clearCachedFieldDefinitions(); | |
// Notify the entity storage. | |
foreach ($fields as $field) { | |
if (!$field->deleted) { | |
\Drupal::entityManager()->onFieldDefinitionDelete($field); | |
} | |
} | |
// If this is part of a configuration synchronization then the following | |
// configuration updates are not necessary. | |
$entity = reset($fields); | |
if ($entity->isSyncing()) { | |
return; | |
} | |
// Delete the associated field storages if they are not used anymore and are | |
// not persistent. | |
$storages_to_delete = array(); | |
foreach ($fields as $field) { | |
$storage_definition = $field->getFieldStorageDefinition(); | |
if (!$field->deleted && !$field->isUninstalling() && $storage_definition->isDeletable()) { | |
// Key by field UUID to avoid deleting the same storage twice. | |
$storages_to_delete[$storage_definition->uuid()] = $storage_definition; | |
} | |
} | |
if ($storages_to_delete) { | |
\Drupal::entityManager()->getStorage('field_storage_config')->delete($storages_to_delete); | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function linkTemplates() { | |
$link_templates = parent::linkTemplates(); | |
if (\Drupal::moduleHandler()->moduleExists('field_ui')) { | |
$link_templates["{$this->entity_type}-field-edit-form"] = 'entity.field_config.' . $this->entity_type . '_field_edit_form'; | |
$link_templates["{$this->entity_type}-storage-edit-form"] = 'entity.field_config.' . $this->entity_type . '_storage_edit_form'; | |
$link_templates["{$this->entity_type}-field-delete-form"] = 'entity.field_config.' . $this->entity_type . '_field_delete_form'; | |
if (isset($link_templates['config-translation-overview'])) { | |
$link_templates["config-translation-overview.{$this->entity_type}"] = "entity.field_config.config_translation_overview.{$this->entity_type}"; | |
} | |
} | |
return $link_templates; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function urlRouteParameters($rel) { | |
$parameters = parent::urlRouteParameters($rel); | |
$entity_type = \Drupal::entityManager()->getDefinition($this->entity_type); | |
$bundle_parameter_key = $entity_type->getBundleEntityType() ?: 'bundle'; | |
$parameters[$bundle_parameter_key] = $this->bundle; | |
return $parameters; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isDeleted() { | |
return $this->deleted; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getFieldStorageDefinition() { | |
if (!$this->fieldStorage) { | |
$fields = $this->entityManager()->getFieldStorageDefinitions($this->entity_type); | |
if (!isset($fields[$this->field_name])) { | |
throw new FieldException("Attempt to create a field {$this->field_name} that does not exist on entity type {$this->entity_type}."); | |
} | |
if (!$fields[$this->field_name] instanceof FieldStorageConfigInterface) { | |
throw new FieldException("Attempt to create a configurable field of non-configurable field storage {$this->field_name}."); | |
} | |
$this->fieldStorage = $fields[$this->field_name]; | |
} | |
return $this->fieldStorage; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isDisplayConfigurable($context) { | |
return TRUE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getDisplayOptions($display_context) { | |
// Hide configurable fields by default. | |
return array('type' => 'hidden'); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isReadOnly() { | |
return FALSE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isComputed() { | |
return FALSE; | |
} | |
/** | |
* Loads a field config entity based on the entity type and field name. | |
* | |
* @param string $entity_type_id | |
* ID of the entity type. | |
* @param string $bundle | |
* Bundle name. | |
* @param string $field_name | |
* Name of the field. | |
* | |
* @return static | |
* The field config entity if one exists for the provided field | |
* name, otherwise NULL. | |
*/ | |
public static function loadByName($entity_type_id, $bundle, $field_name) { | |
return \Drupal::entityManager()->getStorage('field_config')->load($entity_type_id . '.' . $bundle . '.' . $field_name); | |
} | |
} |