BaseFieldDefinition.php 26 KB

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