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();
146 * Gets the base field definition.
148 * @return \Drupal\Core\Field\BaseFieldDefinition
150 protected function getBaseFieldDefinition() {
151 if (!isset($this->baseFieldDefinition)) {
152 $fields = $this->entityManager()->getBaseFieldDefinitions($this->entity_type);
153 $this->baseFieldDefinition = $fields[$this->getName()];
155 return $this->baseFieldDefinition;
161 * @throws \Drupal\Core\Field\FieldException
162 * If the bundle is being changed.
164 public function preSave(EntityStorageInterface $storage) {
165 // Filter out unknown settings and make sure all settings are present, so
166 // that a complete field definition is passed to the various hooks and
167 // written to config.
168 $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
169 $default_settings = $field_type_manager->getDefaultFieldSettings($this->getType());
170 $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
172 // Call the parent's presave method to perform validate and calculate
174 parent::preSave($storage);
176 if ($this->isNew()) {
177 // @todo This assumes that the previous definition isn't some
178 // non-config-based override, but that might not be the case:
179 // https://www.drupal.org/node/2321071.
180 $previous_definition = $this->getBaseFieldDefinition();
183 // Some updates are always disallowed.
184 if ($this->entity_type != $this->original->entity_type) {
185 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})");
187 if ($this->bundle != $this->original->bundle) {
188 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})");
190 $previous_definition = $this->original;
192 // Notify the entity storage.
193 $this->entityManager()->getStorage($this->getTargetEntityTypeId())->onFieldDefinitionUpdate($this, $previous_definition);
199 public static function postDelete(EntityStorageInterface $storage, array $field_overrides) {
200 $entity_manager = \Drupal::entityManager();
201 // Clear the cache upfront, to refresh the results of getBundles().
202 $entity_manager->clearCachedFieldDefinitions();
203 /** @var \Drupal\Core\Field\Entity\BaseFieldOverride $field_override */
204 foreach ($field_overrides as $field_override) {
205 // Inform the system that the field definition is being updated back to
206 // its non-overridden state.
207 // @todo This assumes that there isn't a non-config-based override that
208 // we're returning to, but that might not be the case:
209 // https://www.drupal.org/node/2321071.
210 $entity_manager->getStorage($field_override->getTargetEntityTypeId())->onFieldDefinitionUpdate($field_override->getBaseFieldDefinition(), $field_override);
215 * Loads a base field bundle override config entity.
217 * @param string $entity_type_id
218 * ID of the entity type.
219 * @param string $bundle
221 * @param string $field_name
225 * The base field bundle override config entity if one exists for the
226 * provided field name, otherwise NULL.
228 public static function loadByName($entity_type_id, $bundle, $field_name) {
229 return \Drupal::entityManager()->getStorage('base_field_override')->load($entity_type_id . '.' . $bundle . '.' . $field_name);
233 * Implements the magic __sleep() method.
235 public function __sleep() {
236 // Only serialize necessary properties, excluding those that can be
238 unset($this->baseFieldDefinition);
239 return parent::__sleep();