- <?php
- * @file
- * Entity controller and class for nodes.
- */
-
- * Defines the node entity class.
- */
- class Node extends Entity {
-
-
- * The node ID.
- *
- * @var integer
- */
- public $nid;
-
-
- * The node revision ID.
- *
- * @var integer
- */
- public $vid;
-
-
- * Indicates whether this is the active node revision.
- *
- * The active revision of a node is the one loaded when no specific revision
- * has been specified. Only active revisions are saved to the node table.
- *
- * @var boolean
- */
- public $is_active_revision = TRUE;
-
-
- * The node content type (bundle).
- *
- * @var string
- */
- public $type;
-
-
- * The node language code.
- *
- * @var string
- */
- public $langcode = LANGUAGE_NONE;
-
-
- * The node title.
- *
- * @var string
- */
- public $title;
-
-
- * The node owner's user ID.
- *
- * @var integer
- */
- public $uid;
-
-
- * The node published status indicator.
- *
- * Unpublished nodes are only visible to their authors and to administrators.
- * The value is either NODE_PUBLISHED or NODE_NOT_PUBLISHED.
- *
- * @var integer
- */
- public $status;
-
-
- * The node creation timestamp.
- *
- * @var integer
- */
- public $created;
-
-
- * The node modification timestamp.
- *
- * @var integer
- */
- public $changed;
-
-
- * The timestamp at which this content should be automatically published.
- *
- * @var integer
- */
- public $scheduled;
-
-
- * The node comment status indicator.
- *
- * COMMENT_NODE_HIDDEN => no comments
- * COMMENT_NODE_CLOSED => comments are read-only
- * COMMENT_NODE_OPEN => open (read/write)
- *
- * @var integer
- */
- public $comment;
-
-
- * The node promotion status.
- *
- * Promoted nodes should be displayed on the home page of the site. The
- * value is either NODE_PROMOTED or NODE_NOT_PROMOTED.
- *
- * @var integer
- */
- public $promote;
-
-
- * The node sticky status.
- *
- * Sticky nodes should be displayed at the top of lists in which they appear.
- * The value is either NODE_STICKY or NODE_NOT_STICKY.
- *
- * @var integer
- */
- public $sticky;
-
-
- * The node translation set ID.
- *
- * Translations sets are based on the ID of the node containing the source
- * text for the translation set.
- *
- * @var integer
- */
- public $tnid;
-
-
- * The node translation status.
- *
- * If the translation page needs to be updated the value is 1, otherwise 0.
- *
- * @var integer
- */
- public $translate;
-
-
- * The node revision creation timestamp.
- *
- * @var integer
- */
- public $revision_timestamp;
-
-
- * The node revision author's user ID.
- *
- * @var integer
- */
- public $revision_uid;
-
-
- * The node preview status.
- *
- * @var boolean
- *
- * @since 1.11.0
- */
- public $in_preview;
-
-
-
- * Create a new Node instance.
- */
- function __construct(array $values = array()) {
- parent::__construct($values);
-
-
- if (empty($this->created)) {
- $this->created = REQUEST_TIME;
- }
- }
-
-
- * Implements EntityInterface::id().
- */
- public function id() {
- return isset($this->nid) ? $this->nid : NULL;
- }
-
-
- * Implements EntityInterface::entityType().
- */
- public function entityType() {
- return 'node';
- }
-
-
- * Implements EntityInterface::bundle().
- */
- public function bundle() {
- return $this->type;
- }
-
-
- * Implements EntityInterface::label().
- */
- public function label() {
- return $this->title;
- }
-
-
- * Implements EntityInterface::uri().
- */
- public function uri() {
- return array(
- 'path' => 'node/' . $this->nid,
- 'options' => array(),
- );
- }
-
-
- * Overrides Entity::createAccess().
- */
- public static function createAccess($bundle = NULL, $account = NULL) {
- $rights = &backdrop_static('node_access', array());
-
-
- if (empty($account)) {
- $account = $GLOBALS['user'];
- }
-
-
-
- if (isset($rights[$account->uid][$bundle])) {
- return $rights[$account->uid][$bundle];
- }
-
- if (user_access('bypass node access', $account)) {
- $rights[$account->uid][$bundle] = TRUE;
- return $rights[$account->uid][$bundle];
- }
- if (!user_access('access content', $account)) {
- $rights[$account->uid][$bundle] = FALSE;
- return $rights[$account->uid][$bundle];
- }
-
-
-
-
-
-
- $access = module_invoke_all('node_access', $bundle, 'create', $account);
- if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
- $rights[$account->uid][$bundle] = FALSE;
- return $rights[$account->uid][$bundle];
- }
- elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
- $rights[$account->uid][$bundle] = TRUE;
- return $rights[$account->uid][$bundle];
- }
-
- $rights[$account->uid][$bundle] = FALSE;
- return $rights[$account->uid][$bundle];
- }
-
-
- * Overrides Entity::access().
- *
- * @param string $op
- * The operation to be performed on the node. Possible values are:
- * - create
- * - view
- * - update
- * - delete
- * @param User|AnonymousUser|object $account
- * (optional) The user to check for. Leave it to NULL to check for the
- * global user.
- *
- * @return bool|NULL
- * TRUE if access is granted, FALSE otherwise.
- */
- public function access($op, $account = NULL) {
-
-
- $rights = &backdrop_static('node_access', array());
-
- if ($op == 'create') {
- return self::createAccess($this->bundle(), $account);
- }
- elseif (!in_array($op, array('view', 'update', 'delete'), TRUE)) {
-
- return FALSE;
- }
-
- if (empty($account)) {
- $account = $GLOBALS['user'];
- }
-
- $cid = $this->id();
-
-
-
- if (isset($rights[$account->uid][$cid][$op])) {
- return $rights[$account->uid][$cid][$op];
- }
-
- if (user_access('bypass node access', $account)) {
- $rights[$account->uid][$cid][$op] = TRUE;
- return $rights[$account->uid][$cid][$op];
- }
- if (!user_access('access content', $account)) {
- $rights[$account->uid][$cid][$op] = FALSE;
- return $rights[$account->uid][$cid][$op];
- }
-
-
-
-
-
-
- $access = module_invoke_all('node_access', $this, $op, $account);
- if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
- $rights[$account->uid][$cid][$op] = FALSE;
- return $rights[$account->uid][$cid][$op];
- }
- elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
- $rights[$account->uid][$cid][$op] = TRUE;
- return $rights[$account->uid][$cid][$op];
- }
-
-
- if ($op == 'view' && !$this->status && user_access('view any unpublished content', $account) && $account->uid != 0) {
- $rights[$account->uid][$cid][$op] = TRUE;
- return $rights[$account->uid][$cid][$op];
- }
-
-
- if ($op == 'view' && !$this->status && user_access('view own unpublished content', $account) && $account->uid == $this->uid && $account->uid != 0) {
- $rights[$account->uid][$cid][$op] = TRUE;
- return $rights[$account->uid][$cid][$op];
- }
-
-
-
- if ($this->id()) {
- if (module_implements('node_grants')) {
- $query = db_select('node_access');
- $query->addExpression('1');
- $query->condition('grant_' . $op, 1, '>=');
- $nids = db_or()->condition('nid', $this->id());
- if ($this->status) {
- $nids->condition('nid', 0);
- }
- $query->condition($nids);
- $query->range(0, 1);
-
- $grants = db_or();
- foreach (node_access_grants($op, $account) as $realm => $gids) {
- foreach ($gids as $gid) {
- $grants->condition(db_and()
- ->condition('gid', $gid)
- ->condition('realm', $realm)
- );
- }
- }
- if (count($grants) > 0) {
- $query->condition($grants);
- }
- $result = (bool) $query
- ->execute()
- ->fetchField();
- $rights[$account->uid][$cid][$op] = $result;
- return $rights[$account->uid][$cid][$op];
- }
- elseif ($op == 'view' && $this->status) {
-
-
- $rights[$account->uid][$cid][$op] = TRUE;
- return $rights[$account->uid][$cid][$op];
- }
- }
-
- $rights[$account->uid][$cid][$op] = FALSE;
- return $rights[$account->uid][$cid][$op];
- }
-
-
- * Overrides Entity::createDuplicate().
- */
- public function createDuplicate() {
- $duplicate = clone $this;
- $duplicate->nid = NULL;
- $duplicate->vid = NULL;
- return $duplicate;
- }
-
-
- * Overrides Backdrop\entity\Entity::getRevisionId().
- */
- public function getRevisionId() {
- return $this->vid;
- }
- }
-
-
- * Controller class for nodes.
- *
- * This extends the EntityDatabaseStorageController class, adding required
- * special handling for node entities.
- */
- class NodeStorageController extends EntityDatabaseStorageController {
-
-
- * Overrides EntityDatabaseStorageController::delete().
- */
- public function delete($ids) {
- $entities = $ids ? $this->load($ids) : FALSE;
- if (!$entities) {
-
- return;
- }
- $transaction = db_transaction();
-
- try {
- $this->preDelete($entities);
- foreach ($entities as $id => $entity) {
- $this->invokeHook('predelete', $entity);
- }
- $ids = array_keys($entities);
-
- db_delete($this->entityInfo['base table'])
- ->condition($this->idKey, $ids, 'IN')
- ->execute();
-
- if ($this->revisionKey) {
- db_delete($this->revisionTable)
- ->condition($this->idKey, $ids, 'IN')
- ->execute();
- }
-
-
- $this->resetCache($ids);
-
- $this->postDelete($entities);
- foreach ($entities as $id => $entity) {
- $this->invokeHook('delete', $entity);
- }
-
- db_ignore_replica();
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception($this->entityType, $e);
- throw new EntityStorageException($e->getMessage(), (int) $e->getCode(), $e);
- }
- }
-
-
- * Overrides EntityDatabaseStorageController::save().
- *
- * @param Node $entity
- * The node entity being saved.
- */
- public function save(EntityInterface $entity) {
- $transaction = db_transaction();
- try {
-
- if (!$entity->isNew() && !isset($entity->original)) {
- $entity->original = entity_load_unchanged($this->entityType, $entity->id());
- }
-
- $this->preSave($entity);
- $this->invokeHook('presave', $entity);
-
- if ($entity->isNew()) {
- $op = 'insert';
- $return = backdrop_write_record($this->entityInfo['base table'], $entity);
- unset($entity->is_new);
- }
- else {
- $op = 'update';
-
-
- if ($entity->isActiveRevision()) {
- $return = backdrop_write_record($this->entityInfo['base table'], $entity, $this->idKey);
- }
- else {
- $return = SAVED_UPDATED;
- }
- }
-
- if ($this->revisionKey) {
- $this->saveRevision($entity);
- }
-
-
- if ($op == 'update') {
- $this->resetCache(array($entity->{$this->idKey}));
- }
-
- $this->postSave($entity, $op == 'update');
- $this->invokeHook($op, $entity);
-
-
- db_ignore_replica();
- unset($entity->original);
-
- return $return;
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception($this->entityType, $e);
- throw new EntityStorageException($e->getMessage(), (int) $e->getCode(), $e);
- }
- }
-
-
- * Saves a node revision.
- *
- * @param Node $entity
- * The node entity whose revision should be saved.
- */
- protected function saveRevision(EntityInterface $entity) {
- $record = clone $entity;
- $record->uid = $entity->revision_uid;
- $record->timestamp = $entity->revision_timestamp;
-
- if (empty($entity->{$this->revisionKey}) || !empty($entity->revision)) {
- backdrop_write_record($this->revisionTable, $record);
-
-
- if ($entity->isActiveRevision()) {
- db_update($this->entityInfo['base table'])
- ->fields(array($this->revisionKey => $record->{$this->revisionKey}))
- ->condition($this->idKey, $entity->{$this->idKey})
- ->execute();
- }
- }
- else {
- backdrop_write_record($this->revisionTable, $record, $this->revisionKey);
- }
-
- $entity->{$this->revisionKey} = $record->{$this->revisionKey};
- }
-
-
- * Overrides DefaultEntityController::attachLoad().
- *
- * @param Node[] $nodes
- * An array of nodes on which fields should be attached.
- */
- protected function attachLoad(&$nodes, $revision_id = FALSE) {
-
-
- $typed_nodes = array();
- foreach ($nodes as $id => $entity) {
- $typed_nodes[$entity->type][$id] = $entity;
- }
-
-
- foreach ($typed_nodes as $node_type => $nodes_of_type) {
- if (node_hook($node_type, 'load')) {
- $function = node_type_get_base($node_type) . '_load';
- $function($nodes_of_type);
- }
- }
-
-
- $argument = array_keys($typed_nodes);
- $this->hookLoadArguments = array($argument);
- parent::attachLoad($nodes, $revision_id);
- }
-
-
- * Overrides DefaultEntityController::buildQuery().
- */
- protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
-
-
- $query = parent::buildQuery($ids, $conditions, $revision_id);
- $fields =& $query->getFields();
- unset($fields['timestamp']);
- $query->addField('revision', 'timestamp', 'revision_timestamp');
- $fields['uid']['table'] = 'base';
- $query->addField('revision', 'uid', 'revision_uid');
- return $query;
- }
-
-
- * Overrides EntityDatabaseStorageController::invokeHook().
- *
- * @param string $hook
- * One of 'presave', 'insert', 'update', 'predelete', or 'delete'.
- * @param Node $node
- * The entity object, always a Node object in this case.
- */
- protected function invokeHook($hook, EntityInterface $node) {
- if ($hook == 'insert' || $hook == 'update') {
- node_invoke($node, $hook);
- }
- elseif ($hook == 'predelete') {
-
-
- node_invoke($node, 'delete');
- }
-
- parent::invokeHook($hook, $node);
-
- if ($hook == 'presave') {
- if ($node->isNew() || !empty($node->revision)) {
-
-
-
-
-
-
-
-
- if (!isset($node->log)) {
- $node->log = '';
- }
- }
- elseif (!isset($node->log) || $node->log === '') {
-
-
-
-
-
-
- unset($node->log);
- }
-
-
-
-
- if (!$node->isNew() && !empty($node->revision) && $node->vid) {
- $node->old_vid = $node->vid;
- $node->vid = NULL;
- }
- }
- }
-
-
- * Overrides EntityDatabaseStorageController::preSave().
- *
- * @param Node $node
- * The node object about to be saved.
- */
- protected function preSave(EntityInterface $node) {
-
- $node->changed = REQUEST_TIME;
-
- if ($this->revisionKey && !empty($node->revision)) {
- $node->revision_timestamp = REQUEST_TIME;
-
- if (!isset($node->revision_uid)) {
- $node->revision_uid = $GLOBALS['user']->uid;
- }
- }
- }
-
-
- * Overrides EntityDatabaseStorageController::postSave().
- *
- * @param Node $node
- * The node object that has just been saved.
- */
- function postSave(EntityInterface $node, $update) {
-
-
-
- if ($node->isActiveRevision()) {
- node_access_acquire_grants($node, $update);
- }
- }
-
-
- * Overrides EntityDatabaseStorageController::preDelete().
- *
- * @param Node[] $entities
- * An array of node entities about to be deleted.
- */
- function preDelete($nodes) {
- if (module_exists('search')) {
- foreach ($nodes as $nid => $node) {
- search_reindex($node->nid, 'node');
- }
- }
- }
-
-
- * Overrides EntityDatabaseStorageController::postDelete().
- *
- * @param Node[] $nodes
- * An array of node entities that have just been deleted.
- */
- protected function postDelete($nodes) {
-
- $ids = array_keys($nodes);
-
- db_delete('history')
- ->condition('nid', $ids, 'IN')
- ->execute();
- db_delete('node_access')
- ->condition('nid', $ids, 'IN')
- ->execute();
- }
-
-
- * Implements EntityControllerInterface::buildContent().
- */
- public function buildContent(EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
- global $language_content;
- $langcode = $langcode ? $langcode : $language_content->langcode;
-
-
- $node->content = array();
-
-
- $view_mode = key(entity_view_mode_prepare('node', array($node->nid => $node), $view_mode, $langcode));
-
-
-
- if (node_hook($node, 'view')) {
- $node = node_invoke($node, 'view', $view_mode, $langcode);
- }
-
-
-
-
-
- field_attach_prepare_view('node', array($node->nid => $node), $view_mode, $langcode);
- entity_prepare_view('node', array($node->nid => $node));
- $node->content += field_attach_view('node', $node, $view_mode, $langcode);
-
-
-
- $links = array();
- $node->content['links'] = array(
- '#theme' => 'links__node',
- '#pre_render' => array('backdrop_pre_render_links'),
- '#attributes' => array('class' => array('links', 'inline')),
- );
- if ($view_mode == 'teaser') {
- $type = node_type_get_type($node);
-
- if (!($type->settings['hidden_path'] && !user_access('view hidden paths'))) {
- $node_title_stripped = strip_tags($node->title);
- $links['node-readmore'] = array(
- 'title' => t('Read more<span class="element-invisible"> about @title</span>', array('@title' => $node_title_stripped)),
- 'href' => 'node/' . $node->nid,
- 'html' => TRUE,
- 'attributes' => array('rel' => 'tag', 'title' => $node_title_stripped),
- );
- }
- }
- $node->content['links']['node'] = array(
- '#theme' => 'links__node__node',
- '#links' => $links,
- '#attributes' => array('class' => array('links', 'inline')),
- );
-
-
- module_invoke_all('node_view', $node, $view_mode, $langcode);
- module_invoke_all('entity_view', $node, 'node', $view_mode, $langcode);
-
-
-
- $node->content += array('#view_mode' => $view_mode);
- }
-
-
- * Overrides DefaultEntityController::view().
- */
- public function view($nodes, $view_mode = 'full', $langcode = NULL, $page = NULL) {
- global $language_content;
- $langcode = $langcode ? $langcode : $language_content->langcode;
-
- $view = array();
- foreach ($nodes as $node) {
-
- if (isset($node->preview) && ($node->preview == 'Preview')) {
- backdrop_set_message(t('This is a preview. Links within the page are disabled.'), 'warning', FALSE);
- backdrop_set_message(t('<strong>Changes are stored temporarily</strong>. Click <em>Save</em> to make your changes permanent, or click <em>Back to content editing</em> to make additional changes.'), 'warning', FALSE);
- }
-
-
- $this->buildContent($node, $view_mode, $langcode);
-
- $build = $node->content;
-
- unset($node->content);
-
- $build += array(
- '#theme' => 'node',
- '#node' => $node,
- '#view_mode' => $view_mode,
- '#langcode' => $langcode,
- '#page' => $page,
- );
-
-
-
-
-
- if (!empty($node->nid) && !($view_mode == 'full' && node_is_page($node))) {
- $build['#contextual_links']['node'] = array('node', array($node->nid));
- }
-
-
- $type = 'node';
- backdrop_alter(array('node_view', 'entity_view'), $build, $type);
- $view[$type][$node->id()] = $build;
- }
-
- return $view;
- }
- }