BaseFieldOverride.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. namespace Drupal\Core\Field\Entity;
  3. use Drupal\Core\Entity\EntityStorageInterface;
  4. use Drupal\Core\Field\BaseFieldDefinition;
  5. use Drupal\Core\Field\FieldConfigBase;
  6. use Drupal\Core\Field\FieldException;
  7. /**
  8. * Defines the base field override entity.
  9. *
  10. * Allows base fields to be overridden on the bundle level.
  11. *
  12. * @ConfigEntityType(
  13. * id = "base_field_override",
  14. * label = @Translation("Base field override"),
  15. * handlers = {
  16. * "storage" = "Drupal\Core\Field\BaseFieldOverrideStorage",
  17. * "access" = "Drupal\Core\Field\BaseFieldOverrideAccessControlHandler",
  18. * },
  19. * config_prefix = "base_field_override",
  20. * entity_keys = {
  21. * "id" = "id",
  22. * "label" = "label"
  23. * },
  24. * config_export = {
  25. * "id",
  26. * "field_name",
  27. * "entity_type",
  28. * "bundle",
  29. * "label",
  30. * "description",
  31. * "required",
  32. * "translatable",
  33. * "default_value",
  34. * "default_value_callback",
  35. * "settings",
  36. * "field_type",
  37. * }
  38. * )
  39. */
  40. class BaseFieldOverride extends FieldConfigBase {
  41. /**
  42. * The base field definition.
  43. *
  44. * @var \Drupal\Core\Field\BaseFieldDefinition
  45. */
  46. protected $baseFieldDefinition;
  47. /**
  48. * Creates a base field override object.
  49. *
  50. * @param \Drupal\Core\Field\BaseFieldDefinition $base_field_definition
  51. * The base field definition to override.
  52. * @param string $bundle
  53. * The bundle to which the override applies.
  54. *
  55. * @return \Drupal\Core\Field\Entity\BaseFieldOverride
  56. * A new base field override object.
  57. */
  58. public static function createFromBaseFieldDefinition(BaseFieldDefinition $base_field_definition, $bundle) {
  59. $values = $base_field_definition->toArray();
  60. $values['bundle'] = $bundle;
  61. $values['baseFieldDefinition'] = $base_field_definition;
  62. return \Drupal::entityManager()->getStorage('base_field_override')->create($values);
  63. }
  64. /**
  65. * Constructs a BaseFieldOverride object.
  66. *
  67. * In most cases, base field override entities are created via
  68. * BaseFieldOverride::createFromBaseFieldDefinition($definition, 'bundle')
  69. *
  70. * @param array $values
  71. * An array of base field bundle override properties, keyed by property
  72. * name. The field to override is specified by referring to an existing
  73. * field with:
  74. * - field_name: The field name.
  75. * - entity_type: The entity type.
  76. * Additionally, a 'bundle' property is required to indicate the entity
  77. * bundle to which the bundle field override is attached to. Other array
  78. * elements will be used to set the corresponding properties on the class;
  79. * see the class property documentation for details.
  80. * @param string $entity_type
  81. * (optional) The type of the entity to create. Defaults to
  82. * 'base_field_override'.
  83. *
  84. * @see entity_create()
  85. *
  86. * @throws \Drupal\Core\Field\FieldException
  87. * Exception thrown if $values does not contain a field_name, entity_type or
  88. * bundle value.
  89. */
  90. public function __construct(array $values, $entity_type = 'base_field_override') {
  91. if (empty($values['field_name'])) {
  92. throw new FieldException('Attempt to create a base field bundle override of a field without a field_name');
  93. }
  94. if (empty($values['entity_type'])) {
  95. throw new FieldException("Attempt to create a base field bundle override of field {$values['field_name']} without an entity_type");
  96. }
  97. if (empty($values['bundle'])) {
  98. throw new FieldException("Attempt to create a base field bundle override of field {$values['field_name']} without a bundle");
  99. }
  100. parent::__construct($values, $entity_type);
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function getFieldStorageDefinition() {
  106. return $this->getBaseFieldDefinition()->getFieldStorageDefinition();
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function isDisplayConfigurable($context) {
  112. return $this->getBaseFieldDefinition()->isDisplayConfigurable($context);
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function getDisplayOptions($display_context) {
  118. return $this->getBaseFieldDefinition()->getDisplayOptions($display_context);
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function isReadOnly() {
  124. return $this->getBaseFieldDefinition()->isReadOnly();
  125. }
  126. /**
  127. * {@inheritdoc}
  128. */
  129. public function isComputed() {
  130. return $this->getBaseFieldDefinition()->isComputed();
  131. }
  132. /**
  133. * {@inheritdoc}
  134. */
  135. public function getClass() {
  136. return $this->getBaseFieldDefinition()->getClass();
  137. }
  138. /**
  139. * {@inheritdoc}
  140. */
  141. public function getUniqueIdentifier() {
  142. return $this->getBaseFieldDefinition()->getUniqueIdentifier();
  143. }
  144. /**
  145. * Gets the base field definition.
  146. *
  147. * @return \Drupal\Core\Field\BaseFieldDefinition
  148. */
  149. protected function getBaseFieldDefinition() {
  150. if (!isset($this->baseFieldDefinition)) {
  151. $fields = $this->entityManager()->getBaseFieldDefinitions($this->entity_type);
  152. $this->baseFieldDefinition = $fields[$this->getName()];
  153. }
  154. return $this->baseFieldDefinition;
  155. }
  156. /**
  157. * {@inheritdoc}
  158. *
  159. * @throws \Drupal\Core\Field\FieldException
  160. * If the bundle is being changed.
  161. */
  162. public function preSave(EntityStorageInterface $storage) {
  163. // Filter out unknown settings and make sure all settings are present, so
  164. // that a complete field definition is passed to the various hooks and
  165. // written to config.
  166. $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  167. $default_settings = $field_type_manager->getDefaultFieldSettings($this->getType());
  168. $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
  169. // Call the parent's presave method to perform validate and calculate
  170. // dependencies.
  171. parent::preSave($storage);
  172. if ($this->isNew()) {
  173. // @todo This assumes that the previous definition isn't some
  174. // non-config-based override, but that might not be the case:
  175. // https://www.drupal.org/node/2321071.
  176. $previous_definition = $this->getBaseFieldDefinition();
  177. }
  178. else {
  179. // Some updates are always disallowed.
  180. if ($this->entity_type != $this->original->entity_type) {
  181. 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})");
  182. }
  183. if ($this->bundle != $this->original->bundle) {
  184. 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})");
  185. }
  186. $previous_definition = $this->original;
  187. }
  188. // Notify the entity storage.
  189. $this->entityManager()->getStorage($this->getTargetEntityTypeId())->onFieldDefinitionUpdate($this, $previous_definition);
  190. }
  191. /**
  192. * {@inheritdoc}
  193. */
  194. public static function postDelete(EntityStorageInterface $storage, array $field_overrides) {
  195. $entity_manager = \Drupal::entityManager();
  196. // Clear the cache upfront, to refresh the results of getBundles().
  197. $entity_manager->clearCachedFieldDefinitions();
  198. /** @var \Drupal\Core\Field\Entity\BaseFieldOverride $field_override */
  199. foreach ($field_overrides as $field_override) {
  200. // Inform the system that the field definition is being updated back to
  201. // its non-overridden state.
  202. // @todo This assumes that there isn't a non-config-based override that
  203. // we're returning to, but that might not be the case:
  204. // https://www.drupal.org/node/2321071.
  205. $entity_manager->getStorage($field_override->getTargetEntityTypeId())->onFieldDefinitionUpdate($field_override->getBaseFieldDefinition(), $field_override);
  206. }
  207. }
  208. /**
  209. * Loads a base field bundle override config entity.
  210. *
  211. * @param string $entity_type_id
  212. * ID of the entity type.
  213. * @param string $bundle
  214. * Bundle name.
  215. * @param string $field_name
  216. * Name of the field.
  217. *
  218. * @return static
  219. * The base field bundle override config entity if one exists for the
  220. * provided field name, otherwise NULL.
  221. */
  222. public static function loadByName($entity_type_id, $bundle, $field_name) {
  223. return \Drupal::entityManager()->getStorage('base_field_override')->load($entity_type_id . '.' . $bundle . '.' . $field_name);
  224. }
  225. /**
  226. * Implements the magic __sleep() method.
  227. */
  228. public function __sleep() {
  229. // Only serialize necessary properties, excluding those that can be
  230. // recalculated.
  231. unset($this->baseFieldDefinition);
  232. return parent::__sleep();
  233. }
  234. }