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