BaseFieldDefinition.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. <?php
  2. namespace Drupal\Core\Field;
  3. use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
  4. use Drupal\Core\Entity\FieldableEntityInterface;
  5. use Drupal\Core\Field\Entity\BaseFieldOverride;
  6. use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
  7. use Drupal\Core\TypedData\ListDataDefinition;
  8. use Drupal\Core\TypedData\OptionsProviderInterface;
  9. /**
  10. * A class for defining entity fields.
  11. */
  12. class BaseFieldDefinition extends ListDataDefinition implements FieldDefinitionInterface, FieldStorageDefinitionInterface, RequiredFieldStorageDefinitionInterface {
  13. use UnchangingCacheableDependencyTrait;
  14. /**
  15. * The field type.
  16. *
  17. * @var string
  18. */
  19. protected $type;
  20. /**
  21. * An array of field property definitions.
  22. *
  23. * @var \Drupal\Core\TypedData\DataDefinitionInterface[]
  24. *
  25. * @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface::getPropertyDefinitions()
  26. */
  27. protected $propertyDefinitions;
  28. /**
  29. * The field schema.
  30. *
  31. * @var array
  32. */
  33. protected $schema;
  34. /**
  35. * @var array
  36. */
  37. protected $indexes = [];
  38. /**
  39. * Creates a new field definition.
  40. *
  41. * @param string $type
  42. * The type of the field.
  43. *
  44. * @return static
  45. * A new field definition object.
  46. */
  47. public static function create($type) {
  48. $field_definition = new static([]);
  49. $field_definition->type = $type;
  50. $field_definition->itemDefinition = FieldItemDataDefinition::create($field_definition);
  51. // Create a definition for the items, and initialize it with the default
  52. // settings for the field type.
  53. $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  54. $default_settings = $field_type_manager->getDefaultStorageSettings($type) + $field_type_manager->getDefaultFieldSettings($type);
  55. $field_definition->itemDefinition->setSettings($default_settings);
  56. return $field_definition;
  57. }
  58. /**
  59. * Creates a new field definition based upon a field storage definition.
  60. *
  61. * In cases where one needs a field storage definitions to act like full
  62. * field definitions, this creates a new field definition based upon the
  63. * (limited) information available. That way it is possible to use the field
  64. * definition in places where a full field definition is required; e.g., with
  65. * widgets or formatters.
  66. *
  67. * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
  68. * The field storage definition to base the new field definition upon.
  69. *
  70. * @return $this
  71. */
  72. public static function createFromFieldStorageDefinition(FieldStorageDefinitionInterface $definition) {
  73. return static::create($definition->getType())
  74. ->setCardinality($definition->getCardinality())
  75. ->setConstraints($definition->getConstraints())
  76. ->setCustomStorage($definition->hasCustomStorage())
  77. ->setDescription($definition->getDescription())
  78. ->setLabel($definition->getLabel())
  79. ->setName($definition->getName())
  80. ->setProvider($definition->getProvider())
  81. ->setRevisionable($definition->isRevisionable())
  82. ->setSettings($definition->getSettings())
  83. ->setTargetEntityTypeId($definition->getTargetEntityTypeId())
  84. ->setTranslatable($definition->isTranslatable());
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public static function createFromItemType($item_type) {
  90. // The data type of a field item is in the form of "field_item:$field_type".
  91. $parts = explode(':', $item_type, 2);
  92. return static::create($parts[1]);
  93. }
  94. /**
  95. * {@inheritdoc}
  96. */
  97. public function getName() {
  98. return $this->definition['field_name'];
  99. }
  100. /**
  101. * Sets the field name.
  102. *
  103. * @param string $name
  104. * The field name to set.
  105. *
  106. * @return static
  107. * The object itself for chaining.
  108. */
  109. public function setName($name) {
  110. $this->definition['field_name'] = $name;
  111. return $this;
  112. }
  113. /**
  114. * {@inheritdoc}
  115. */
  116. public function getType() {
  117. return $this->type;
  118. }
  119. /**
  120. * {@inheritdoc}
  121. */
  122. public function getSettings() {
  123. return $this->getItemDefinition()->getSettings();
  124. }
  125. /**
  126. * {@inheritdoc}
  127. *
  128. * Note that the method does not unset existing settings not specified in the
  129. * incoming $settings array.
  130. *
  131. * For example:
  132. * @code
  133. * // Given these are the default settings.
  134. * $field_definition->getSettings() === [
  135. * 'fruit' => 'apple',
  136. * 'season' => 'summer',
  137. * ];
  138. * // Change only the 'fruit' setting.
  139. * $field_definition->setSettings(['fruit' => 'banana']);
  140. * // The 'season' setting persists unchanged.
  141. * $field_definition->getSettings() === [
  142. * 'fruit' => 'banana',
  143. * 'season' => 'summer',
  144. * ];
  145. * @endcode
  146. *
  147. * For clarity, it is preferred to use setSetting() if not all available
  148. * settings are supplied.
  149. */
  150. public function setSettings(array $settings) {
  151. // Assign settings individually, in order to keep the current values
  152. // of settings not specified in $settings.
  153. foreach ($settings as $setting_name => $setting) {
  154. $this->getItemDefinition()->setSetting($setting_name, $setting);
  155. }
  156. return $this;
  157. }
  158. /**
  159. * {@inheritdoc}
  160. */
  161. public function getSetting($setting_name) {
  162. return $this->getItemDefinition()->getSetting($setting_name);
  163. }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. public function setSetting($setting_name, $value) {
  168. $this->getItemDefinition()->setSetting($setting_name, $value);
  169. return $this;
  170. }
  171. /**
  172. * {@inheritdoc}
  173. */
  174. public function getProvider() {
  175. return isset($this->definition['provider']) ? $this->definition['provider'] : NULL;
  176. }
  177. /**
  178. * Sets the name of the provider of this field.
  179. *
  180. * @param string $provider
  181. * The provider name to set.
  182. *
  183. * @return $this
  184. */
  185. public function setProvider($provider) {
  186. $this->definition['provider'] = $provider;
  187. return $this;
  188. }
  189. /**
  190. * {@inheritdoc}
  191. */
  192. public function isTranslatable() {
  193. return !empty($this->definition['translatable']);
  194. }
  195. /**
  196. * Sets whether the field is translatable.
  197. *
  198. * @param bool $translatable
  199. * Whether the field is translatable.
  200. *
  201. * @return $this
  202. * The object itself for chaining.
  203. */
  204. public function setTranslatable($translatable) {
  205. $this->definition['translatable'] = $translatable;
  206. return $this;
  207. }
  208. /**
  209. * {@inheritdoc}
  210. */
  211. public function isRevisionable() {
  212. return !empty($this->definition['revisionable']);
  213. }
  214. /**
  215. * Sets whether the field is revisionable.
  216. *
  217. * @param bool $revisionable
  218. * Whether the field is revisionable.
  219. *
  220. * @return $this
  221. * The object itself for chaining.
  222. */
  223. public function setRevisionable($revisionable) {
  224. $this->definition['revisionable'] = $revisionable;
  225. return $this;
  226. }
  227. /**
  228. * {@inheritdoc}
  229. */
  230. public function getCardinality() {
  231. // @todo: Allow to control this.
  232. return isset($this->definition['cardinality']) ? $this->definition['cardinality'] : 1;
  233. }
  234. /**
  235. * Sets the maximum number of items allowed for the field.
  236. *
  237. * Possible values are positive integers or
  238. * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
  239. *
  240. * @param int $cardinality
  241. * The field cardinality.
  242. *
  243. * @return $this
  244. */
  245. public function setCardinality($cardinality) {
  246. $this->definition['cardinality'] = $cardinality;
  247. return $this;
  248. }
  249. /**
  250. * {@inheritdoc}
  251. */
  252. public function isMultiple() {
  253. $cardinality = $this->getCardinality();
  254. return ($cardinality == static::CARDINALITY_UNLIMITED) || ($cardinality > 1);
  255. }
  256. /**
  257. * {@inheritdoc}
  258. */
  259. public function isQueryable() {
  260. @trigger_error('BaseFieldDefinition::isQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::hasCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED);
  261. return !$this->hasCustomStorage();
  262. }
  263. /**
  264. * Sets whether the field is queryable.
  265. *
  266. * @param bool $queryable
  267. * Whether the field is queryable.
  268. *
  269. * @return static
  270. * The object itself for chaining.
  271. *
  272. * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use
  273. * \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage() instead.
  274. *
  275. * @see https://www.drupal.org/node/2856563
  276. */
  277. public function setQueryable($queryable) {
  278. @trigger_error('BaseFieldDefinition::setQueryable() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\Field\BaseFieldDefinition::setCustomStorage(). See https://www.drupal.org/node/2856563.', E_USER_DEPRECATED);
  279. $this->definition['queryable'] = $queryable;
  280. return $this;
  281. }
  282. /**
  283. * Sets constraints for a given field item property.
  284. *
  285. * Note: this overwrites any existing property constraints. If you need to
  286. * add to the existing constraints, use
  287. * \Drupal\Core\Field\BaseFieldDefinition::addPropertyConstraints()
  288. *
  289. * @param string $name
  290. * The name of the property to set constraints for.
  291. * @param array $constraints
  292. * The constraints to set.
  293. *
  294. * @return static
  295. * The object itself for chaining.
  296. */
  297. public function setPropertyConstraints($name, array $constraints) {
  298. $item_constraints = $this->getItemDefinition()->getConstraints();
  299. $item_constraints['ComplexData'][$name] = $constraints;
  300. $this->getItemDefinition()->setConstraints($item_constraints);
  301. return $this;
  302. }
  303. /**
  304. * Adds constraints for a given field item property.
  305. *
  306. * Adds a constraint to a property of a base field item. e.g.
  307. * @code
  308. * // Limit the field item's value property to the range 0 through 10.
  309. * // e.g. $node->size->value.
  310. * $field->addPropertyConstraints('value', [
  311. * 'Range' => [
  312. * 'min' => 0,
  313. * 'max' => 10,
  314. * ]
  315. * ]);
  316. * @endcode
  317. *
  318. * If you want to add a validation constraint that applies to the
  319. * \Drupal\Core\Field\FieldItemList, use BaseFieldDefinition::addConstraint()
  320. * instead.
  321. *
  322. * Note: passing a new set of options for an existing property constraint will
  323. * overwrite with the new options.
  324. *
  325. * @param string $name
  326. * The name of the property to set constraints for.
  327. * @param array $constraints
  328. * The constraints to set.
  329. *
  330. * @return static
  331. * The object itself for chaining.
  332. *
  333. * @see \Drupal\Core\Field\BaseFieldDefinition::addConstraint()
  334. */
  335. public function addPropertyConstraints($name, array $constraints) {
  336. $item_constraints = $this->getItemDefinition()->getConstraint('ComplexData') ?: [];
  337. if (isset($item_constraints[$name])) {
  338. // Add the new property constraints, overwriting as required.
  339. $item_constraints[$name] = $constraints + $item_constraints[$name];
  340. }
  341. else {
  342. $item_constraints[$name] = $constraints;
  343. }
  344. $this->getItemDefinition()->addConstraint('ComplexData', $item_constraints);
  345. return $this;
  346. }
  347. /**
  348. * Sets the display options for the field in forms or rendered entities.
  349. *
  350. * This enables generic rendering of the field with widgets / formatters,
  351. * including automated support for "In place editing", and with optional
  352. * configurability in the "Manage display" / "Manage form display" UI screens.
  353. *
  354. * Unless this method is called, the field remains invisible (or requires
  355. * ad-hoc rendering logic).
  356. *
  357. * @param string $display_context
  358. * The display context. Either 'view' or 'form'.
  359. * @param array $options
  360. * An array of display options. Refer to
  361. * \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for
  362. * a list of supported keys. The options should include at least a 'weight',
  363. * or specify 'type' = 'hidden'. The 'default_widget' / 'default_formatter'
  364. * for the field type will be used if no 'type' is specified.
  365. *
  366. * @return static
  367. * The object itself for chaining.
  368. */
  369. public function setDisplayOptions($display_context, array $options) {
  370. $this->definition['display'][$display_context]['options'] = $options;
  371. return $this;
  372. }
  373. /**
  374. * Sets whether the display for the field can be configured.
  375. *
  376. * @param string $display_context
  377. * The display context. Either 'view' or 'form'.
  378. * @param bool $configurable
  379. * Whether the display options can be configured (e.g., via the "Manage
  380. * display" / "Manage form display" UI screens). If TRUE, the options
  381. * specified via getDisplayOptions() act as defaults.
  382. *
  383. * @return static
  384. * The object itself for chaining.
  385. */
  386. public function setDisplayConfigurable($display_context, $configurable) {
  387. // If no explicit display options have been specified, default to 'hidden'.
  388. if (empty($this->definition['display'][$display_context])) {
  389. $this->definition['display'][$display_context]['options'] = ['region' => 'hidden'];
  390. }
  391. $this->definition['display'][$display_context]['configurable'] = $configurable;
  392. return $this;
  393. }
  394. /**
  395. * {@inheritdoc}
  396. */
  397. public function getDisplayOptions($display_context) {
  398. return isset($this->definition['display'][$display_context]['options']) ? $this->definition['display'][$display_context]['options'] : NULL;
  399. }
  400. /**
  401. * {@inheritdoc}
  402. */
  403. public function isDisplayConfigurable($display_context) {
  404. return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
  405. }
  406. /**
  407. * {@inheritdoc}
  408. */
  409. public function getDefaultValueLiteral() {
  410. return isset($this->definition['default_value']) ? $this->definition['default_value'] : [];
  411. }
  412. /**
  413. * {@inheritdoc}
  414. */
  415. public function getDefaultValueCallback() {
  416. return isset($this->definition['default_value_callback']) ? $this->definition['default_value_callback'] : NULL;
  417. }
  418. /**
  419. * {@inheritdoc}
  420. */
  421. public function getDefaultValue(FieldableEntityInterface $entity) {
  422. // Allow custom default values function.
  423. if ($callback = $this->getDefaultValueCallback()) {
  424. $value = call_user_func($callback, $entity, $this);
  425. }
  426. else {
  427. $value = $this->getDefaultValueLiteral();
  428. }
  429. // Normalize into the "array keyed by delta" format.
  430. if (isset($value) && !is_array($value)) {
  431. $properties = $this->getPropertyNames();
  432. $property = reset($properties);
  433. $value = [
  434. [$property => $value],
  435. ];
  436. }
  437. // Allow the field type to process default values.
  438. $field_item_list_class = $this->getClass();
  439. return $field_item_list_class::processDefaultValue($value, $entity, $this);
  440. }
  441. /**
  442. * {@inheritdoc}
  443. */
  444. public function setDefaultValue($value) {
  445. if ($value === NULL) {
  446. $value = [];
  447. }
  448. // Unless the value is an empty array, we may need to transform it.
  449. if (!is_array($value) || !empty($value)) {
  450. if (!is_array($value)) {
  451. $value = [[$this->getMainPropertyName() => $value]];
  452. }
  453. elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
  454. $value = [0 => $value];
  455. }
  456. }
  457. $this->definition['default_value'] = $value;
  458. return $this;
  459. }
  460. /**
  461. * {@inheritdoc}
  462. */
  463. public function setDefaultValueCallback($callback) {
  464. if (isset($callback) && !is_string($callback)) {
  465. throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
  466. }
  467. $this->definition['default_value_callback'] = $callback;
  468. return $this;
  469. }
  470. /**
  471. * Returns the initial value for the field.
  472. *
  473. * @return array
  474. * The initial value for the field, as a numerically indexed array of items,
  475. * each item being a property/value array (array() for no default value).
  476. */
  477. public function getInitialValue() {
  478. $value = isset($this->definition['initial_value']) ? $this->definition['initial_value'] : [];
  479. // Normalize into the "array keyed by delta" format.
  480. if (isset($value) && !is_array($value)) {
  481. $value = [
  482. [$this->getMainPropertyName() => $value],
  483. ];
  484. }
  485. return $value;
  486. }
  487. /**
  488. * Sets an initial value for the field.
  489. *
  490. * @param mixed $value
  491. * The initial value for the field. This can be either:
  492. * - a literal, in which case it will be assigned to the first property of
  493. * the first item;
  494. * - a numerically indexed array of items, each item being a property/value
  495. * array;
  496. * - a non-numerically indexed array, in which case the array is assumed to
  497. * be a property/value array and used as the first item;
  498. * - an empty array for no initial value.
  499. *
  500. * @return $this
  501. */
  502. public function setInitialValue($value) {
  503. // @todo Implement initial value support for multi-value fields in
  504. // https://www.drupal.org/node/2883851.
  505. if ($this->isMultiple()) {
  506. throw new FieldException('Multi-value fields can not have an initial value.');
  507. }
  508. if ($value === NULL) {
  509. $value = [];
  510. }
  511. // Unless the value is an empty array, we may need to transform it.
  512. if (!is_array($value) || !empty($value)) {
  513. if (!is_array($value)) {
  514. $value = [[$this->getMainPropertyName() => $value]];
  515. }
  516. elseif (is_array($value) && !is_numeric(array_keys($value)[0])) {
  517. $value = [0 => $value];
  518. }
  519. }
  520. $this->definition['initial_value'] = $value;
  521. return $this;
  522. }
  523. /**
  524. * Returns the name of the field that will be used for getting initial values.
  525. *
  526. * @return string|null
  527. * The field name.
  528. */
  529. public function getInitialValueFromField() {
  530. return isset($this->definition['initial_value_from_field']) ? $this->definition['initial_value_from_field'] : NULL;
  531. }
  532. /**
  533. * Sets a field that will be used for getting initial values.
  534. *
  535. * @param string $field_name
  536. * The name of the field that will be used for getting initial values.
  537. *
  538. * @return $this
  539. */
  540. public function setInitialValueFromField($field_name) {
  541. $this->definition['initial_value_from_field'] = $field_name;
  542. return $this;
  543. }
  544. /**
  545. * {@inheritdoc}
  546. */
  547. public function getOptionsProvider($property_name, FieldableEntityInterface $entity) {
  548. // If the field item class implements the interface, create an orphaned
  549. // runtime item object, so that it can be used as the options provider
  550. // without modifying the entity being worked on.
  551. if (is_subclass_of($this->getItemDefinition()->getClass(), OptionsProviderInterface::class)) {
  552. $items = $entity->get($this->getName());
  553. return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
  554. }
  555. // @todo: Allow setting custom options provider, see
  556. // https://www.drupal.org/node/2002138.
  557. }
  558. /**
  559. * {@inheritdoc}
  560. */
  561. public function getPropertyDefinition($name) {
  562. if (!isset($this->propertyDefinitions)) {
  563. $this->getPropertyDefinitions();
  564. }
  565. if (isset($this->propertyDefinitions[$name])) {
  566. return $this->propertyDefinitions[$name];
  567. }
  568. }
  569. /**
  570. * {@inheritdoc}
  571. */
  572. public function getPropertyDefinitions() {
  573. if (!isset($this->propertyDefinitions)) {
  574. $class = $this->getItemDefinition()->getClass();
  575. $this->propertyDefinitions = $class::propertyDefinitions($this);
  576. }
  577. return $this->propertyDefinitions;
  578. }
  579. /**
  580. * {@inheritdoc}
  581. */
  582. public function getPropertyNames() {
  583. return array_keys($this->getPropertyDefinitions());
  584. }
  585. /**
  586. * {@inheritdoc}
  587. */
  588. public function getMainPropertyName() {
  589. $class = $this->getItemDefinition()->getClass();
  590. return $class::mainPropertyName();
  591. }
  592. /**
  593. * Helper to retrieve the field item class.
  594. *
  595. * @deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Use
  596. * \Drupal\Core\TypedData\ListDataDefinition::getClass() instead.
  597. */
  598. protected function getFieldItemClass() {
  599. @trigger_error('BaseFieldDefinition::getFieldItemClass() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Instead, you should use \Drupal\Core\TypedData\ListDataDefinition::getClass(). See https://www.drupal.org/node/2933964.', E_USER_DEPRECATED);
  600. if ($class = $this->getItemDefinition()->getClass()) {
  601. return $class;
  602. }
  603. else {
  604. $type_definition = \Drupal::typedDataManager()
  605. ->getDefinition($this->getItemDefinition()->getDataType());
  606. return $type_definition['class'];
  607. }
  608. }
  609. /**
  610. * {@inheritdoc}
  611. */
  612. public function __sleep() {
  613. // Do not serialize the statically cached property definitions.
  614. $vars = get_object_vars($this);
  615. unset($vars['propertyDefinitions'], $vars['typedDataManager']);
  616. return array_keys($vars);
  617. }
  618. /**
  619. * {@inheritdoc}
  620. */
  621. public function getTargetEntityTypeId() {
  622. return isset($this->definition['entity_type']) ? $this->definition['entity_type'] : NULL;
  623. }
  624. /**
  625. * Sets the ID of the type of the entity this field is attached to.
  626. *
  627. * @param string $entity_type_id
  628. * The name of the target entity type to set.
  629. *
  630. * @return $this
  631. */
  632. public function setTargetEntityTypeId($entity_type_id) {
  633. $this->definition['entity_type'] = $entity_type_id;
  634. return $this;
  635. }
  636. /**
  637. * {@inheritdoc}
  638. */
  639. public function getTargetBundle() {
  640. return isset($this->definition['bundle']) ? $this->definition['bundle'] : NULL;
  641. }
  642. /**
  643. * Sets the bundle this field is defined for.
  644. *
  645. * @param string|null $bundle
  646. * The bundle, or NULL if the field is not bundle-specific.
  647. *
  648. * @return $this
  649. */
  650. public function setTargetBundle($bundle) {
  651. $this->definition['bundle'] = $bundle;
  652. return $this;
  653. }
  654. /**
  655. * {@inheritdoc}
  656. */
  657. public function getSchema() {
  658. if (!isset($this->schema)) {
  659. // Get the schema from the field item class.
  660. $definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType());
  661. $class = $definition['class'];
  662. $schema = $class::schema($this);
  663. // Fill in default values.
  664. $schema += [
  665. 'columns' => [],
  666. 'unique keys' => [],
  667. 'indexes' => [],
  668. 'foreign keys' => [],
  669. ];
  670. // Merge custom indexes with those specified by the field type. Custom
  671. // indexes prevail.
  672. $schema['indexes'] = $this->indexes + $schema['indexes'];
  673. $this->schema = $schema;
  674. }
  675. return $this->schema;
  676. }
  677. /**
  678. * {@inheritdoc}
  679. */
  680. public function getColumns() {
  681. $schema = $this->getSchema();
  682. // A typical use case for the method is to iterate on the columns, while
  683. // some other use cases rely on identifying the first column with the key()
  684. // function. Since the schema is persisted in the Field object, we take care
  685. // of resetting the array pointer so that the former does not interfere with
  686. // the latter.
  687. reset($schema['columns']);
  688. return $schema['columns'];
  689. }
  690. /**
  691. * {@inheritdoc}
  692. */
  693. public function hasCustomStorage() {
  694. return !empty($this->definition['custom_storage']) || $this->isComputed();
  695. }
  696. /**
  697. * {@inheritdoc}
  698. */
  699. public function isBaseField() {
  700. return TRUE;
  701. }
  702. /**
  703. * Sets the storage behavior for this field.
  704. *
  705. * @param bool $custom_storage
  706. * Pass FALSE if the storage takes care of storing the field,
  707. * TRUE otherwise.
  708. *
  709. * @return $this
  710. *
  711. * @throws \LogicException
  712. * Thrown if custom storage is to be set to FALSE for a computed field.
  713. */
  714. public function setCustomStorage($custom_storage) {
  715. if (!$custom_storage && $this->isComputed()) {
  716. throw new \LogicException("Entity storage cannot store a computed field.");
  717. }
  718. $this->definition['custom_storage'] = $custom_storage;
  719. return $this;
  720. }
  721. /**
  722. * {@inheritdoc}
  723. */
  724. public function getFieldStorageDefinition() {
  725. return $this;
  726. }
  727. /**
  728. * {@inheritdoc}
  729. */
  730. public function getUniqueStorageIdentifier() {
  731. return $this->getTargetEntityTypeId() . '-' . $this->getName();
  732. }
  733. /**
  734. * {@inheritdoc}
  735. */
  736. public function getUniqueIdentifier() {
  737. // If we have a specified target bundle, we're dealing with a bundle base
  738. // field definition, so we need to include it in the unique identifier.
  739. if ($this->getTargetBundle()) {
  740. return $this->getTargetEntityTypeId() . '-' . $this->getTargetBundle() . '-' . $this->getName();
  741. }
  742. return $this->getUniqueStorageIdentifier();
  743. }
  744. /**
  745. * {@inheritdoc}
  746. */
  747. public function isDeleted() {
  748. return !empty($this->definition['deleted']);
  749. }
  750. /**
  751. * Sets whether the field storage is deleted.
  752. *
  753. * @param bool $deleted
  754. * Whether the field storage is deleted.
  755. *
  756. * @return $this
  757. */
  758. public function setDeleted($deleted) {
  759. $this->definition['deleted'] = $deleted;
  760. return $this;
  761. }
  762. /**
  763. * {@inheritdoc}
  764. */
  765. public function getConfig($bundle) {
  766. $override = BaseFieldOverride::loadByName($this->getTargetEntityTypeId(), $bundle, $this->getName());
  767. if ($override) {
  768. return $override;
  769. }
  770. return BaseFieldOverride::createFromBaseFieldDefinition($this, $bundle);
  771. }
  772. /**
  773. * {@inheritdoc}
  774. */
  775. public function isStorageRequired() {
  776. if (isset($this->definition['storage_required'])) {
  777. return (bool) $this->definition['storage_required'];
  778. }
  779. // Default to the 'required' property of the base field.
  780. return $this->isRequired();
  781. }
  782. /**
  783. * Sets whether the field storage is required.
  784. *
  785. * @param bool $required
  786. * Whether the field storage is required.
  787. *
  788. * @return static
  789. * The object itself for chaining.
  790. */
  791. public function setStorageRequired($required) {
  792. $this->definition['storage_required'] = $required;
  793. return $this;
  794. }
  795. /**
  796. * Magic method: Implements a deep clone.
  797. */
  798. public function __clone() {
  799. parent::__clone();
  800. // The itemDefinition (\Drupal\Core\Field\TypedData\FieldItemDataDefinition)
  801. // has a property fieldDefinition, which is a recursive reference to the
  802. // parent BaseFieldDefinition, therefore the reference to the old object has
  803. // to be overwritten with a reference to the cloned one.
  804. $this->itemDefinition->setFieldDefinition($this);
  805. // Reset the static cache of the field property definitions in order to
  806. // ensure that the clone will reference different field property definitions
  807. // objects.
  808. $this->propertyDefinitions = NULL;
  809. }
  810. /**
  811. * {@inheritdoc}
  812. */
  813. public function isInternal() {
  814. // All fields are not internal unless explicitly set.
  815. return !empty($this->definition['internal']);
  816. }
  817. }