PageRenderTime 26ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/core/modules/node/src/Entity/Node.php

http://github.com/drupal/drupal
PHP | 397 lines | 196 code | 40 blank | 161 comment | 9 complexity | cf6efd1ae8b35ed3c555e8952900dda0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. namespace Drupal\node\Entity;
  3. use Drupal\Core\Entity\EditorialContentEntityBase;
  4. use Drupal\Core\Entity\EntityStorageInterface;
  5. use Drupal\Core\Entity\EntityTypeInterface;
  6. use Drupal\Core\Field\BaseFieldDefinition;
  7. use Drupal\Core\Session\AccountInterface;
  8. use Drupal\node\NodeInterface;
  9. use Drupal\user\EntityOwnerTrait;
  10. /**
  11. * Defines the node entity class.
  12. *
  13. * @ContentEntityType(
  14. * id = "node",
  15. * label = @Translation("Content"),
  16. * label_collection = @Translation("Content"),
  17. * label_singular = @Translation("content item"),
  18. * label_plural = @Translation("content items"),
  19. * label_count = @PluralTranslation(
  20. * singular = "@count content item",
  21. * plural = "@count content items"
  22. * ),
  23. * bundle_label = @Translation("Content type"),
  24. * handlers = {
  25. * "storage" = "Drupal\node\NodeStorage",
  26. * "storage_schema" = "Drupal\node\NodeStorageSchema",
  27. * "view_builder" = "Drupal\node\NodeViewBuilder",
  28. * "access" = "Drupal\node\NodeAccessControlHandler",
  29. * "views_data" = "Drupal\node\NodeViewsData",
  30. * "form" = {
  31. * "default" = "Drupal\node\NodeForm",
  32. * "delete" = "Drupal\node\Form\NodeDeleteForm",
  33. * "edit" = "Drupal\node\NodeForm",
  34. * "delete-multiple-confirm" = "Drupal\node\Form\DeleteMultiple"
  35. * },
  36. * "route_provider" = {
  37. * "html" = "Drupal\node\Entity\NodeRouteProvider",
  38. * },
  39. * "list_builder" = "Drupal\node\NodeListBuilder",
  40. * "translation" = "Drupal\node\NodeTranslationHandler"
  41. * },
  42. * base_table = "node",
  43. * data_table = "node_field_data",
  44. * revision_table = "node_revision",
  45. * revision_data_table = "node_field_revision",
  46. * show_revision_ui = TRUE,
  47. * translatable = TRUE,
  48. * list_cache_contexts = { "user.node_grants:view" },
  49. * entity_keys = {
  50. * "id" = "nid",
  51. * "revision" = "vid",
  52. * "bundle" = "type",
  53. * "label" = "title",
  54. * "langcode" = "langcode",
  55. * "uuid" = "uuid",
  56. * "status" = "status",
  57. * "published" = "status",
  58. * "uid" = "uid",
  59. * "owner" = "uid",
  60. * },
  61. * revision_metadata_keys = {
  62. * "revision_user" = "revision_uid",
  63. * "revision_created" = "revision_timestamp",
  64. * "revision_log_message" = "revision_log"
  65. * },
  66. * bundle_entity_type = "node_type",
  67. * field_ui_base_route = "entity.node_type.edit_form",
  68. * common_reference_target = TRUE,
  69. * permission_granularity = "bundle",
  70. * links = {
  71. * "canonical" = "/node/{node}",
  72. * "delete-form" = "/node/{node}/delete",
  73. * "delete-multiple-form" = "/admin/content/node/delete",
  74. * "edit-form" = "/node/{node}/edit",
  75. * "version-history" = "/node/{node}/revisions",
  76. * "revision" = "/node/{node}/revisions/{node_revision}/view",
  77. * "create" = "/node",
  78. * }
  79. * )
  80. */
  81. class Node extends EditorialContentEntityBase implements NodeInterface {
  82. use EntityOwnerTrait;
  83. /**
  84. * Whether the node is being previewed or not.
  85. *
  86. * The variable is set to public as it will give a considerable performance
  87. * improvement. See https://www.drupal.org/node/2498919.
  88. *
  89. * @var true|null
  90. * TRUE if the node is being previewed and NULL if it is not.
  91. */
  92. public $in_preview = NULL;
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function preSave(EntityStorageInterface $storage) {
  97. parent::preSave($storage);
  98. foreach (array_keys($this->getTranslationLanguages()) as $langcode) {
  99. $translation = $this->getTranslation($langcode);
  100. // If no owner has been set explicitly, make the anonymous user the owner.
  101. if (!$translation->getOwner()) {
  102. $translation->setOwnerId(0);
  103. }
  104. }
  105. // If no revision author has been set explicitly, make the node owner the
  106. // revision author.
  107. if (!$this->getRevisionUser()) {
  108. $this->setRevisionUserId($this->getOwnerId());
  109. }
  110. }
  111. /**
  112. * {@inheritdoc}
  113. */
  114. public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
  115. parent::preSaveRevision($storage, $record);
  116. if (!$this->isNewRevision() && isset($this->original) && (!isset($record->revision_log) || $record->revision_log === '')) {
  117. // If we are updating an existing node without adding a new revision, we
  118. // need to make sure $entity->revision_log is reset whenever it is empty.
  119. // Therefore, this code allows us to avoid clobbering an existing log
  120. // entry with an empty one.
  121. $record->revision_log = $this->original->revision_log->value;
  122. }
  123. }
  124. /**
  125. * {@inheritdoc}
  126. */
  127. public function postSave(EntityStorageInterface $storage, $update = TRUE) {
  128. parent::postSave($storage, $update);
  129. // Update the node access table for this node, but only if it is the
  130. // default revision. There's no need to delete existing records if the node
  131. // is new.
  132. if ($this->isDefaultRevision()) {
  133. /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */
  134. $access_control_handler = \Drupal::entityTypeManager()->getAccessControlHandler('node');
  135. $grants = $access_control_handler->acquireGrants($this);
  136. \Drupal::service('node.grant_storage')->write($this, $grants, NULL, $update);
  137. }
  138. // Reindex the node when it is updated. The node is automatically indexed
  139. // when it is added, simply by being added to the node table.
  140. if ($update) {
  141. node_reindex_node_search($this->id());
  142. }
  143. }
  144. /**
  145. * {@inheritdoc}
  146. */
  147. public static function preDelete(EntityStorageInterface $storage, array $entities) {
  148. parent::preDelete($storage, $entities);
  149. // Ensure that all nodes deleted are removed from the search index.
  150. if (\Drupal::hasService('search.index')) {
  151. /** @var \Drupal\search\SearchIndexInterface $search_index */
  152. $search_index = \Drupal::service('search.index');
  153. foreach ($entities as $entity) {
  154. $search_index->clear('node_search', $entity->nid->value);
  155. }
  156. }
  157. }
  158. /**
  159. * {@inheritdoc}
  160. */
  161. public static function postDelete(EntityStorageInterface $storage, array $nodes) {
  162. parent::postDelete($storage, $nodes);
  163. \Drupal::service('node.grant_storage')->deleteNodeRecords(array_keys($nodes));
  164. }
  165. /**
  166. * {@inheritdoc}
  167. */
  168. public function getType() {
  169. return $this->bundle();
  170. }
  171. /**
  172. * {@inheritdoc}
  173. */
  174. public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
  175. // This override exists to set the operation to the default value "view".
  176. return parent::access($operation, $account, $return_as_object);
  177. }
  178. /**
  179. * {@inheritdoc}
  180. */
  181. public function getTitle() {
  182. return $this->get('title')->value;
  183. }
  184. /**
  185. * {@inheritdoc}
  186. */
  187. public function setTitle($title) {
  188. $this->set('title', $title);
  189. return $this;
  190. }
  191. /**
  192. * {@inheritdoc}
  193. */
  194. public function getCreatedTime() {
  195. return $this->get('created')->value;
  196. }
  197. /**
  198. * {@inheritdoc}
  199. */
  200. public function setCreatedTime($timestamp) {
  201. $this->set('created', $timestamp);
  202. return $this;
  203. }
  204. /**
  205. * {@inheritdoc}
  206. */
  207. public function isPromoted() {
  208. return (bool) $this->get('promote')->value;
  209. }
  210. /**
  211. * {@inheritdoc}
  212. */
  213. public function setPromoted($promoted) {
  214. $this->set('promote', $promoted ? NodeInterface::PROMOTED : NodeInterface::NOT_PROMOTED);
  215. return $this;
  216. }
  217. /**
  218. * {@inheritdoc}
  219. */
  220. public function isSticky() {
  221. return (bool) $this->get('sticky')->value;
  222. }
  223. /**
  224. * {@inheritdoc}
  225. */
  226. public function setSticky($sticky) {
  227. $this->set('sticky', $sticky ? NodeInterface::STICKY : NodeInterface::NOT_STICKY);
  228. return $this;
  229. }
  230. /**
  231. * {@inheritdoc}
  232. */
  233. public function getRevisionAuthor() {
  234. @trigger_error(__NAMESPACE__ . '\Node::getRevisionAuthor is deprecated in drupal:8.2.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Entity\RevisionLogInterface::getRevisionUser() instead. See https://www.drupal.org/node/3069750', E_USER_DEPRECATED);
  235. return $this->getRevisionUser();
  236. }
  237. /**
  238. * {@inheritdoc}
  239. */
  240. public function setRevisionAuthorId($uid) {
  241. @trigger_error(__NAMESPACE__ . '\Node::setRevisionAuthorId is deprecated in drupal:8.2.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Entity\RevisionLogInterface::setRevisionUserId() instead. See https://www.drupal.org/node/3069750', E_USER_DEPRECATED);
  242. return $this->setRevisionUserId($uid);
  243. }
  244. /**
  245. * {@inheritdoc}
  246. */
  247. public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
  248. $fields = parent::baseFieldDefinitions($entity_type);
  249. $fields += static::ownerBaseFieldDefinitions($entity_type);
  250. $fields['title'] = BaseFieldDefinition::create('string')
  251. ->setLabel(t('Title'))
  252. ->setRequired(TRUE)
  253. ->setTranslatable(TRUE)
  254. ->setRevisionable(TRUE)
  255. ->setSetting('max_length', 255)
  256. ->setDisplayOptions('view', [
  257. 'label' => 'hidden',
  258. 'type' => 'string',
  259. 'weight' => -5,
  260. ])
  261. ->setDisplayOptions('form', [
  262. 'type' => 'string_textfield',
  263. 'weight' => -5,
  264. ])
  265. ->setDisplayConfigurable('form', TRUE);
  266. $fields['uid']
  267. ->setLabel(t('Authored by'))
  268. ->setDescription(t('The username of the content author.'))
  269. ->setRevisionable(TRUE)
  270. ->setDisplayOptions('view', [
  271. 'label' => 'hidden',
  272. 'type' => 'author',
  273. 'weight' => 0,
  274. ])
  275. ->setDisplayOptions('form', [
  276. 'type' => 'entity_reference_autocomplete',
  277. 'weight' => 5,
  278. 'settings' => [
  279. 'match_operator' => 'CONTAINS',
  280. 'size' => '60',
  281. 'placeholder' => '',
  282. ],
  283. ])
  284. ->setDisplayConfigurable('form', TRUE);
  285. $fields['status']
  286. ->setDisplayOptions('form', [
  287. 'type' => 'boolean_checkbox',
  288. 'settings' => [
  289. 'display_label' => TRUE,
  290. ],
  291. 'weight' => 120,
  292. ])
  293. ->setDisplayConfigurable('form', TRUE);
  294. $fields['created'] = BaseFieldDefinition::create('created')
  295. ->setLabel(t('Authored on'))
  296. ->setDescription(t('The time that the node was created.'))
  297. ->setRevisionable(TRUE)
  298. ->setTranslatable(TRUE)
  299. ->setDisplayOptions('view', [
  300. 'label' => 'hidden',
  301. 'type' => 'timestamp',
  302. 'weight' => 0,
  303. ])
  304. ->setDisplayOptions('form', [
  305. 'type' => 'datetime_timestamp',
  306. 'weight' => 10,
  307. ])
  308. ->setDisplayConfigurable('form', TRUE);
  309. $fields['changed'] = BaseFieldDefinition::create('changed')
  310. ->setLabel(t('Changed'))
  311. ->setDescription(t('The time that the node was last edited.'))
  312. ->setRevisionable(TRUE)
  313. ->setTranslatable(TRUE);
  314. $fields['promote'] = BaseFieldDefinition::create('boolean')
  315. ->setLabel(t('Promoted to front page'))
  316. ->setRevisionable(TRUE)
  317. ->setTranslatable(TRUE)
  318. ->setDefaultValue(TRUE)
  319. ->setDisplayOptions('form', [
  320. 'type' => 'boolean_checkbox',
  321. 'settings' => [
  322. 'display_label' => TRUE,
  323. ],
  324. 'weight' => 15,
  325. ])
  326. ->setDisplayConfigurable('form', TRUE);
  327. $fields['sticky'] = BaseFieldDefinition::create('boolean')
  328. ->setLabel(t('Sticky at top of lists'))
  329. ->setRevisionable(TRUE)
  330. ->setTranslatable(TRUE)
  331. ->setDefaultValue(FALSE)
  332. ->setDisplayOptions('form', [
  333. 'type' => 'boolean_checkbox',
  334. 'settings' => [
  335. 'display_label' => TRUE,
  336. ],
  337. 'weight' => 16,
  338. ])
  339. ->setDisplayConfigurable('form', TRUE);
  340. return $fields;
  341. }
  342. /**
  343. * Default value callback for 'uid' base field definition.
  344. *
  345. * @see ::baseFieldDefinitions()
  346. *
  347. * @deprecated The ::getCurrentUserId method is deprecated in 8.6.x and will
  348. * be removed before 9.0.0.
  349. *
  350. * @return array
  351. * An array of default values.
  352. */
  353. public static function getCurrentUserId() {
  354. @trigger_error('The ::getCurrentUserId method is deprecated in 8.6.x and will be removed before 9.0.0.', E_USER_DEPRECATED);
  355. return [\Drupal::currentUser()->id()];
  356. }
  357. }