Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
2.00% |
1 / 50 |
CRAP | |
4.49% |
7 / 156 |
FieldStorageConfig | |
0.00% |
0 / 1 |
|
2.00% |
1 / 50 |
5656.54 | |
4.49% |
7 / 156 |
__construct | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 10 |
|||
id | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
preSave | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 9 |
|||
preSaveNew | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 14 |
|||
calculateDependencies | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
preSaveUpdated | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 9 |
|||
postSave | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
preDelete | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 12 |
|||
postDelete | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
getSchema | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
hasCustomStorage | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isBaseField | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getColumns | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
getBundles | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
getName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isDeleted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getTypeProvider | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getType | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getSettings | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
getSetting | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
setSetting | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
setSettings | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
isTranslatable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isRevisionable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
setTranslatable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getProvider | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getLabel | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getDescription | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getCardinality | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
setCardinality | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getOptionsProvider | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
isMultiple | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 2 |
|||
isLocked | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
setLocked | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getTargetEntityTypeId | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isQueryable | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
hasData | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
__sleep | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
getConstraints | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getConstraint | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getPropertyDefinition | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
getPropertyDefinitions | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
getPropertyNames | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getMainPropertyName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getUniqueStorageIdentifier | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getFieldItemClass | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
loadByName | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
isDeletable | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 1 |
|||
getIndexes | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
setIndexes | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\field\Entity\FieldStorageConfig. | |
*/ | |
namespace Drupal\field\Entity; | |
use Drupal\Component\Utility\Unicode; | |
use Drupal\Core\Config\Entity\ConfigEntityBase; | |
use Drupal\Core\Entity\EntityStorageInterface; | |
use Drupal\Core\Entity\FieldableEntityInterface; | |
use Drupal\Core\Field\FieldException; | |
use Drupal\Core\Field\FieldStorageDefinitionInterface; | |
use Drupal\Core\TypedData\OptionsProviderInterface; | |
use Drupal\field\FieldStorageConfigInterface; | |
/** | |
* Defines the Field storage configuration entity. | |
* | |
* @ConfigEntityType( | |
* id = "field_storage_config", | |
* label = @Translation("Field storage"), | |
* handlers = { | |
* "storage" = "Drupal\field\FieldStorageConfigStorage" | |
* }, | |
* config_prefix = "storage", | |
* entity_keys = { | |
* "id" = "id", | |
* "label" = "id" | |
* }, | |
* config_export = { | |
* "id", | |
* "field_name", | |
* "entity_type", | |
* "type", | |
* "settings", | |
* "module", | |
* "locked", | |
* "cardinality", | |
* "translatable", | |
* "indexes", | |
* "persist_with_no_fields", | |
* "custom_storage", | |
* } | |
* ) | |
*/ | |
class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigInterface { | |
/** | |
* The maximum length of the field name, in characters. | |
* | |
* For fields created through Field UI, this includes the 'field_' prefix. | |
*/ | |
const NAME_MAX_LENGTH = 32; | |
/** | |
* The field ID. | |
* | |
* The ID consists of 2 parts: the entity type and the field name. | |
* | |
* Example: node.body, user.field_main_image. | |
* | |
* @var string | |
*/ | |
protected $id; | |
/** | |
* The field name. | |
* | |
* This is the name of the property under which the field values are placed in | |
* an entity: $entity->{$field_name}. The maximum length is | |
* Field:NAME_MAX_LENGTH. | |
* | |
* Example: body, field_main_image. | |
* | |
* @var string | |
*/ | |
protected $field_name; | |
/** | |
* The name of the entity type the field can be attached to. | |
* | |
* @var string | |
*/ | |
protected $entity_type; | |
/** | |
* The field type. | |
* | |
* Example: text, integer. | |
* | |
* @var string | |
*/ | |
protected $type; | |
/** | |
* The name of the module that provides the field type. | |
* | |
* @var string | |
*/ | |
protected $module; | |
/** | |
* Field-type specific settings. | |
* | |
* An array of key/value pairs, The keys and default values are defined by the | |
* field type. | |
* | |
* @var array | |
*/ | |
protected $settings = []; | |
/** | |
* The field cardinality. | |
* | |
* The maximum number of values the field can hold. Possible values are | |
* positive integers or | |
* FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED. Defaults to 1. | |
* | |
* @var int | |
*/ | |
protected $cardinality = 1; | |
/** | |
* Flag indicating whether the field is translatable. | |
* | |
* Defaults to TRUE. | |
* | |
* @var bool | |
*/ | |
protected $translatable = TRUE; | |
/** | |
* Flag indicating whether the field is available for editing. | |
* | |
* If TRUE, some actions not available though the UI (but are still possible | |
* through direct API manipulation): | |
* - field settings cannot be changed, | |
* - new fields cannot be created | |
* - existing fields cannot be deleted. | |
* Defaults to FALSE. | |
* | |
* @var bool | |
*/ | |
protected $locked = FALSE; | |
/** | |
* Flag indicating whether the field storage should be deleted when orphaned. | |
* | |
* By default field storages for configurable fields are removed when there | |
* are no remaining fields using them. If multiple modules provide bundles | |
* which need to use the same field storage then setting this to TRUE will | |
* preserve the field storage regardless of what happens to the bundles. The | |
* classic use case for this is node body field storage since Book, Forum, the | |
* Standard profile and bundle (node type) creation through the UI all use | |
* same field storage. | |
* | |
* @var bool | |
*/ | |
protected $persist_with_no_fields = FALSE; | |
/** | |
* A boolean indicating whether or not the field item uses custom storage. | |
* | |
* @var bool | |
*/ | |
public $custom_storage = FALSE; | |
/** | |
* The custom storage indexes for the field data storage. | |
* | |
* This set of indexes is merged with the "default" indexes specified by the | |
* field type in hook_field_schema() to determine the actual set of indexes | |
* that get created. | |
* | |
* The indexes are defined using the same definition format as Schema API | |
* index specifications. Only columns that are part of the field schema, as | |
* defined by the field type in hook_field_schema(), are allowed. | |
* | |
* Some storage backends might not support indexes, and discard that | |
* information. | |
* | |
* @var array | |
*/ | |
protected $indexes = []; | |
/** | |
* 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 field schema. | |
* | |
* @var array | |
*/ | |
protected $schema; | |
/** | |
* An array of field property definitions. | |
* | |
* @var \Drupal\Core\TypedData\DataDefinitionInterface[] | |
* | |
* @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface::getPropertyDefinitions() | |
*/ | |
protected $propertyDefinitions; | |
/** | |
* Static flag set to prevent recursion during field deletes. | |
* | |
* @var bool | |
*/ | |
protected static $inDeletion = FALSE; | |
/** | |
* Constructs a FieldStorageConfig object. | |
* | |
* @param array $values | |
* An array of field properties, keyed by property name. Most array | |
* elements will be used to set the corresponding properties on the class; | |
* see the class property documentation for details. Some array elements | |
* have special meanings and a few are required. Special elements are: | |
* - name: required. As a temporary Backwards Compatibility layer right now, | |
* a 'field_name' property can be accepted in place of 'id'. | |
* - entity_type: required. | |
* - type: required. | |
* | |
* In most cases, Field entities are created via | |
* entity_create('field_storage_config', $values)), where $values is the same | |
* parameter as in this constructor. | |
* | |
* @see entity_create() | |
*/ | |
public function __construct(array $values, $entity_type = 'field_storage_config') { | |
// Check required properties. | |
if (empty($values['field_name'])) { | |
throw new FieldException('Attempt to create a field storage without a field name.'); | |
} | |
if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['field_name'])) { | |
throw new FieldException("Attempt to create a field storage {$values['field_name']} with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character"); | |
} | |
if (empty($values['type'])) { | |
throw new FieldException("Attempt to create a field storage {$values['field_name']} with no type."); | |
} | |
if (empty($values['entity_type'])) { | |
throw new FieldException("Attempt to create a field storage {$values['field_name']} with no entity_type."); | |
} | |
parent::__construct($values, $entity_type); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function id() { | |
return $this->getTargetEntityTypeId() . '.' . $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) { | |
// Clear the derived data about the field. | |
unset($this->schema); | |
// 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. | |
$field_type_manager = \Drupal::service('plugin.manager.field.field_type'); | |
$default_settings = $field_type_manager->getDefaultStorageSettings($this->type); | |
$this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings; | |
if ($this->isNew()) { | |
$this->preSaveNew($storage); | |
} | |
else { | |
$this->preSaveUpdated($storage); | |
} | |
parent::preSave($storage); | |
} | |
/** | |
* Prepares saving a new field definition. | |
* | |
* @param \Drupal\Core\Entity\EntityStorageInterface $storage | |
* The entity storage. | |
* | |
* @throws \Drupal\Core\Field\FieldException If the field definition is invalid. | |
*/ | |
protected function preSaveNew(EntityStorageInterface $storage) { | |
$entity_manager = \Drupal::entityManager(); | |
$field_type_manager = \Drupal::service('plugin.manager.field.field_type'); | |
// Assign the ID. | |
$this->id = $this->id(); | |
// Field name cannot be longer than FieldStorageConfig::NAME_MAX_LENGTH characters. | |
// We use Unicode::strlen() because the DB layer assumes that column widths | |
// are given in characters rather than bytes. | |
if (Unicode::strlen($this->getName()) > static::NAME_MAX_LENGTH) { | |
throw new FieldException('Attempt to create a field storage with an name longer than ' . static::NAME_MAX_LENGTH . ' characters: ' . $this->getName()); | |
} | |
// Disallow reserved field names. | |
$disallowed_field_names = array_keys($entity_manager->getBaseFieldDefinitions($this->getTargetEntityTypeId())); | |
if (in_array($this->getName(), $disallowed_field_names)) { | |
throw new FieldException("Attempt to create field storage {$this->getName()} which is reserved by entity type {$this->getTargetEntityTypeId()}."); | |
} | |
// Check that the field type is known. | |
$field_type = $field_type_manager->getDefinition($this->getType(), FALSE); | |
if (!$field_type) { | |
throw new FieldException("Attempt to create a field storage of unknown type {$this->getType()}."); | |
} | |
$this->module = $field_type['provider']; | |
// Notify the entity manager. | |
$entity_manager->onFieldStorageDefinitionCreate($this); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function calculateDependencies() { | |
parent::calculateDependencies(); | |
// Ensure the field is dependent on the providing module. | |
$this->addDependency('module', $this->getTypeProvider()); | |
// Ask the field type for any additional storage dependencies. | |
// @see \Drupal\Core\Field\FieldItemInterface::calculateStorageDependencies() | |
$definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType(), FALSE); | |
$this->addDependencies($definition['class']::calculateStorageDependencies($this)); | |
// Ensure the field is dependent on the provider of the entity type. | |
$entity_type = \Drupal::entityManager()->getDefinition($this->entity_type); | |
$this->addDependency('module', $entity_type->getProvider()); | |
return $this; | |
} | |
/** | |
* Prepares saving an updated field definition. | |
* | |
* @param \Drupal\Core\Entity\EntityStorageInterface $storage | |
* The entity storage. | |
*/ | |
protected function preSaveUpdated(EntityStorageInterface $storage) { | |
$module_handler = \Drupal::moduleHandler(); | |
$entity_manager = \Drupal::entityManager(); | |
// Some updates are always disallowed. | |
if ($this->getType() != $this->original->getType()) { | |
throw new FieldException("Cannot change the field type for an existing field storage."); | |
} | |
if ($this->getTargetEntityTypeId() != $this->original->getTargetEntityTypeId()) { | |
throw new FieldException("Cannot change the entity type for an existing field storage."); | |
} | |
// See if any module forbids the update by throwing an exception. This | |
// invokes hook_field_storage_config_update_forbid(). | |
$module_handler->invokeAll('field_storage_config_update_forbid', array($this, $this->original)); | |
// Notify the entity manager. A listener can reject the definition | |
// update as invalid by raising an exception, which stops execution before | |
// the definition is written to config. | |
$entity_manager->onFieldStorageDefinitionUpdate($this, $this->original); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function postSave(EntityStorageInterface $storage, $update = TRUE) { | |
if ($update) { | |
// Invalidate the render cache for all affected entities. | |
$entity_manager = \Drupal::entityManager(); | |
$entity_type = $this->getTargetEntityTypeId(); | |
if ($entity_manager->hasHandler($entity_type, 'view_builder')) { | |
$entity_manager->getViewBuilder($entity_type)->resetCache(); | |
} | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function preDelete(EntityStorageInterface $storage, array $field_storages) { | |
$state = \Drupal::state(); | |
// Set the static flag so that we don't delete field storages whilst | |
// deleting fields. | |
static::$inDeletion = TRUE; | |
// Delete or fix any configuration that is dependent, for example, fields. | |
parent::preDelete($storage, $field_storages); | |
// Keep the field definitions in the state storage so we can use them later | |
// during field_purge_batch(). | |
$deleted_storages = $state->get('field.storage.deleted') ?: array(); | |
foreach ($field_storages as $field_storage) { | |
if (!$field_storage->deleted) { | |
$config = $field_storage->toArray(); | |
$config['deleted'] = TRUE; | |
$config['bundles'] = $field_storage->getBundles(); | |
$deleted_storages[$field_storage->uuid()] = $config; | |
} | |
} | |
$state->set('field.storage.deleted', $deleted_storages); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function postDelete(EntityStorageInterface $storage, array $fields) { | |
// Notify the storage. | |
foreach ($fields as $field) { | |
if (!$field->deleted) { | |
\Drupal::entityManager()->onFieldStorageDefinitionDelete($field); | |
$field->deleted = TRUE; | |
} | |
} | |
// Unset static flag. | |
static::$inDeletion = FALSE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getSchema() { | |
if (!isset($this->schema)) { | |
// Get the schema from the field item class. | |
$class = $this->getFieldItemClass(); | |
$schema = $class::schema($this); | |
// Fill in default values for optional entries. | |
$schema += array( | |
'columns' => array(), | |
'unique keys' => array(), | |
'indexes' => array(), | |
'foreign keys' => array(), | |
); | |
// Merge custom indexes with those specified by the field type. Custom | |
// indexes prevail. | |
$schema['indexes'] = $this->indexes + $schema['indexes']; | |
$this->schema = $schema; | |
} | |
return $this->schema; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function hasCustomStorage() { | |
return $this->custom_storage; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isBaseField() { | |
return FALSE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getColumns() { | |
$schema = $this->getSchema(); | |
// A typical use case for the method is to iterate on the columns, while | |
// some other use cases rely on identifying the first column with the key() | |
// function. Since the schema is persisted in the Field object, we take care | |
// of resetting the array pointer so that the former does not interfere with | |
// the latter. | |
reset($schema['columns']); | |
return $schema['columns']; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getBundles() { | |
if (!$this->isDeleted()) { | |
$map = \Drupal::entityManager()->getFieldMap(); | |
if (isset($map[$this->getTargetEntityTypeId()][$this->getName()]['bundles'])) { | |
return $map[$this->getTargetEntityTypeId()][$this->getName()]['bundles']; | |
} | |
} | |
return array(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getName() { | |
return $this->field_name; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isDeleted() { | |
return $this->deleted; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getTypeProvider() { | |
return $this->module; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getType() { | |
return $this->type; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getSettings() { | |
// @todo FieldTypePluginManager maintains its own static cache. However, do | |
// some CPU and memory profiling to see if it's worth statically caching | |
// $field_type_info, or the default field storage and field settings, | |
// within $this. | |
$field_type_manager = \Drupal::service('plugin.manager.field.field_type'); | |
$settings = $field_type_manager->getDefaultStorageSettings($this->getType()); | |
return $this->settings + $settings; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getSetting($setting_name) { | |
// @todo See getSettings() about potentially statically caching this. | |
// We assume here that one call to array_key_exists() is more efficient | |
// than calling getSettings() when all we need is a single setting. | |
if (array_key_exists($setting_name, $this->settings)) { | |
return $this->settings[$setting_name]; | |
} | |
$settings = $this->getSettings(); | |
if (array_key_exists($setting_name, $settings)) { | |
return $settings[$setting_name]; | |
} | |
else { | |
return NULL; | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setSetting($setting_name, $value) { | |
$this->settings[$setting_name] = $value; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setSettings(array $settings) { | |
$this->settings = $settings + $this->settings; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isTranslatable() { | |
return $this->translatable; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isRevisionable() { | |
// All configurable fields are revisionable. | |
return TRUE; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setTranslatable($translatable) { | |
$this->translatable = $translatable; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getProvider() { | |
return 'field'; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getLabel() { | |
return $this->label(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getDescription() { | |
return NULL; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getCardinality() { | |
return $this->cardinality; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setCardinality($cardinality) { | |
$this->cardinality = $cardinality; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getOptionsProvider($property_name, FieldableEntityInterface $entity) { | |
// If the field item class implements the interface, create an orphaned | |
// runtime item object, so that it can be used as the options provider | |
// without modifying the entity being worked on. | |
if (is_subclass_of($this->getFieldItemClass(), '\Drupal\Core\TypedData\OptionsProviderInterface')) { | |
$items = $entity->get($this->getName()); | |
return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0); | |
} | |
// @todo: Allow setting custom options provider, see | |
// https://www.drupal.org/node/2002138. | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isMultiple() { | |
$cardinality = $this->getCardinality(); | |
return ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) || ($cardinality > 1); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isLocked() { | |
return $this->locked; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setLocked($locked) { | |
$this->locked = $locked; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getTargetEntityTypeId() { | |
return $this->entity_type; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isQueryable() { | |
return TRUE; | |
} | |
/** | |
* Determines whether a field has any data. | |
* | |
* @return bool | |
* TRUE if the field has data for any entity; FALSE otherwise. | |
*/ | |
public function hasData() { | |
return \Drupal::entityManager()->getStorage($this->entity_type)->countFieldData($this, TRUE); | |
} | |
/** | |
* Implements the magic __sleep() method. | |
* | |
* Using the Serialize interface and serialize() / unserialize() methods | |
* breaks entity forms in PHP 5.4. | |
* @todo Investigate in https://www.drupal.org/node/2074253. | |
*/ | |
public function __sleep() { | |
// Only serialize necessary properties, excluding those that can be | |
// recalculated. | |
$properties = get_object_vars($this); | |
unset($properties['schema'], $properties['propertyDefinitions'], $properties['original']); | |
return array_keys($properties); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getConstraints() { | |
return array(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getConstraint($constraint_name) { | |
return NULL; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getPropertyDefinition($name) { | |
if (!isset($this->propertyDefinitions)) { | |
$this->getPropertyDefinitions(); | |
} | |
if (isset($this->propertyDefinitions[$name])) { | |
return $this->propertyDefinitions[$name]; | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getPropertyDefinitions() { | |
if (!isset($this->propertyDefinitions)) { | |
$class = $this->getFieldItemClass(); | |
$this->propertyDefinitions = $class::propertyDefinitions($this); | |
} | |
return $this->propertyDefinitions; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getPropertyNames() { | |
return array_keys($this->getPropertyDefinitions()); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getMainPropertyName() { | |
$class = $this->getFieldItemClass(); | |
return $class::mainPropertyName(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getUniqueStorageIdentifier() { | |
return $this->uuid(); | |
} | |
/** | |
* Helper to retrieve the field item class. | |
*/ | |
protected function getFieldItemClass() { | |
$type_definition = \Drupal::typedDataManager() | |
->getDefinition('field_item:' . $this->getType()); | |
return $type_definition['class']; | |
} | |
/** | |
* 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 $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, $field_name) { | |
return \Drupal::entityManager()->getStorage('field_storage_config')->load($entity_type_id . '.' . $field_name); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function isDeletable() { | |
// The field storage is not deleted, is configured to be removed when there | |
// are no fields, the field storage has no bundles, and field storages are | |
// not in the process of being deleted. | |
return !$this->deleted && !$this->persist_with_no_fields && count($this->getBundles()) == 0 && !static::$inDeletion; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getIndexes() { | |
return $this->indexes; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setIndexes(array $indexes) { | |
$this->indexes = $indexes; | |
return $this; | |
} | |
} |