EntityBase.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. <?php
  2. namespace Drupal\Core\Entity;
  3. use Drupal\Core\Cache\Cache;
  4. use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
  5. use Drupal\Core\DependencyInjection\DependencySerializationTrait;
  6. use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
  7. use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
  8. use Drupal\Core\Language\Language;
  9. use Drupal\Core\Language\LanguageInterface;
  10. use Drupal\Core\Link;
  11. use Drupal\Core\Session\AccountInterface;
  12. use Drupal\Core\Url;
  13. use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
  14. use Symfony\Component\Routing\Exception\RouteNotFoundException;
  15. /**
  16. * Defines a base entity class.
  17. */
  18. abstract class EntityBase implements EntityInterface {
  19. use RefinableCacheableDependencyTrait;
  20. use DependencySerializationTrait {
  21. __sleep as traitSleep;
  22. }
  23. /**
  24. * The entity type.
  25. *
  26. * @var string
  27. */
  28. protected $entityTypeId;
  29. /**
  30. * Boolean indicating whether the entity should be forced to be new.
  31. *
  32. * @var bool
  33. */
  34. protected $enforceIsNew;
  35. /**
  36. * A typed data object wrapping this entity.
  37. *
  38. * @var \Drupal\Core\TypedData\ComplexDataInterface
  39. */
  40. protected $typedData;
  41. /**
  42. * Constructs an Entity object.
  43. *
  44. * @param array $values
  45. * An array of values to set, keyed by property name. If the entity type
  46. * has bundles, the bundle key has to be specified.
  47. * @param string $entity_type
  48. * The type of the entity to create.
  49. */
  50. public function __construct(array $values, $entity_type) {
  51. $this->entityTypeId = $entity_type;
  52. // Set initial values.
  53. foreach ($values as $key => $value) {
  54. $this->$key = $value;
  55. }
  56. }
  57. /**
  58. * Gets the entity manager.
  59. *
  60. * @return \Drupal\Core\Entity\EntityManagerInterface
  61. *
  62. * @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0.
  63. * Use \Drupal::entityTypeManager() instead in most cases. If the needed
  64. * method is not on \Drupal\Core\Entity\EntityTypeManagerInterface, see the
  65. * deprecated \Drupal\Core\Entity\EntityManager to find the
  66. * correct interface or service.
  67. */
  68. protected function entityManager() {
  69. @trigger_error('Entity::getEntityManager() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use ::getEntityTypeManager() instead. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
  70. return \Drupal::entityManager();
  71. }
  72. /**
  73. * Gets the entity type manager.
  74. *
  75. * @return \Drupal\Core\Entity\EntityTypeManagerInterface
  76. */
  77. protected function entityTypeManager() {
  78. return \Drupal::entityTypeManager();
  79. }
  80. /**
  81. * Gets the entity type bundle info service.
  82. *
  83. * @return \Drupal\Core\Entity\EntityTypeBundleInfoInterface
  84. */
  85. protected function entityTypeBundleInfo() {
  86. return \Drupal::service('entity_type.bundle.info');
  87. }
  88. /**
  89. * Gets the language manager.
  90. *
  91. * @return \Drupal\Core\Language\LanguageManagerInterface
  92. */
  93. protected function languageManager() {
  94. return \Drupal::languageManager();
  95. }
  96. /**
  97. * Gets the UUID generator.
  98. *
  99. * @return \Drupal\Component\Uuid\UuidInterface
  100. */
  101. protected function uuidGenerator() {
  102. return \Drupal::service('uuid');
  103. }
  104. /**
  105. * {@inheritdoc}
  106. */
  107. public function id() {
  108. return isset($this->id) ? $this->id : NULL;
  109. }
  110. /**
  111. * {@inheritdoc}
  112. */
  113. public function uuid() {
  114. return isset($this->uuid) ? $this->uuid : NULL;
  115. }
  116. /**
  117. * {@inheritdoc}
  118. */
  119. public function isNew() {
  120. return !empty($this->enforceIsNew) || !$this->id();
  121. }
  122. /**
  123. * {@inheritdoc}
  124. */
  125. public function enforceIsNew($value = TRUE) {
  126. $this->enforceIsNew = $value;
  127. return $this;
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function getEntityTypeId() {
  133. return $this->entityTypeId;
  134. }
  135. /**
  136. * {@inheritdoc}
  137. */
  138. public function bundle() {
  139. return $this->entityTypeId;
  140. }
  141. /**
  142. * {@inheritdoc}
  143. */
  144. public function label() {
  145. $label = NULL;
  146. $entity_type = $this->getEntityType();
  147. if (($label_callback = $entity_type->get('label_callback')) && is_callable($label_callback)) {
  148. @trigger_error('Entity type ' . $this->getEntityTypeId() . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794', E_USER_DEPRECATED);
  149. $label = call_user_func($label_callback, $this);
  150. }
  151. elseif (($label_key = $entity_type->getKey('label')) && isset($this->{$label_key})) {
  152. $label = $this->{$label_key};
  153. }
  154. return $label;
  155. }
  156. /**
  157. * {@inheritdoc}
  158. */
  159. public function urlInfo($rel = 'canonical', array $options = []) {
  160. @trigger_error('EntityInterface::urlInfo() is deprecated in Drupal 8.0.0 and will be removed in Drupal 9.0.0. EntityInterface::toUrl() instead. See https://www.drupal.org/node/2614344', E_USER_DEPRECATED);
  161. return $this->toUrl($rel, $options);
  162. }
  163. /**
  164. * {@inheritdoc}
  165. */
  166. public function toUrl($rel = 'canonical', array $options = []) {
  167. if ($this->id() === NULL) {
  168. throw new EntityMalformedException(sprintf('The "%s" entity cannot have a URI as it does not have an ID', $this->getEntityTypeId()));
  169. }
  170. // The links array might contain URI templates set in annotations.
  171. $link_templates = $this->linkTemplates();
  172. // Links pointing to the current revision point to the actual entity. So
  173. // instead of using the 'revision' link, use the 'canonical' link.
  174. if ($rel === 'revision' && $this instanceof RevisionableInterface && $this->isDefaultRevision()) {
  175. $rel = 'canonical';
  176. }
  177. if (isset($link_templates[$rel])) {
  178. $route_parameters = $this->urlRouteParameters($rel);
  179. $route_name = "entity.{$this->entityTypeId}." . str_replace(['-', 'drupal:'], ['_', ''], $rel);
  180. $uri = new Url($route_name, $route_parameters);
  181. }
  182. else {
  183. $bundle = $this->bundle();
  184. // A bundle-specific callback takes precedence over the generic one for
  185. // the entity type.
  186. $bundles = $this->entityTypeBundleInfo()->getBundleInfo($this->getEntityTypeId());
  187. if (isset($bundles[$bundle]['uri_callback'])) {
  188. $uri_callback = $bundles[$bundle]['uri_callback'];
  189. }
  190. elseif ($entity_uri_callback = $this->getEntityType()->getUriCallback()) {
  191. $uri_callback = $entity_uri_callback;
  192. }
  193. // Invoke the callback to get the URI. If there is no callback, use the
  194. // default URI format.
  195. if (isset($uri_callback) && is_callable($uri_callback)) {
  196. $uri = call_user_func($uri_callback, $this);
  197. }
  198. else {
  199. throw new UndefinedLinkTemplateException("No link template '$rel' found for the '{$this->getEntityTypeId()}' entity type");
  200. }
  201. }
  202. // Pass the entity data through as options, so that alter functions do not
  203. // need to look up this entity again.
  204. $uri
  205. ->setOption('entity_type', $this->getEntityTypeId())
  206. ->setOption('entity', $this);
  207. // Display links by default based on the current language.
  208. // Link relations that do not require an existing entity should not be
  209. // affected by this entity's language, however.
  210. if (!in_array($rel, ['collection', 'add-page', 'add-form'], TRUE)) {
  211. $options += ['language' => $this->language()];
  212. }
  213. $uri_options = $uri->getOptions();
  214. $uri_options += $options;
  215. return $uri->setOptions($uri_options);
  216. }
  217. /**
  218. * {@inheritdoc}
  219. */
  220. public function hasLinkTemplate($rel) {
  221. $link_templates = $this->linkTemplates();
  222. return isset($link_templates[$rel]);
  223. }
  224. /**
  225. * Gets an array link templates.
  226. *
  227. * @return array
  228. * An array of link templates containing paths.
  229. */
  230. protected function linkTemplates() {
  231. return $this->getEntityType()->getLinkTemplates();
  232. }
  233. /**
  234. * {@inheritdoc}
  235. */
  236. public function link($text = NULL, $rel = 'canonical', array $options = []) {
  237. @trigger_error("EntityInterface::link() is deprecated in Drupal 8.0.0 and will be removed in Drupal 9.0.0. Use EntityInterface::toLink()->toString() instead. Note, the default relationship for configuration entities changes from 'edit-form' to 'canonical'. See https://www.drupal.org/node/2614344", E_USER_DEPRECATED);
  238. return $this->toLink($text, $rel, $options)->toString();
  239. }
  240. /**
  241. * {@inheritdoc}
  242. */
  243. public function toLink($text = NULL, $rel = 'canonical', array $options = []) {
  244. if (!isset($text)) {
  245. $text = $this->label();
  246. }
  247. $url = $this->toUrl($rel);
  248. $options += $url->getOptions();
  249. $url->setOptions($options);
  250. return new Link($text, $url);
  251. }
  252. /**
  253. * {@inheritdoc}
  254. */
  255. public function url($rel = 'canonical', $options = []) {
  256. @trigger_error('EntityInterface::url() is deprecated in Drupal 8.0.0 and will be removed in Drupal 9.0.0. EntityInterface::toUrl() instead. Note, a \Drupal\Core\Url object is returned. See https://www.drupal.org/node/2614344', E_USER_DEPRECATED);
  257. // While self::toUrl() will throw an exception if the entity has no id,
  258. // the expected result for a URL is always a string.
  259. if ($this->id() === NULL || !$this->hasLinkTemplate($rel)) {
  260. return '';
  261. }
  262. $uri = $this->toUrl($rel);
  263. $options += $uri->getOptions();
  264. $uri->setOptions($options);
  265. return $uri->toString();
  266. }
  267. /**
  268. * Gets an array of placeholders for this entity.
  269. *
  270. * Individual entity classes may override this method to add additional
  271. * placeholders if desired. If so, they should be sure to replicate the
  272. * property caching logic.
  273. *
  274. * @param string $rel
  275. * The link relationship type, for example: canonical or edit-form.
  276. *
  277. * @return array
  278. * An array of URI placeholders.
  279. */
  280. protected function urlRouteParameters($rel) {
  281. $uri_route_parameters = [];
  282. if (!in_array($rel, ['collection', 'add-page', 'add-form'], TRUE)) {
  283. // The entity ID is needed as a route parameter.
  284. $uri_route_parameters[$this->getEntityTypeId()] = $this->id();
  285. }
  286. if ($rel === 'add-form' && ($this->getEntityType()->hasKey('bundle'))) {
  287. $parameter_name = $this->getEntityType()->getBundleEntityType() ?: $this->getEntityType()->getKey('bundle');
  288. $uri_route_parameters[$parameter_name] = $this->bundle();
  289. }
  290. if ($rel === 'revision' && $this instanceof RevisionableInterface) {
  291. $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
  292. }
  293. return $uri_route_parameters;
  294. }
  295. /**
  296. * {@inheritdoc}
  297. */
  298. public function uriRelationships() {
  299. return array_filter(array_keys($this->linkTemplates()), function ($link_relation_type) {
  300. // It's not guaranteed that every link relation type also has a
  301. // corresponding route. For some, additional modules or configuration may
  302. // be necessary. The interface demands that we only return supported URI
  303. // relationships.
  304. try {
  305. $this->toUrl($link_relation_type)->toString(TRUE)->getGeneratedUrl();
  306. }
  307. catch (RouteNotFoundException $e) {
  308. return FALSE;
  309. }
  310. catch (MissingMandatoryParametersException $e) {
  311. return FALSE;
  312. }
  313. return TRUE;
  314. });
  315. }
  316. /**
  317. * {@inheritdoc}
  318. */
  319. public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
  320. if ($operation == 'create') {
  321. return $this->entityTypeManager()
  322. ->getAccessControlHandler($this->entityTypeId)
  323. ->createAccess($this->bundle(), $account, [], $return_as_object);
  324. }
  325. return $this->entityTypeManager()
  326. ->getAccessControlHandler($this->entityTypeId)
  327. ->access($this, $operation, $account, $return_as_object);
  328. }
  329. /**
  330. * {@inheritdoc}
  331. */
  332. public function language() {
  333. if ($key = $this->getEntityType()->getKey('langcode')) {
  334. $langcode = $this->$key;
  335. $language = $this->languageManager()->getLanguage($langcode);
  336. if ($language) {
  337. return $language;
  338. }
  339. }
  340. // Make sure we return a proper language object.
  341. $langcode = !empty($this->langcode) ? $this->langcode : LanguageInterface::LANGCODE_NOT_SPECIFIED;
  342. $language = new Language(['id' => $langcode]);
  343. return $language;
  344. }
  345. /**
  346. * {@inheritdoc}
  347. */
  348. public function save() {
  349. $storage = $this->entityTypeManager()->getStorage($this->entityTypeId);
  350. return $storage->save($this);
  351. }
  352. /**
  353. * {@inheritdoc}
  354. */
  355. public function delete() {
  356. if (!$this->isNew()) {
  357. $this->entityTypeManager()->getStorage($this->entityTypeId)->delete([$this->id() => $this]);
  358. }
  359. }
  360. /**
  361. * {@inheritdoc}
  362. */
  363. public function createDuplicate() {
  364. $duplicate = clone $this;
  365. $entity_type = $this->getEntityType();
  366. // Reset the entity ID and indicate that this is a new entity.
  367. $duplicate->{$entity_type->getKey('id')} = NULL;
  368. $duplicate->enforceIsNew();
  369. // Check if the entity type supports UUIDs and generate a new one if so.
  370. if ($entity_type->hasKey('uuid')) {
  371. $duplicate->{$entity_type->getKey('uuid')} = $this->uuidGenerator()->generate();
  372. }
  373. return $duplicate;
  374. }
  375. /**
  376. * {@inheritdoc}
  377. */
  378. public function getEntityType() {
  379. return $this->entityTypeManager()->getDefinition($this->getEntityTypeId());
  380. }
  381. /**
  382. * {@inheritdoc}
  383. */
  384. public function preSave(EntityStorageInterface $storage) {
  385. // Check if this is an entity bundle.
  386. if ($this->getEntityType()->getBundleOf()) {
  387. // Throw an exception if the bundle ID is longer than 32 characters.
  388. if (mb_strlen($this->id()) > EntityTypeInterface::BUNDLE_MAX_LENGTH) {
  389. throw new ConfigEntityIdLengthException("Attempt to create a bundle with an ID longer than " . EntityTypeInterface::BUNDLE_MAX_LENGTH . " characters: $this->id().");
  390. }
  391. }
  392. }
  393. /**
  394. * {@inheritdoc}
  395. */
  396. public function postSave(EntityStorageInterface $storage, $update = TRUE) {
  397. $this->invalidateTagsOnSave($update);
  398. }
  399. /**
  400. * {@inheritdoc}
  401. */
  402. public static function preCreate(EntityStorageInterface $storage, array &$values) {
  403. }
  404. /**
  405. * {@inheritdoc}
  406. */
  407. public function postCreate(EntityStorageInterface $storage) {
  408. }
  409. /**
  410. * {@inheritdoc}
  411. */
  412. public static function preDelete(EntityStorageInterface $storage, array $entities) {
  413. }
  414. /**
  415. * {@inheritdoc}
  416. */
  417. public static function postDelete(EntityStorageInterface $storage, array $entities) {
  418. static::invalidateTagsOnDelete($storage->getEntityType(), $entities);
  419. }
  420. /**
  421. * {@inheritdoc}
  422. */
  423. public static function postLoad(EntityStorageInterface $storage, array &$entities) {
  424. }
  425. /**
  426. * {@inheritdoc}
  427. */
  428. public function referencedEntities() {
  429. return [];
  430. }
  431. /**
  432. * {@inheritdoc}
  433. */
  434. public function getCacheContexts() {
  435. return $this->cacheContexts;
  436. }
  437. /**
  438. * The list cache tags to invalidate for this entity.
  439. *
  440. * @return string[]
  441. * Set of list cache tags.
  442. */
  443. protected function getListCacheTagsToInvalidate() {
  444. $tags = $this->getEntityType()->getListCacheTags();
  445. if ($this->getEntityType()->hasKey('bundle')) {
  446. $tags[] = $this->getEntityTypeId() . '_list:' . $this->bundle();
  447. }
  448. return $tags;
  449. }
  450. /**
  451. * {@inheritdoc}
  452. */
  453. public function getCacheTagsToInvalidate() {
  454. if ($this->isNew()) {
  455. return [];
  456. }
  457. return [$this->entityTypeId . ':' . $this->id()];
  458. }
  459. /**
  460. * {@inheritdoc}
  461. */
  462. public function getCacheTags() {
  463. if ($this->cacheTags) {
  464. return Cache::mergeTags($this->getCacheTagsToInvalidate(), $this->cacheTags);
  465. }
  466. return $this->getCacheTagsToInvalidate();
  467. }
  468. /**
  469. * {@inheritdoc}
  470. */
  471. public function getCacheMaxAge() {
  472. return $this->cacheMaxAge;
  473. }
  474. /**
  475. * {@inheritdoc}
  476. */
  477. public static function load($id) {
  478. $entity_type_repository = \Drupal::service('entity_type.repository');
  479. $entity_type_manager = \Drupal::entityTypeManager();
  480. $storage = $entity_type_manager->getStorage($entity_type_repository->getEntityTypeFromClass(get_called_class()));
  481. return $storage->load($id);
  482. }
  483. /**
  484. * {@inheritdoc}
  485. */
  486. public static function loadMultiple(array $ids = NULL) {
  487. $entity_type_repository = \Drupal::service('entity_type.repository');
  488. $entity_type_manager = \Drupal::entityTypeManager();
  489. $storage = $entity_type_manager->getStorage($entity_type_repository->getEntityTypeFromClass(get_called_class()));
  490. return $storage->loadMultiple($ids);
  491. }
  492. /**
  493. * {@inheritdoc}
  494. */
  495. public static function create(array $values = []) {
  496. $entity_type_repository = \Drupal::service('entity_type.repository');
  497. $entity_type_manager = \Drupal::entityTypeManager();
  498. $storage = $entity_type_manager->getStorage($entity_type_repository->getEntityTypeFromClass(get_called_class()));
  499. return $storage->create($values);
  500. }
  501. /**
  502. * Invalidates an entity's cache tags upon save.
  503. *
  504. * @param bool $update
  505. * TRUE if the entity has been updated, or FALSE if it has been inserted.
  506. */
  507. protected function invalidateTagsOnSave($update) {
  508. // An entity was created or updated: invalidate its list cache tags. (An
  509. // updated entity may start to appear in a listing because it now meets that
  510. // listing's filtering requirements. A newly created entity may start to
  511. // appear in listings because it did not exist before.)
  512. $tags = $this->getListCacheTagsToInvalidate();
  513. if ($this->hasLinkTemplate('canonical')) {
  514. // Creating or updating an entity may change a cached 403 or 404 response.
  515. $tags = Cache::mergeTags($tags, ['4xx-response']);
  516. }
  517. if ($update) {
  518. // An existing entity was updated, also invalidate its unique cache tag.
  519. $tags = Cache::mergeTags($tags, $this->getCacheTagsToInvalidate());
  520. }
  521. Cache::invalidateTags($tags);
  522. }
  523. /**
  524. * Invalidates an entity's cache tags upon delete.
  525. *
  526. * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
  527. * The entity type definition.
  528. * @param \Drupal\Core\Entity\EntityInterface[] $entities
  529. * An array of entities.
  530. */
  531. protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_type, array $entities) {
  532. $tags = $entity_type->getListCacheTags();
  533. foreach ($entities as $entity) {
  534. // An entity was deleted: invalidate its own cache tag, but also its list
  535. // cache tags. (A deleted entity may cause changes in a paged list on
  536. // other pages than the one it's on. The one it's on is handled by its own
  537. // cache tag, but subsequent list pages would not be invalidated, hence we
  538. // must invalidate its list cache tags as well.)
  539. $tags = Cache::mergeTags($tags, $entity->getCacheTagsToInvalidate());
  540. $tags = Cache::mergeTags($tags, $entity->getListCacheTagsToInvalidate());
  541. }
  542. Cache::invalidateTags($tags);
  543. }
  544. /**
  545. * {@inheritdoc}
  546. */
  547. public function getOriginalId() {
  548. // By default, entities do not support renames and do not have original IDs.
  549. return NULL;
  550. }
  551. /**
  552. * {@inheritdoc}
  553. */
  554. public function setOriginalId($id) {
  555. // By default, entities do not support renames and do not have original IDs.
  556. // If the specified ID is anything except NULL, this should mark this entity
  557. // as no longer new.
  558. if ($id !== NULL) {
  559. $this->enforceIsNew(FALSE);
  560. }
  561. return $this;
  562. }
  563. /**
  564. * {@inheritdoc}
  565. */
  566. public function toArray() {
  567. return [];
  568. }
  569. /**
  570. * {@inheritdoc}
  571. */
  572. public function getTypedData() {
  573. if (!isset($this->typedData)) {
  574. $class = \Drupal::typedDataManager()->getDefinition('entity')['class'];
  575. $this->typedData = $class::createFromEntity($this);
  576. }
  577. return $this->typedData;
  578. }
  579. /**
  580. * {@inheritdoc}
  581. */
  582. public function __sleep() {
  583. $this->typedData = NULL;
  584. return $this->traitSleep();
  585. }
  586. /**
  587. * {@inheritdoc}
  588. */
  589. public function getConfigDependencyKey() {
  590. return $this->getEntityType()->getConfigDependencyKey();
  591. }
  592. /**
  593. * {@inheritdoc}
  594. */
  595. public function getConfigDependencyName() {
  596. return $this->getEntityTypeId() . ':' . $this->bundle() . ':' . $this->uuid();
  597. }
  598. /**
  599. * {@inheritdoc}
  600. */
  601. public function getConfigTarget() {
  602. // For content entities, use the UUID for the config target identifier.
  603. // This ensures that references to the target can be deployed reliably.
  604. return $this->uuid();
  605. }
  606. }