123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- <?php
- namespace Drupal\Core\Field;
- use Drupal\Core\Config\Entity\ConfigEntityBase;
- use Drupal\Core\Entity\EntityStorageInterface;
- use Drupal\Core\Entity\FieldableEntityInterface;
- use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
- /**
- * Base class for configurable field definitions.
- */
- abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigInterface {
- /**
- * The field ID.
- *
- * The ID consists of 3 parts: the entity type, bundle and the field name.
- *
- * Example: node.article.body, user.user.field_main_image.
- *
- * @var string
- */
- protected $id;
- /**
- * The field name.
- *
- * @var string
- */
- protected $field_name;
- /**
- * The field type.
- *
- * This property is denormalized from the field storage for optimization of
- * the "entity and render cache hits" critical paths. If not present in the
- * $values passed to create(), it is populated from the field storage in
- * postCreate(), and saved in config records so that it is present on
- * subsequent loads.
- *
- * @var string
- */
- protected $field_type;
- /**
- * The name of the entity type the field is attached to.
- *
- * @var string
- */
- protected $entity_type;
- /**
- * The name of the bundle the field is attached to.
- *
- * @var string
- */
- protected $bundle;
- /**
- * The human-readable label for the field.
- *
- * This will be used as the title of Form API elements for the field in entity
- * edit forms, or as the label for the field values in displayed entities.
- *
- * If not specified, this defaults to the field_name (mostly useful for fields
- * created in tests).
- *
- * @var string
- */
- protected $label;
- /**
- * The field description.
- *
- * A human-readable description for the field when used with this bundle.
- * For example, the description will be the help text of Form API elements for
- * this field in entity edit forms.
- *
- * @var string
- */
- protected $description = '';
- /**
- * 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 = [];
- /**
- * Flag indicating whether the field is required.
- *
- * TRUE if a value for this field is required when used with this bundle,
- * FALSE otherwise. Currently, required-ness is only enforced at the Form API
- * level in entity edit forms, not during direct API saves.
- *
- * @var bool
- */
- protected $required = FALSE;
- /**
- * Flag indicating whether the field is translatable.
- *
- * Defaults to TRUE.
- *
- * @var bool
- */
- protected $translatable = TRUE;
- /**
- * Default field value.
- *
- * The default value is used when an entity is created, either:
- * - through an entity creation form; the form elements for the field are
- * prepopulated with the default value.
- * - through direct API calls (i.e. $entity->save()); the default value is
- * added if the $entity object provides no explicit entry (actual values or
- * "the field is empty") for the field.
- *
- * The default value is expressed as a numerically indexed array of items,
- * each item being an array of key/value pairs matching the set of 'columns'
- * defined by the "field schema" for the field type, as exposed in
- * hook_field_schema(). If the number of items exceeds the cardinality of the
- * field, extraneous items will be ignored.
- *
- * This property is overlooked if the $default_value_callback is non-empty.
- *
- * Example for a integer field:
- * @code
- * array(
- * array('value' => 1),
- * array('value' => 2),
- * )
- * @endcode
- *
- * @var array
- */
- protected $default_value = [];
- /**
- * The name of a callback function that returns default values.
- *
- * The function will be called with the following arguments:
- * - \Drupal\Core\Entity\FieldableEntityInterface $entity
- * The entity being created.
- * - \Drupal\Core\Field\FieldDefinitionInterface $definition
- * The field definition.
- * It should return an array of default values, in the same format as the
- * $default_value property.
- *
- * This property takes precedence on the list of fixed values specified in the
- * $default_value property.
- *
- * @var string
- */
- protected $default_value_callback = '';
- /**
- * The field storage object.
- *
- * @var \Drupal\Core\Field\FieldStorageDefinitionInterface
- */
- protected $fieldStorage;
- /**
- * The data definition of a field item.
- *
- * @var \Drupal\Core\Field\TypedData\FieldItemDataDefinition
- */
- protected $itemDefinition;
- /**
- * Array of constraint options keyed by constraint plugin ID.
- *
- * @var array
- */
- protected $constraints = [];
- /**
- * Array of property constraint options keyed by property ID. The values are
- * associative array of constraint options keyed by constraint plugin ID.
- *
- * @var array[]
- */
- protected $propertyConstraints = [];
- /**
- * {@inheritdoc}
- */
- public function id() {
- return $this->entity_type . '.' . $this->bundle . '.' . $this->field_name;
- }
- /**
- * {@inheritdoc}
- */
- public function getName() {
- return $this->field_name;
- }
- /**
- * {@inheritdoc}
- */
- public function getType() {
- return $this->field_type;
- }
- /**
- * {@inheritdoc}
- */
- public function getTargetEntityTypeId() {
- return $this->entity_type;
- }
- /**
- * {@inheritdoc}
- */
- public function getTargetBundle() {
- return $this->bundle;
- }
- /**
- * {@inheritdoc}
- */
- public function calculateDependencies() {
- parent::calculateDependencies();
- // Add dependencies from the field type plugin. We can not use
- // self::calculatePluginDependencies() because instantiation of a field item
- // plugin requires a parent entity.
- /** @var $field_type_manager \Drupal\Core\Field\FieldTypePluginManagerInterface */
- $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
- $definition = $field_type_manager->getDefinition($this->getType());
- $this->addDependency('module', $definition['provider']);
- // Plugins can declare additional dependencies in their definition.
- if (isset($definition['config_dependencies'])) {
- $this->addDependencies($definition['config_dependencies']);
- }
- // Let the field type plugin specify its own dependencies.
- // @see \Drupal\Core\Field\FieldItemInterface::calculateDependencies()
- $this->addDependencies($definition['class']::calculateDependencies($this));
- // Create dependency on the bundle.
- $bundle_config_dependency = $this->entityManager()->getDefinition($this->entity_type)->getBundleConfigDependency($this->bundle);
- $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function onDependencyRemoval(array $dependencies) {
- $changed = parent::onDependencyRemoval($dependencies);
- $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
- $definition = $field_type_manager->getDefinition($this->getType());
- if ($definition['class']::onDependencyRemoval($this, $dependencies)) {
- $changed = TRUE;
- }
- return $changed;
- }
- /**
- * {@inheritdoc}
- */
- public function postCreate(EntityStorageInterface $storage) {
- parent::postCreate($storage);
- // If it was not present in the $values passed to create(), (e.g. for
- // programmatic creation), populate the denormalized field_type property
- // from the field storage, so that it gets saved in the config record.
- if (empty($this->field_type)) {
- $this->field_type = $this->getFieldStorageDefinition()->getType();
- }
- }
- /**
- * {@inheritdoc}
- */
- public function postSave(EntityStorageInterface $storage, $update = TRUE) {
- // Clear the cache.
- $this->entityManager()->clearCachedFieldDefinitions();
- // Invalidate the render cache for all affected entities.
- $entity_type = $this->getFieldStorageDefinition()->getTargetEntityTypeId();
- if ($this->entityManager()->hasHandler($entity_type, 'view_builder')) {
- $this->entityManager()->getViewBuilder($entity_type)->resetCache();
- }
- }
- /**
- * {@inheritdoc}
- */
- public function getLabel() {
- return $this->label();
- }
- /**
- * {@inheritdoc}
- */
- public function setLabel($label) {
- $this->label = $label;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getDescription() {
- return $this->description;
- }
- /**
- * {@inheritdoc}
- */
- public function setDescription($description) {
- $this->description = $description;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isTranslatable() {
- // A field can be enabled for translation only if translation is supported.
- return $this->translatable && $this->getFieldStorageDefinition()->isTranslatable();
- }
- /**
- * {@inheritdoc}
- */
- public function setTranslatable($translatable) {
- $this->translatable = $translatable;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getSettings() {
- return $this->settings + $this->getFieldStorageDefinition()->getSettings();
- }
- /**
- * {@inheritdoc}
- */
- public function setSettings(array $settings) {
- $this->settings = $settings + $this->settings;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getSetting($setting_name) {
- if (array_key_exists($setting_name, $this->settings)) {
- return $this->settings[$setting_name];
- }
- else {
- return $this->getFieldStorageDefinition()->getSetting($setting_name);
- }
- }
- /**
- * {@inheritdoc}
- */
- public function setSetting($setting_name, $value) {
- $this->settings[$setting_name] = $value;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isRequired() {
- return $this->required;
- }
- /**
- * [@inheritdoc}
- */
- public function setRequired($required) {
- $this->required = $required;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getDefaultValue(FieldableEntityInterface $entity) {
- // Allow custom default values function.
- if ($callback = $this->getDefaultValueCallback()) {
- $value = call_user_func($callback, $entity, $this);
- }
- else {
- $value = $this->getDefaultValueLiteral();
- }
- // Allow the field type to process default values.
- $field_item_list_class = $this->getClass();
- return $field_item_list_class::processDefaultValue($value, $entity, $this);
- }
- /**
- * {@inheritdoc}
- */
- public function getDefaultValueLiteral() {
- return $this->default_value;
- }
- /**
- * {@inheritdoc}
- */
- public function setDefaultValue($value) {
- if (!is_array($value)) {
- if ($value === NULL) {
- $value = [];
- }
- $key = $this->getFieldStorageDefinition()->getPropertyNames()[0];
- // Convert to the multi value format to support fields with a cardinality
- // greater than 1.
- $value = [
- [$key => $value],
- ];
- }
- $this->default_value = $value;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getDefaultValueCallback() {
- return $this->default_value_callback;
- }
- /**
- * {@inheritdoc}
- */
- public function setDefaultValueCallback($callback) {
- $this->default_value_callback = $callback;
- return $this;
- }
- /**
- * 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['fieldStorage'], $properties['itemDefinition'], $properties['original']);
- return array_keys($properties);
- }
- /**
- * {@inheritdoc}
- */
- public static function createFromItemType($item_type) {
- // Forward to the field definition class for creating new data definitions
- // via the typed manager.
- return BaseFieldDefinition::createFromItemType($item_type);
- }
- /**
- * {@inheritdoc}
- */
- public static function createFromDataType($type) {
- // Forward to the field definition class for creating new data definitions
- // via the typed manager.
- return BaseFieldDefinition::createFromDataType($type);
- }
- /**
- * {@inheritdoc}
- */
- public function getDataType() {
- return 'list';
- }
- /**
- * {@inheritdoc}
- */
- public function isList() {
- return TRUE;
- }
- /**
- * {@inheritdoc}
- */
- public function getClass() {
- // Derive list class from the field type.
- $type_definition = \Drupal::service('plugin.manager.field.field_type')
- ->getDefinition($this->getType());
- return $type_definition['list_class'];
- }
- /**
- * {@inheritdoc}
- */
- public function getConstraints() {
- return \Drupal::typedDataManager()->getDefaultConstraints($this) + $this->constraints;
- }
- /**
- * {@inheritdoc}
- */
- public function getConstraint($constraint_name) {
- $constraints = $this->getConstraints();
- return isset($constraints[$constraint_name]) ? $constraints[$constraint_name] : NULL;
- }
- /**
- * {@inheritdoc}
- */
- public function getItemDefinition() {
- if (!isset($this->itemDefinition)) {
- $this->itemDefinition = FieldItemDataDefinition::create($this)
- ->setSettings($this->getSettings());
- // Add any custom property constraints, overwriting as required.
- $item_constraints = $this->itemDefinition->getConstraint('ComplexData') ?: [];
- foreach ($this->propertyConstraints as $name => $constraints) {
- if (isset($item_constraints[$name])) {
- $item_constraints[$name] = $constraints + $item_constraints[$name];
- }
- else {
- $item_constraints[$name] = $constraints;
- }
- $this->itemDefinition->addConstraint('ComplexData', $item_constraints);
- }
- }
- return $this->itemDefinition;
- }
- /**
- * {@inheritdoc}
- */
- public function getConfig($bundle) {
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setConstraints(array $constraints) {
- $this->constraints = $constraints;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addConstraint($constraint_name, $options = NULL) {
- $this->constraints[$constraint_name] = $options;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setPropertyConstraints($name, array $constraints) {
- $this->propertyConstraints[$name] = $constraints;
- // Reset the field item definition so the next time it is instantiated it
- // will receive the new constraints.
- $this->itemDefinition = NULL;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addPropertyConstraints($name, array $constraints) {
- foreach ($constraints as $constraint_name => $options) {
- $this->propertyConstraints[$name][$constraint_name] = $options;
- }
- // Reset the field item definition so the next time it is instantiated it
- // will receive the new constraints.
- $this->itemDefinition = NULL;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isInternal() {
- // Respect the definition, otherwise default to TRUE for computed fields.
- if (isset($this->definition['internal'])) {
- return $this->definition['internal'];
- }
- return $this->isComputed();
- }
- }
|