--- /dev/null
+<?php
+
+namespace Drupal\node\Entity;
+
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityPublishedTrait;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\node\NodeInterface;
+use Drupal\user\UserInterface;
+
+/**
+ * Defines the node entity class.
+ *
+ * @ContentEntityType(
+ * id = "node",
+ * label = @Translation("Content"),
+ * label_collection = @Translation("Content"),
+ * label_singular = @Translation("content item"),
+ * label_plural = @Translation("content items"),
+ * label_count = @PluralTranslation(
+ * singular = "@count content item",
+ * plural = "@count content items"
+ * ),
+ * bundle_label = @Translation("Content type"),
+ * handlers = {
+ * "storage" = "Drupal\node\NodeStorage",
+ * "storage_schema" = "Drupal\node\NodeStorageSchema",
+ * "view_builder" = "Drupal\node\NodeViewBuilder",
+ * "access" = "Drupal\node\NodeAccessControlHandler",
+ * "views_data" = "Drupal\node\NodeViewsData",
+ * "form" = {
+ * "default" = "Drupal\node\NodeForm",
+ * "delete" = "Drupal\node\Form\NodeDeleteForm",
+ * "edit" = "Drupal\node\NodeForm"
+ * },
+ * "route_provider" = {
+ * "html" = "Drupal\node\Entity\NodeRouteProvider",
+ * },
+ * "list_builder" = "Drupal\node\NodeListBuilder",
+ * "translation" = "Drupal\node\NodeTranslationHandler"
+ * },
+ * base_table = "node",
+ * data_table = "node_field_data",
+ * revision_table = "node_revision",
+ * revision_data_table = "node_field_revision",
+ * show_revision_ui = TRUE,
+ * translatable = TRUE,
+ * list_cache_contexts = { "user.node_grants:view" },
+ * entity_keys = {
+ * "id" = "nid",
+ * "revision" = "vid",
+ * "bundle" = "type",
+ * "label" = "title",
+ * "langcode" = "langcode",
+ * "uuid" = "uuid",
+ * "status" = "status",
+ * "published" = "status",
+ * "uid" = "uid",
+ * },
+ * bundle_entity_type = "node_type",
+ * field_ui_base_route = "entity.node_type.edit_form",
+ * common_reference_target = TRUE,
+ * permission_granularity = "bundle",
+ * links = {
+ * "canonical" = "/node/{node}",
+ * "delete-form" = "/node/{node}/delete",
+ * "edit-form" = "/node/{node}/edit",
+ * "version-history" = "/node/{node}/revisions",
+ * "revision" = "/node/{node}/revisions/{node_revision}/view",
+ * }
+ * )
+ */
+class Node extends ContentEntityBase implements NodeInterface {
+
+ use EntityChangedTrait;
+ use EntityPublishedTrait;
+
+ /**
+ * Whether the node is being previewed or not.
+ *
+ * The variable is set to public as it will give a considerable performance
+ * improvement. See https://www.drupal.org/node/2498919.
+ *
+ * @var true|null
+ * TRUE if the node is being previewed and NULL if it is not.
+ */
+ public $in_preview = NULL;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function preSave(EntityStorageInterface $storage) {
+ parent::preSave($storage);
+
+ foreach (array_keys($this->getTranslationLanguages()) as $langcode) {
+ $translation = $this->getTranslation($langcode);
+
+ // If no owner has been set explicitly, make the anonymous user the owner.
+ if (!$translation->getOwner()) {
+ $translation->setOwnerId(0);
+ }
+ }
+
+ // If no revision author has been set explicitly, make the node owner the
+ // revision author.
+ if (!$this->getRevisionUser()) {
+ $this->setRevisionUserId($this->getOwnerId());
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
+ parent::preSaveRevision($storage, $record);
+
+ if (!$this->isNewRevision() && isset($this->original) && (!isset($record->revision_log) || $record->revision_log === '')) {
+ // If we are updating an existing node without adding a new revision, we
+ // need to make sure $entity->revision_log is reset whenever it is empty.
+ // Therefore, this code allows us to avoid clobbering an existing log
+ // entry with an empty one.
+ $record->revision_log = $this->original->revision_log->value;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+ parent::postSave($storage, $update);
+
+ // Update the node access table for this node, but only if it is the
+ // default revision. There's no need to delete existing records if the node
+ // is new.
+ if ($this->isDefaultRevision()) {
+ /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */
+ $access_control_handler = \Drupal::entityManager()->getAccessControlHandler('node');
+ $grants = $access_control_handler->acquireGrants($this);
+ \Drupal::service('node.grant_storage')->write($this, $grants, NULL, $update);
+ }
+
+ // Reindex the node when it is updated. The node is automatically indexed
+ // when it is added, simply by being added to the node table.
+ if ($update) {
+ node_reindex_node_search($this->id());
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function preDelete(EntityStorageInterface $storage, array $entities) {
+ parent::preDelete($storage, $entities);
+
+ // Ensure that all nodes deleted are removed from the search index.
+ if (\Drupal::moduleHandler()->moduleExists('search')) {
+ foreach ($entities as $entity) {
+ search_index_clear('node_search', $entity->nid->value);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function postDelete(EntityStorageInterface $storage, array $nodes) {
+ parent::postDelete($storage, $nodes);
+ \Drupal::service('node.grant_storage')->deleteNodeRecords(array_keys($nodes));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType() {
+ return $this->bundle();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
+ // This override exists to set the operation to the default value "view".
+ return parent::access($operation, $account, $return_as_object);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTitle() {
+ return $this->get('title')->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTitle($title) {
+ $this->set('title', $title);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCreatedTime() {
+ return $this->get('created')->value;
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setCreatedTime($timestamp) {
+ $this->set('created', $timestamp);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPromoted() {
+ return (bool) $this->get('promote')->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPromoted($promoted) {
+ $this->set('promote', $promoted ? NodeInterface::PROMOTED : NodeInterface::NOT_PROMOTED);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSticky() {
+ return (bool) $this->get('sticky')->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSticky($sticky) {
+ $this->set('sticky', $sticky ? NodeInterface::STICKY : NodeInterface::NOT_STICKY);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOwner() {
+ return $this->get('uid')->entity;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOwnerId() {
+ return $this->getEntityKey('uid');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setOwnerId($uid) {
+ $this->set('uid', $uid);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setOwner(UserInterface $account) {
+ $this->set('uid', $account->id());
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRevisionCreationTime() {
+ return $this->get('revision_timestamp')->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRevisionCreationTime($timestamp) {
+ $this->set('revision_timestamp', $timestamp);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRevisionAuthor() {
+ return $this->getRevisionUser();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRevisionUser() {
+ return $this->get('revision_uid')->entity;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRevisionAuthorId($uid) {
+ $this->setRevisionUserId($uid);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRevisionUser(UserInterface $user) {
+ $this->set('revision_uid', $user);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRevisionUserId() {
+ return $this->get('revision_uid')->entity->id();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRevisionUserId($user_id) {
+ $this->set('revision_uid', $user_id);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRevisionLogMessage() {
+ return $this->get('revision_log')->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRevisionLogMessage($revision_log_message) {
+ $this->set('revision_log', $revision_log_message);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+ $fields = parent::baseFieldDefinitions($entity_type);
+ $fields += static::publishedBaseFieldDefinitions($entity_type);
+
+ $fields['title'] = BaseFieldDefinition::create('string')
+ ->setLabel(t('Title'))
+ ->setRequired(TRUE)
+ ->setTranslatable(TRUE)
+ ->setRevisionable(TRUE)
+ ->setSetting('max_length', 255)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'string',
+ 'weight' => -5,
+ ])
+ ->setDisplayOptions('form', [
+ 'type' => 'string_textfield',
+ 'weight' => -5,
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['uid'] = BaseFieldDefinition::create('entity_reference')
+ ->setLabel(t('Authored by'))
+ ->setDescription(t('The username of the content author.'))
+ ->setRevisionable(TRUE)
+ ->setSetting('target_type', 'user')
+ ->setDefaultValueCallback('Drupal\node\Entity\Node::getCurrentUserId')
+ ->setTranslatable(TRUE)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'author',
+ 'weight' => 0,
+ ])
+ ->setDisplayOptions('form', [
+ 'type' => 'entity_reference_autocomplete',
+ 'weight' => 5,
+ 'settings' => [
+ 'match_operator' => 'CONTAINS',
+ 'size' => '60',
+ 'placeholder' => '',
+ ],
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['created'] = BaseFieldDefinition::create('created')
+ ->setLabel(t('Authored on'))
+ ->setDescription(t('The time that the node was created.'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'timestamp',
+ 'weight' => 0,
+ ])
+ ->setDisplayOptions('form', [
+ 'type' => 'datetime_timestamp',
+ 'weight' => 10,
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['changed'] = BaseFieldDefinition::create('changed')
+ ->setLabel(t('Changed'))
+ ->setDescription(t('The time that the node was last edited.'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE);
+
+ $fields['promote'] = BaseFieldDefinition::create('boolean')
+ ->setLabel(t('Promoted to front page'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE)
+ ->setDefaultValue(TRUE)
+ ->setDisplayOptions('form', [
+ 'type' => 'boolean_checkbox',
+ 'settings' => [
+ 'display_label' => TRUE,
+ ],
+ 'weight' => 15,
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['sticky'] = BaseFieldDefinition::create('boolean')
+ ->setLabel(t('Sticky at top of lists'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE)
+ ->setDefaultValue(FALSE)
+ ->setDisplayOptions('form', [
+ 'type' => 'boolean_checkbox',
+ 'settings' => [
+ 'display_label' => TRUE,
+ ],
+ 'weight' => 16,
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['revision_timestamp'] = BaseFieldDefinition::create('created')
+ ->setLabel(t('Revision timestamp'))
+ ->setDescription(t('The time that the current revision was created.'))
+ ->setQueryable(FALSE)
+ ->setRevisionable(TRUE);
+
+ $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference')
+ ->setLabel(t('Revision user ID'))
+ ->setDescription(t('The user ID of the author of the current revision.'))
+ ->setSetting('target_type', 'user')
+ ->setQueryable(FALSE)
+ ->setRevisionable(TRUE);
+
+ $fields['revision_log'] = BaseFieldDefinition::create('string_long')
+ ->setLabel(t('Revision log message'))
+ ->setDescription(t('Briefly describe the changes you have made.'))
+ ->setRevisionable(TRUE)
+ ->setDefaultValue('')
+ ->setDisplayOptions('form', [
+ 'type' => 'string_textarea',
+ 'weight' => 25,
+ 'settings' => [
+ 'rows' => 4,
+ ],
+ ]);
+
+ $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
+ ->setLabel(t('Revision translation affected'))
+ ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
+ ->setReadOnly(TRUE)
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE);
+
+ return $fields;
+ }
+
+ /**
+ * Default value callback for 'uid' base field definition.
+ *
+ * @see ::baseFieldDefinitions()
+ *
+ * @return array
+ * An array of default values.
+ */
+ public static function getCurrentUserId() {
+ return [\Drupal::currentUser()->id()];
+ }
+
+}