3 namespace Drupal\Core\Field\Entity;
5 use Drupal\Core\Entity\EntityStorageInterface;
6 use Drupal\Core\Field\BaseFieldDefinition;
7 use Drupal\Core\Field\FieldConfigBase;
8 use Drupal\Core\Field\FieldException;
11 * Defines the base field override entity.
13 * Allows base fields to be overridden on the bundle level.
16 * id = "base_field_override",
17 * label = @Translation("Base field override"),
19 * "storage" = "Drupal\Core\Field\BaseFieldOverrideStorage",
20 * "access" = "Drupal\Core\Field\BaseFieldOverrideAccessControlHandler",
22 * config_prefix = "base_field_override",
37 * "default_value_callback",
43 class BaseFieldOverride extends FieldConfigBase {
46 * The base field definition.
48 * @var \Drupal\Core\Field\BaseFieldDefinition
50 protected $baseFieldDefinition;
53 * Creates a base field override object.
55 * @param \Drupal\Core\Field\BaseFieldDefinition $base_field_definition
56 * The base field definition to override.
57 * @param string $bundle
58 * The bundle to which the override applies.
60 * @return \Drupal\Core\Field\Entity\BaseFieldOverride
61 * A new base field override object.
63 public static function createFromBaseFieldDefinition(BaseFieldDefinition $base_field_definition, $bundle) {
64 $values = $base_field_definition->toArray();
65 $values['bundle'] = $bundle;
66 $values['baseFieldDefinition'] = $base_field_definition;
67 return \Drupal::entityManager()->getStorage('base_field_override')->create($values);
71 * Constructs a BaseFieldOverride object.
73 * In most cases, base field override entities are created via
74 * BaseFieldOverride::createFromBaseFieldDefinition($definition, 'bundle')
76 * @param array $values
77 * An array of base field bundle override properties, keyed by property
78 * name. The field to override is specified by referring to an existing
80 * - field_name: The field name.
81 * - entity_type: The entity type.
82 * Additionally, a 'bundle' property is required to indicate the entity
83 * bundle to which the bundle field override is attached to. Other array
84 * elements will be used to set the corresponding properties on the class;
85 * see the class property documentation for details.
86 * @param string $entity_type
87 * (optional) The type of the entity to create. Defaults to
88 * 'base_field_override'.
90 * @see entity_create()
92 * @throws \Drupal\Core\Field\FieldException
93 * Exception thrown if $values does not contain a field_name, entity_type or
96 public function __construct(array $values, $entity_type = 'base_field_override') {
97 if (empty($values['field_name'])) {
98 throw new FieldException('Attempt to create a base field bundle override of a field without a field_name');
100 if (empty($values['entity_type'])) {
101 throw new FieldException("Attempt to create a base field bundle override of field {$values['field_name']} without an entity_type");
103 if (empty($values['bundle'])) {
104 throw new FieldException("Attempt to create a base field bundle override of field {$values['field_name']} without a bundle");
107 parent::__construct($values, $entity_type);
113 public function getFieldStorageDefinition() {
114 return $this->getBaseFieldDefinition()->getFieldStorageDefinition();
120 public function isDisplayConfigurable($context) {
121 return $this->getBaseFieldDefinition()->isDisplayConfigurable($context);
127 public function getDisplayOptions($display_context) {
128 return $this->getBaseFieldDefinition()->getDisplayOptions($display_context);
134 public function isReadOnly() {
135 return $this->getBaseFieldDefinition()->isReadOnly();
141 public function isComputed() {
142 return $this->getBaseFieldDefinition()->isComputed();
148 public function getClass() {
149 return $this->getBaseFieldDefinition()->getClass();
153 * Gets the base field definition.
155 * @return \Drupal\Core\Field\BaseFieldDefinition
157 protected function getBaseFieldDefinition() {
158 if (!isset($this->baseFieldDefinition)) {
159 $fields = $this->entityManager()->getBaseFieldDefinitions($this->entity_type);
160 $this->baseFieldDefinition = $fields[$this->getName()];
162 return $this->baseFieldDefinition;
168 * @throws \Drupal\Core\Field\FieldException
169 * If the bundle is being changed.
171 public function preSave(EntityStorageInterface $storage) {
172 // Filter out unknown settings and make sure all settings are present, so
173 // that a complete field definition is passed to the various hooks and
174 // written to config.
175 $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
176 $default_settings = $field_type_manager->getDefaultFieldSettings($this->getType());
177 $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
179 // Call the parent's presave method to perform validate and calculate
181 parent::preSave($storage);
183 if ($this->isNew()) {
184 // @todo This assumes that the previous definition isn't some
185 // non-config-based override, but that might not be the case:
186 // https://www.drupal.org/node/2321071.
187 $previous_definition = $this->getBaseFieldDefinition();
190 // Some updates are always disallowed.
191 if ($this->entity_type != $this->original->entity_type) {
192 throw new FieldException("Cannot change the entity_type of an existing base field bundle override (entity type:{$this->entity_type}, bundle:{$this->original->bundle}, field name: {$this->field_name})");
194 if ($this->bundle != $this->original->bundle) {
195 throw new FieldException("Cannot change the bundle of an existing base field bundle override (entity type:{$this->entity_type}, bundle:{$this->original->bundle}, field name: {$this->field_name})");
197 $previous_definition = $this->original;
199 // Notify the entity storage.
200 $this->entityManager()->getStorage($this->getTargetEntityTypeId())->onFieldDefinitionUpdate($this, $previous_definition);
206 public static function postDelete(EntityStorageInterface $storage, array $field_overrides) {
207 $entity_manager = \Drupal::entityManager();
208 // Clear the cache upfront, to refresh the results of getBundles().
209 $entity_manager->clearCachedFieldDefinitions();
210 /** @var \Drupal\Core\Field\Entity\BaseFieldOverride $field_override */
211 foreach ($field_overrides as $field_override) {
212 // Inform the system that the field definition is being updated back to
213 // its non-overridden state.
214 // @todo This assumes that there isn't a non-config-based override that
215 // we're returning to, but that might not be the case:
216 // https://www.drupal.org/node/2321071.
217 $entity_manager->getStorage($field_override->getTargetEntityTypeId())->onFieldDefinitionUpdate($field_override->getBaseFieldDefinition(), $field_override);
222 * Loads a base field bundle override config entity.
224 * @param string $entity_type_id
225 * ID of the entity type.
226 * @param string $bundle
228 * @param string $field_name
232 * The base field bundle override config entity if one exists for the
233 * provided field name, otherwise NULL.
235 public static function loadByName($entity_type_id, $bundle, $field_name) {
236 return \Drupal::entityManager()->getStorage('base_field_override')->load($entity_type_id . '.' . $bundle . '.' . $field_name);
240 * Implements the magic __sleep() method.
242 public function __sleep() {
243 // Only serialize necessary properties, excluding those that can be
245 unset($this->baseFieldDefinition);
246 return parent::__sleep();