diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php index e8998f8..4ccf8da 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php @@ -154,7 +154,7 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { // Map the loaded stdclass records into entity objects and according fields. $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision); - // Attach fields. + // Activate backward-compatibility mode to attach fields. if ($this->entityInfo['fieldable']) { // Prepare BC compatible entities before passing them to the field API. $bc_entities = array(); @@ -270,6 +270,9 @@ protected function attachPropertyData(array &$entities, $load_revision = FALSE) public function save(EntityInterface $entity) { $transaction = db_transaction(); try { + // Ensure we are dealing with the actual entity. + $entity = $entity->getOriginalEntity(); + // Load the stored entity, if any. if (!$entity->isNew() && !isset($entity->original)) { $entity->original = entity_load_unchanged($this->entityType, $entity->id()); @@ -279,7 +282,7 @@ public function save(EntityInterface $entity) { $this->invokeHook('presave', $entity); // Create the storage record to be saved. - $record = $this->maptoStorageRecord($entity); + $record = $this->mapToStorageRecord($entity); if (!$entity->isNew()) { if ($entity->isDefaultRevision()) { @@ -446,7 +449,9 @@ protected function mapToStorageRecord(EntityInterface $entity) { protected function mapToRevisionStorageRecord(EntityInterface $entity) { $record = new \stdClass(); foreach ($this->entityInfo['schema_fields_sql']['revision_table'] as $name) { - $record->$name = $entity->$name->value; + if (isset($entity->$name->value)) { + $record->$name = $entity->$name->value; + } } return $record; } @@ -489,6 +494,11 @@ public function delete(array $entities) { $transaction = db_transaction(); try { + // Ensure we are dealing with the actual entities. + foreach ($entities as $id => $entity) { + $entities[$id] = $entity->getOriginalEntity(); + } + $this->preDelete($entities); foreach ($entities as $id => $entity) { $this->invokeHook('predelete', $entity); diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php index 7e941a9..8ca2915 100644 --- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php +++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php @@ -46,13 +46,43 @@ class EntityBCDecorator implements IteratorAggregate, EntityInterface { protected $decorated; /** + * Local cache for field definitions. + * + * @var array + */ + protected $definitions; + + /** + * The plain data values of the decorated entity fields. + * + * @var array + */ + protected $values; + + /** + * The array of fields, each being an instance of FieldInterface. + * + * @var array + */ + protected $fields; + + /** * Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object. * * @param \Drupal\Core\Entity\EntityInterface $decorated * The decorated entity. - */ - function __construct(EntityNG $decorated) { + * @param array + * An array of field definitions. + * @param array + * The plain data values of the decorated entity fields. + * @param array + * The array of fields, each being an instance of FieldInterface. + */ + function __construct(EntityNG $decorated, array &$definitions, array &$values, array &$fields) { $this->decorated = $decorated; + $this->definitions = &$definitions; + $this->values = &$values; + $this->fields = &$fields; } /** @@ -75,6 +105,11 @@ public function getBCEntity() { * Directly accesses the plain field values, as done in Drupal 7. */ public function &__get($name) { + // Directly return the original property. + if ($name == 'original') { + return $this->values[$name]; + } + // We access the protected 'values' and 'fields' properties of the decorated // entity via the magic getter - which returns them by reference for us. We // do so, as providing references to these arrays would make $entity->values @@ -83,34 +118,53 @@ public function &__get($name) { // on the variable is problematic in conjunction with the magic // getter/setter). - if (!empty($this->decorated->fields[$name])) { + if (!empty($this->fields[$name])) { // Any field value set via the new Entity Field API will be stored inside // the field objects managed by the entity, thus we need to ensure - // $this->decorated->values reflects the latest values first. - foreach ($this->decorated->fields[$name] as $langcode => $field) { - $this->decorated->values[$name][$langcode] = $field->getValue(); + // $this->values reflects the latest values first. + foreach ($this->fields[$name] as $langcode => $field) { + if (!$this->fields[$name][$langcode]->isEmpty()) { + $this->values[$name][$langcode] = $field->getValue(); + } + else { + $this->values[$name][$langcode] = array(); + } } // The returned values might be changed by reference, so we need to remove // the field object to avoid the field object and the value getting out of // sync. That way, the next field object instantiated by EntityNG will // receive the possibly updated value. - unset($this->decorated->fields[$name]); + unset($this->fields[$name]); } - // Allow accessing field values in entity default language other than - // LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT. This is - // necessary as EntityNG does key values in default language always with - // LANGUAGE_DEFAULT while field API expects them to be keyed by langcode. - $langcode = $this->decorated->language()->langcode; - if ($langcode != LANGUAGE_DEFAULT && isset($this->decorated->values[$name]) && is_array($this->decorated->values[$name])) { - if (isset($this->decorated->values[$name][LANGUAGE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) { - $this->decorated->values[$name][$langcode] = &$this->decorated->values[$name][LANGUAGE_DEFAULT]; + // When accessing values for entity properties that have been converted to + // an entity field, provide direct access to the plain value. This makes it + // possible to use the BC-decorator with properties; e.g., $node->title. + if (isset($this->definitions[$name]) && empty($this->definitions[$name]['configurable'])) { + if (!isset($this->values[$name][LANGUAGE_DEFAULT])) { + $this->values[$name][LANGUAGE_DEFAULT][0]['value'] = NULL; + } + $value = $this->values[$name][LANGUAGE_DEFAULT]; + if (is_array($value)) { + $value = !empty($value[0]) ? reset($value[0]) : NULL; } + return $value; } - - if (!isset($this->decorated->values[$name])) { - $this->decorated->values[$name] = NULL; + else { + // Allow accessing field values in entity default language other than + // LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT. This is + // necessary as EntityNG does key values in default language always with + // LANGUAGE_DEFAULT while field API expects them to be keyed by langcode. + $langcode = $this->decorated->language()->langcode; + if ($langcode != LANGUAGE_DEFAULT && isset($this->values[$name]) && is_array($this->values[$name])) { + if (isset($this->values[$name][LANGUAGE_DEFAULT]) && !isset($this->values[$name][$langcode])) { + $this->values[$name][$langcode] = &$this->values[$name][LANGUAGE_DEFAULT]; + } + } + if (!isset($this->values[$name])) { + $this->values[$name] = NULL; + } + return $this->values[$name]; } - return $this->decorated->values[$name]; } /** @@ -119,24 +173,33 @@ public function &__get($name) { * Directly writes to the plain field values, as done by Drupal 7. */ public function __set($name, $value) { - if (is_array($value) && $definition = $this->decorated->getPropertyDefinition($name)) { - // If field API sets a value with a langcode in entity language, move it - // to LANGUAGE_DEFAULT. - // This is necessary as EntityNG does key values in default language always - // with LANGUAGE_DEFAULT while field API expects them to be keyed by - // langcode. - foreach ($value as $langcode => $data) { - if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) { - $value[LANGUAGE_DEFAULT] = $data; - unset($value[$langcode]); + $defined = isset($this->definitions[$name]); + // When updating values for entity properties that have been converted to + // an entity field, directly write to the plain value. This makes it + // possible to use the BC-decorator with properties; e.g., $node->title. + if ($defined && empty($this->definitions[$name]['configurable'])) { + $this->values[$name][LANGUAGE_DEFAULT] = $value; + } + else { + if ($defined && is_array($value)) { + // If field API sets a value with a langcode in entity language, move it + // to LANGUAGE_DEFAULT. + // This is necessary as EntityNG does key values in default language always + // with LANGUAGE_DEFAULT while field API expects them to be keyed by + // langcode. + foreach ($value as $langcode => $data) { + if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) { + $value[LANGUAGE_DEFAULT] = $data; + unset($value[$langcode]); + } } } + $this->values[$name] = $value; } - $this->decorated->values[$name] = $value; // Remove the field object to avoid the field object and the value getting // out of sync. That way, the next field object instantiated by EntityNG // will hold the updated value. - unset($this->decorated->fields[$name]); + unset($this->fields[$name]); } /** diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 8763f6d..894740d 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -367,7 +367,8 @@ public function translations() { */ public function getBCEntity() { if (!isset($this->bcEntity)) { - $this->bcEntity = new EntityBCDecorator($this); + $this->getPropertyDefinitions(); + $this->bcEntity = new EntityBCDecorator($this, $this->fieldDefinitions, $this->values, $this->fields); } return $this->bcEntity; } @@ -408,11 +409,6 @@ public function &__get($name) { $return = $this->getTranslatedField($name, LANGUAGE_DEFAULT); return $return; } - // Allow the EntityBCDecorator to directly access the values and fields. - // @todo: Remove once the EntityBCDecorator gets removed. - if ($name == 'values' || $name == 'fields') { - return $this->$name; - } // Else directly read/write plain values. That way, non-field entity // properties can always be accessed directly. if (!isset($this->values[$name])) { @@ -483,6 +479,12 @@ public function createDuplicate() { $uuid = new Uuid(); $duplicate->{$entity_info['entity_keys']['uuid']}->value = $uuid->generate(); } + + // Check whether the entity type supports revisions and initialize it if so. + if (!empty($entity_info['entity_keys']['revision'])) { + $duplicate->{$entity_info['entity_keys']['revision']}->value = NULL; + } + return $duplicate; } @@ -516,4 +518,5 @@ public function label($langcode = NULL) { } return $label; } + } diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc index d112180..2be14c7 100644 --- a/core/modules/book/book.admin.inc +++ b/core/modules/book/book.admin.inc @@ -5,7 +5,7 @@ * Administration page callbacks for the Book module. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Page callback: Returns an administrative overview of all books. @@ -101,7 +101,7 @@ function book_admin_settings_submit($form, &$form_state) { /** * Form constructor for administering a single book's hierarchy. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node of the top-level page in the book. * * @see book_menu() @@ -109,7 +109,7 @@ function book_admin_settings_submit($form, &$form_state) { * @see book_admin_edit_submit() * @ingroup forms */ -function book_admin_edit($form, $form_state, Node $node) { +function book_admin_edit($form, $form_state, EntityInterface $node) { drupal_set_title($node->label()); $form['#node'] = $node; _book_admin_table($node, $form); @@ -182,14 +182,14 @@ function book_admin_edit_submit($form, &$form_state) { /** * Builds the table portion of the form for the book administration page. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node of the top-level page in the book. * @param $form * The form that is being modified, passed by reference. * * @see book_admin_edit() */ -function _book_admin_table(Node $node, &$form) { +function _book_admin_table(EntityInterface $node, &$form) { $form['table'] = array( '#theme' => 'book_admin_table', '#tree' => TRUE, diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 653ba54..2709fa7 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -5,7 +5,7 @@ * Allows users to create and organize related content in an outline. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; use Drupal\Core\Template\Attribute; @@ -87,12 +87,12 @@ function book_permission() { /** * Adds relevant book links to the node's links. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The book page node to add links to. * @param $view_mode * The view mode of the node. */ -function book_node_view_link(Node $node, $view_mode) { +function book_node_view_link(EntityInterface $node, $view_mode) { $links = array(); if (isset($node->book['depth'])) { @@ -199,10 +199,10 @@ function book_menu() { /** * Access callback: Determines if the book export page is accessible. * - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\node\Plugin\Core\Entity\EntityInterface $node * The node whose export page is to be viewed. */ -function book_export_access(Node $node) { +function book_export_access(EntityInterface $node) { return user_access('access printer-friendly version') && node_access('view', $node); } @@ -213,24 +213,24 @@ function book_export_access(Node $node) { * - admin/content/book/%node * - node/%node/outline * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node whose outline tab is to be viewed. * * @see book_menu() */ -function _book_outline_access(Node $node) { +function _book_outline_access(EntityInterface $node) { return user_access('administer book outlines') && node_access('view', $node); } /** * Access callback: Determines if the user can remove nodes from the outline. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to remove from the outline. * * @see book_menu() */ -function _book_outline_remove_access(Node $node) { +function _book_outline_remove_access(EntityInterface $node) { return _book_node_is_removable($node) && _book_outline_access($node); } @@ -240,7 +240,7 @@ function _book_outline_remove_access(Node $node) { * A node can be removed from a book if it is actually in a book and it either * is not a top-level page or is a top-level page with no children. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to remove from the outline. */ function _book_node_is_removable($node) { @@ -420,10 +420,10 @@ function _book_parent_select($book_link) { /** * Builds the common elements of the book form for the node and outline forms. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node whose form is being viewed. */ -function _book_add_form_elements(&$form, &$form_state, Node $node) { +function _book_add_form_elements(&$form, &$form_state, EntityInterface $node) { // If the form is being processed during the Ajax callback of our book bid // dropdown, then $form_state will hold the value that was selected. if (isset($form_state['values']['book'])) { @@ -523,13 +523,13 @@ function book_form_update($form, $form_state) { * outline through node addition, node editing, node deletion, or the outline * tab. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being saved, added, deleted, or moved. * * @return * TRUE if the menu link was saved; FALSE otherwise. */ -function _book_update_outline(Node $node) { +function _book_update_outline(EntityInterface $node) { if (empty($node->book['bid'])) { return FALSE; } @@ -787,7 +787,7 @@ function book_node_load($nodes, $types) { /** * Implements hook_node_view(). */ -function book_node_view(Node $node, EntityDisplay $display, $view_mode) { +function book_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { if ($view_mode == 'full') { if (!empty($node->book['bid']) && empty($node->in_preview)) { $node->content['book_navigation'] = array( @@ -819,7 +819,7 @@ function book_page_alter(&$page) { /** * Implements hook_node_presave(). */ -function book_node_presave(Node $node) { +function book_node_presave(EntityInterface $node) { // Always save a revision for non-administrators. if (!empty($node->book['bid']) && !user_access('administer nodes')) { $node->setNewRevision(); @@ -833,7 +833,7 @@ function book_node_presave(Node $node) { /** * Implements hook_node_insert(). */ -function book_node_insert(Node $node) { +function book_node_insert(EntityInterface $node) { if (!empty($node->book['bid'])) { if ($node->book['bid'] == 'new') { // New nodes that are their own book. @@ -848,7 +848,7 @@ function book_node_insert(Node $node) { /** * Implements hook_node_update(). */ -function book_node_update(Node $node) { +function book_node_update(EntityInterface $node) { if (!empty($node->book['bid'])) { if ($node->book['bid'] == 'new') { // New nodes that are their own book. @@ -863,7 +863,7 @@ function book_node_update(Node $node) { /** * Implements hook_node_predelete(). */ -function book_node_predelete(Node $node) { +function book_node_predelete(EntityInterface $node) { if (!empty($node->book['bid'])) { if ($node->nid == $node->book['bid']) { // Handle deletion of a top-level post. @@ -887,7 +887,7 @@ function book_node_predelete(Node $node) { /** * Implements hook_node_prepare(). */ -function book_node_prepare(Node $node) { +function book_node_prepare(EntityInterface $node) { // Prepare defaults for the add/edit form. if (empty($node->book) && (user_access('add content to books') || user_access('administer book outlines'))) { $node->book = array(); @@ -1183,7 +1183,7 @@ function book_export_traverse($tree, $visit_func) { /** * Generates printer-friendly HTML for a node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that will be output. * @param $children * (optional) All the rendered child nodes within the current node. Defaults @@ -1194,7 +1194,7 @@ function book_export_traverse($tree, $visit_func) { * * @see book_export_traverse() */ -function book_node_export(Node $node, $children = '') { +function book_node_export(EntityInterface $node, $children = '') { $build = node_view($node, 'print'); unset($build['#theme']); // @todo Rendering should happen in the template using render(). diff --git a/core/modules/book/book.pages.inc b/core/modules/book/book.pages.inc index a971aa6..2418591 100644 --- a/core/modules/book/book.pages.inc +++ b/core/modules/book/book.pages.inc @@ -5,7 +5,7 @@ * User page callbacks for the book module. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -39,7 +39,7 @@ function book_render() { * currently supported in book module: * - html: Printer-friendly HTML. * Other types may be supported in contributed modules. - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\node\Plugin\Core\Entity\EntityInterface $node * The node to export. * * @return @@ -50,7 +50,7 @@ function book_render() { * * @see book_menu() */ -function book_export($type, Node $node) { +function book_export($type, EntityInterface $node) { $type = drupal_strtolower($type); $export_function = 'book_export_' . $type; @@ -84,7 +84,7 @@ function book_export($type, Node $node) { * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ -function book_export_html(Node $node) { +function book_export_html(EntityInterface $node) { if (user_access('access printer-friendly version')) { if (isset($node->book)) { $tree = book_menu_subtree_data($node->book); @@ -103,7 +103,7 @@ function book_export_html(Node $node) { /** * Page callback: Shows the outline form for a single node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The book node for which to show the outline. * * @return string @@ -111,7 +111,7 @@ function book_export_html(Node $node) { * * @see book_menu() */ -function book_outline(Node $node) { +function book_outline(EntityInterface $node) { drupal_set_title($node->label()); return drupal_get_form('book_outline_form', $node); } @@ -121,14 +121,14 @@ function book_outline(Node $node) { * * Allows handling of all book outline operations via the outline tab. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The book node for which to show the outline. * * @see book_outline_form_submit() * @see book_remove_button_submit() * @ingroup forms */ -function book_outline_form($form, &$form_state, Node $node) { +function book_outline_form($form, &$form_state, EntityInterface $node) { if (!isset($node->book)) { // The node is not part of any book yet - set default options. $node->book = _book_link_defaults($node->nid); @@ -208,14 +208,14 @@ function book_outline_form_submit($form, &$form_state) { /** * Form constructor to confirm removal of a node from a book. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to delete. * * @see book_remove_form_submit() * @see book_menu() * @ingroup forms */ -function book_remove_form($form, &$form_state, Node $node) { +function book_remove_form($form, &$form_state, EntityInterface $node) { $form['#node'] = $node; $title = array('%title' => $node->label()); diff --git a/core/modules/book/lib/Drupal/book/Tests/BookTest.php b/core/modules/book/lib/Drupal/book/Tests/BookTest.php index 2bc08b8..210066a 100644 --- a/core/modules/book/lib/Drupal/book/Tests/BookTest.php +++ b/core/modules/book/lib/Drupal/book/Tests/BookTest.php @@ -7,7 +7,7 @@ namespace Drupal\book\Tests; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\simpletest\WebTestBase; /** @@ -145,7 +145,7 @@ function testBook() { * * Also checks the printer friendly version of the outline. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * Node to check. * @param $nodes * Nodes that should be in outline. @@ -158,7 +158,7 @@ function testBook() { * @param array $breadcrumb * The nodes that should be displayed in the breadcrumb. */ - function checkBookNode(Node $node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) { + function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) { // $number does not use drupal_static as it should not be reset // since it uniquely identifies each call to checkBookNode(). static $number = 0; diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 6f2795a..29aedc0 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -9,7 +9,6 @@ * book page, etc. */ -use Drupal\node\Plugin\Core\Entity\Node; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; use Drupal\file\Plugin\Core\Entity\File; use Drupal\Core\Entity\EntityInterface; @@ -494,13 +493,13 @@ function comment_get_recent($number = 10) { * Number of comments. * @param $new_replies * Number of new replies. - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The first new comment node. * * @return * "page=X" if the page number is greater than zero; empty string otherwise. */ -function comment_new_page_count($num_comments, $new_replies, Node $node) { +function comment_new_page_count($num_comments, $new_replies, EntityInterface $node) { $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED); $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50); $pagenum = NULL; @@ -578,7 +577,7 @@ function theme_comment_block($variables) { /** * Implements hook_node_view(). */ -function comment_node_view(Node $node, EntityDisplay $display, $view_mode) { +function comment_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { $links = array(); if ($node->comment != COMMENT_NODE_HIDDEN) { @@ -686,14 +685,14 @@ function comment_node_view(Node $node, EntityDisplay $display, $view_mode) { /** * Builds the comment-related elements for node detail pages. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity for which to build the comment-related elements. * * @return * A renderable array representing the comment-related page elements for the * node. */ -function comment_node_page_additions(Node $node) { +function comment_node_page_additions(EntityInterface $node) { $additions = array(); // Only attempt to render comments if the node has visible comments. @@ -731,7 +730,7 @@ function comment_node_page_additions(Node $node) { /** * Returns a rendered form to comment the given node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity to be commented. * @param int $pid * (optional) Some comments are replies to other comments. In those cases, @@ -740,7 +739,7 @@ function comment_node_page_additions(Node $node) { * @return array * The renderable array for the comment addition form. */ -function comment_add(Node $node, $pid = NULL) { +function comment_add(EntityInterface $node, $pid = NULL) { $values = array('nid' => $node->nid, 'pid' => $pid, 'node_type' => 'comment_node_' . $node->type); $comment = entity_create('comment', $values); return entity_get_form($comment); @@ -749,7 +748,7 @@ function comment_add(Node $node, $pid = NULL) { /** * Retrieves comments for a thread. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node whose comment(s) needs rendering. * @param $mode * The comment display mode; COMMENT_MODE_FLAT or COMMENT_MODE_THREADED. @@ -813,7 +812,7 @@ function comment_add(Node $node, $pid = NULL) { * spoil the reverse ordering, "ORDER BY thread ASC" -- here, we do not need * to consider the trailing "/" so we use a substring only. */ -function comment_get_thread(Node $node, $mode, $comments_per_page) { +function comment_get_thread(EntityInterface $node, $mode, $comments_per_page) { $query = db_select('comment', 'c') ->extend('Drupal\Core\Database\Query\PagerSelectExtender'); $query->addField('c', 'cid'); @@ -923,13 +922,13 @@ function comment_view(Comment $comment, $view_mode = 'full', $langcode = NULL) { * * @param Drupal\comment\Comment $comment * The comment object. - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node the comment is attached to. * * @return * A structured array of links. */ -function comment_links(Comment $comment, Node $node) { +function comment_links(Comment $comment, EntityInterface $node) { $links = array(); if ($node->comment == COMMENT_NODE_OPEN) { if (user_access('administer comments') && user_access('post comments')) { @@ -1203,7 +1202,7 @@ function comment_node_load($nodes, $types) { /** * Implements hook_node_prepare(). */ -function comment_node_prepare(Node $node) { +function comment_node_prepare(EntityInterface $node) { if (!isset($node->comment)) { $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN); } @@ -1212,7 +1211,7 @@ function comment_node_prepare(Node $node) { /** * Implements hook_node_insert(). */ -function comment_node_insert(Node $node) { +function comment_node_insert(EntityInterface $node) { // Allow bulk updates and inserts to temporarily disable the // maintenance of the {node_comment_statistics} table. if (variable_get('comment_maintain_node_statistics', TRUE)) { @@ -1232,7 +1231,7 @@ function comment_node_insert(Node $node) { /** * Implements hook_node_predelete(). */ -function comment_node_predelete(Node $node) { +function comment_node_predelete(EntityInterface $node) { $cids = db_query('SELECT cid FROM {comment} WHERE nid = :nid', array(':nid' => $node->nid))->fetchCol(); comment_delete_multiple($cids); db_delete('node_comment_statistics') @@ -1243,7 +1242,7 @@ function comment_node_predelete(Node $node) { /** * Implements hook_node_update_index(). */ -function comment_node_update_index(Node $node, $langcode) { +function comment_node_update_index(EntityInterface $node, $langcode) { $index_comments = &drupal_static(__FUNCTION__); if ($index_comments === NULL) { @@ -1292,7 +1291,7 @@ function comment_update_index() { * Formats a comment count string and returns it, for display with search * results. */ -function comment_node_search_result(Node $node) { +function comment_node_search_result(EntityInterface $node) { // Do not make a string if comments are hidden. if (user_access('access comments') && $node->comment != COMMENT_NODE_HIDDEN) { $comments = db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array('nid' => $node->nid))->fetchField(); diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc index da359a4..be4ef3f 100644 --- a/core/modules/comment/comment.pages.inc +++ b/core/modules/comment/comment.pages.inc @@ -5,7 +5,7 @@ * User page callbacks for the Comment module. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -21,7 +21,7 @@ * The node or comment that is being replied to must appear above the comment * form to provide the user context while authoring the comment. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * Every comment belongs to a node. This is that node. * @param $pid * (optional) Some comments are replies to other comments. In those cases, @@ -34,7 +34,7 @@ * - comment_parent: If the comment is a reply to another comment. * - comment_form: The comment form as a renderable array. */ -function comment_reply(Node $node, $pid = NULL) { +function comment_reply(EntityInterface $node, $pid = NULL) { // Set the breadcrumb trail. drupal_set_breadcrumb(array(l(t('Home'), NULL), l($node->label(), 'node/' . $node->nid))); $op = isset($_POST['op']) ? $_POST['op'] : ''; diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php index 6851be0..7f01ea6 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php @@ -56,7 +56,7 @@ protected function attachLoad(&$records, $load_revision = FALSE) { */ public function create(array $values) { if (empty($values['node_type']) && !empty($values['nid'])) { - $node = node_load($values['nid']); + $node = node_load(is_object($values['nid']) ? $values['nid']->value : $values['nid']); $values['node_type'] = 'comment_node_' . $node->type; } return parent::create($values); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php index 253136e..f735871 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php @@ -80,7 +80,7 @@ function setUp() { /** * Posts a comment. * - * @param Drupal\node\Node|null $node + * @param \Drupal\Core\Entity\EntityInterface $node|null $node * Node to post comment on or NULL to post to the previusly loaded page. * @param $comment * Comment body. diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php index 45de66e..e519b1c 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php @@ -7,7 +7,7 @@ namespace Drupal\field_ui\Tests; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Tests the functionality of the 'Manage display' screens. @@ -216,7 +216,7 @@ function testNoFieldsDisplayOverview() { /** * Asserts that a string is found in the rendered node in a view mode. * - * @param Node $node + * @param EntityInterface $node * The node. * @param $view_mode * The view mode in which the node should be displayed. @@ -228,14 +228,14 @@ function testNoFieldsDisplayOverview() { * @return * TRUE on pass, FALSE on fail. */ - function assertNodeViewText(Node $node, $view_mode, $text, $message) { + function assertNodeViewText(EntityInterface $node, $view_mode, $text, $message) { return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, FALSE); } /** * Asserts that a string is not found in the rendered node in a view mode. * - * @param Node $node + * @param EntityInterface $node * The node. * @param $view_mode * The view mode in which the node should be displayed. @@ -246,7 +246,7 @@ function assertNodeViewText(Node $node, $view_mode, $text, $message) { * @return * TRUE on pass, FALSE on fail. */ - function assertNodeViewNoText(Node $node, $view_mode, $text, $message) { + function assertNodeViewNoText(EntityInterface $node, $view_mode, $text, $message) { return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, TRUE); } @@ -256,7 +256,7 @@ function assertNodeViewNoText(Node $node, $view_mode, $text, $message) { * This helper function is used by assertNodeViewText() and * assertNodeViewNoText(). * - * @param Node $node + * @param EntityInterface $node * The node. * @param $view_mode * The view mode in which the node should be displayed. @@ -270,7 +270,7 @@ function assertNodeViewNoText(Node $node, $view_mode, $text, $message) { * @return * TRUE on pass, FALSE on fail. */ - function assertNodeViewTextHelper(Node $node, $view_mode, $text, $message, $not_exists) { + function assertNodeViewTextHelper(EntityInterface $node, $view_mode, $text, $message, $not_exists) { // Make sure caches on the tester side are refreshed after changes // submitted on the tested side. field_info_cache_clear(); diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 872eb95..f0434fb 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -6,7 +6,6 @@ */ use Drupal\Core\Entity\EntityInterface; -use Drupal\node\Plugin\Core\Entity\Node; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; use Drupal\taxonomy\Plugin\Core\Entity\Term; @@ -242,13 +241,13 @@ function forum_uri($forum) { /** * Checks whether a node can be used in a forum, based on its content type. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * * @return * Boolean indicating if the node can be assigned to a forum. */ -function _forum_node_check_node_type(Node $node) { +function _forum_node_check_node_type(EntityInterface $node) { // Fetch information about the forum field. $instance = field_info_instance('node', 'taxonomy_forums', $node->type); return !empty($instance); @@ -257,7 +256,7 @@ function _forum_node_check_node_type(Node $node) { /** * Implements hook_node_view(). */ -function forum_node_view(Node $node, EntityDisplay $display, $view_mode) { +function forum_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { $vid = config('forum.settings')->get('vocabulary'); $vocabulary = taxonomy_vocabulary_load($vid); if (_forum_node_check_node_type($node)) { @@ -283,7 +282,7 @@ function forum_node_view(Node $node, EntityDisplay $display, $view_mode) { * Checks in particular that the node is assigned only a "leaf" term in the * forum taxonomy. */ -function forum_node_validate(Node $node, $form) { +function forum_node_validate(EntityInterface $node, $form) { if (_forum_node_check_node_type($node)) { $langcode = $form['taxonomy_forums']['#language']; // vocabulary is selected, not a "container" term. @@ -319,7 +318,7 @@ function forum_node_validate(Node $node, $form) { * * Assigns the forum taxonomy when adding a topic from within a forum. */ -function forum_node_presave(Node $node) { +function forum_node_presave(EntityInterface $node) { if (_forum_node_check_node_type($node)) { // Make sure all fields are set properly: $node->icon = !empty($node->icon) ? $node->icon : ''; @@ -339,7 +338,7 @@ function forum_node_presave(Node $node) { /** * Implements hook_node_update(). */ -function forum_node_update(Node $node) { +function forum_node_update(EntityInterface $node) { if (_forum_node_check_node_type($node)) { // If this is not a new revision and does exist, update the forum record, // otherwise insert a new one. @@ -389,7 +388,7 @@ function forum_node_update(Node $node) { /** * Implements hook_node_insert(). */ -function forum_node_insert(Node $node) { +function forum_node_insert(EntityInterface $node) { if (_forum_node_check_node_type($node)) { if (!empty($node->forum_tid)) { $nid = db_insert('forum') @@ -406,7 +405,7 @@ function forum_node_insert(Node $node) { /** * Implements hook_node_predelete(). */ -function forum_node_predelete(Node $node) { +function forum_node_predelete(EntityInterface $node) { if (_forum_node_check_node_type($node)) { db_delete('forum') ->condition('nid', $node->nid) @@ -657,7 +656,7 @@ function forum_block_view_pre_render($elements) { /** * Implements hook_form(). */ -function forum_form(Node $node, &$form_state) { +function forum_form(EntityInterface $node, &$form_state) { $type = node_type_load($node->type); $form['title'] = array( '#type' => 'textfield', diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php index 5070396..c08ce70 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php @@ -7,7 +7,7 @@ namespace Drupal\forum\Tests; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\simpletest\WebTestBase; /** @@ -540,14 +540,14 @@ function createForumTopic($forum, $container = FALSE) { * * @param $node_user * The user who creates the node. - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being checked. * @param $admin * Boolean to indicate whether the user can 'access administration pages'. * @param $response * The exptected HTTP response code. */ - private function verifyForums($node_user, Node $node, $admin, $response = 200) { + private function verifyForums($node_user, EntityInterface $node, $admin, $response = 200) { $response2 = ($admin) ? 200 : 403; // View forum help node. diff --git a/core/modules/history/history.module b/core/modules/history/history.module index 45027fe..84abade 100644 --- a/core/modules/history/history.module +++ b/core/modules/history/history.module @@ -9,7 +9,7 @@ * - Generic helper for node_mark(). */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Entities changed before this time are always shown as read. @@ -79,7 +79,7 @@ function history_cron() { /** * Implements hook_node_delete(). */ -function history_node_delete(Node $node) { +function history_node_delete(EntityInterface $node) { db_delete('history') ->condition('nid', $node->nid) ->execute(); diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index 09567cf..5e10e60 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -11,7 +11,7 @@ * URLs to be added to the main site navigation menu. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\block\Plugin\Core\Entity\Block; use Drupal\system\Plugin\Core\Entity\Menu; use Drupal\system\Plugin\block\block\SystemMenuBlock; @@ -437,21 +437,21 @@ function menu_block_view_alter(array &$build, Block $block) { /** * Implements hook_node_insert(). */ -function menu_node_insert(Node $node) { +function menu_node_insert(EntityInterface $node) { menu_node_save($node); } /** * Implements hook_node_update(). */ -function menu_node_update(Node $node) { +function menu_node_update(EntityInterface $node) { menu_node_save($node); } /** * Helper for hook_node_insert() and hook_node_update(). */ -function menu_node_save(Node $node) { +function menu_node_save(EntityInterface $node) { if (isset($node->menu)) { $link = &$node->menu; if (empty($link['enabled'])) { @@ -480,7 +480,7 @@ function menu_node_save(Node $node) { /** * Implements hook_node_predelete(). */ -function menu_node_predelete(Node $node) { +function menu_node_predelete(EntityInterface $node) { // Delete all menu module links that point to this node. $result = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :path AND module = 'menu'", array(':path' => 'node/' . $node->nid), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $m) { @@ -491,7 +491,7 @@ function menu_node_predelete(Node $node) { /** * Implements hook_node_prepare(). */ -function menu_node_prepare(Node $node) { +function menu_node_prepare(EntityInterface $node) { if (empty($node->menu)) { // Prepare the node for the edit form so that $node->menu always exists. $menu_name = strtok(variable_get('menu_parent_' . $node->type, 'main:0'), ':'); @@ -657,7 +657,7 @@ function menu_form_node_form_alter(&$form, $form_state) { * * @see menu_form_node_form_alter() */ -function menu_node_submit(Node $node, $form, $form_state) { +function menu_node_submit(EntityInterface $node, $form, $form_state) { // Decompose the selected menu parent option into 'menu_name' and 'plid', if // the form used the default parent selection widget. if (!empty($form_state['values']['menu']['parent'])) { diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index c038d40..3c0a6c4 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -10,12 +10,12 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityFormController; +use Drupal\Core\Entity\EntityFormControllerNG; /** * Form controller for the node edit forms. */ -class NodeFormController extends EntityFormController { +class NodeFormController extends EntityFormControllerNG { /** * Prepares the node object. @@ -512,4 +512,19 @@ public function delete(array $form, array &$form_state) { $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination)); } + /** + * Implements \Drupal\Core\Entity\EntityFormControllerInterface::buildEntity(). + */ + public function buildEntity(array $form, array &$form_state) { + return parent::buildEntity($form, $form_state)->getBCEntity(); + } + + /** + * Implements \Drupal\Core\Entity\EntityFormControllerInterface::getEntity(). + */ + public function getEntity(array $form_state) { + $entity = parent::getEntity($form_state); + return isset($entity) ? $entity->getBCEntity() : $entity; + } + } diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index d855384..db32105 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -7,7 +7,7 @@ namespace Drupal\node; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\DatabaseStorageControllerNG; use Drupal\Core\Entity\EntityInterface; /** @@ -16,31 +16,40 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for node entities. */ -class NodeStorageController extends DatabaseStorageController { +class NodeStorageController extends DatabaseStorageControllerNG { /** * Overrides Drupal\Core\Entity\DatabaseStorageController::create(). */ public function create(array $values) { - $node = parent::create($values); - - // Set the created time to now. - if (empty($node->created)) { - $node->created = REQUEST_TIME; + // @todo Handle this through property defaults. + if (empty($values['created'])) { + $values['created'] = REQUEST_TIME; } - - return $node; + return parent::create($values)->getBCEntity(); } /** - * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad(). + * Overrides Drupal\Core\Entity\DatabaseStorageControllerNG::attachLoad(). */ - protected function attachLoad(&$nodes, $load_revision = FALSE) { + protected function attachLoad(&$queried_entities, $load_revision = FALSE) { + $nodes = $this->mapFromStorageRecords($queried_entities, $load_revision); + // Create an array of nodes for each content type and pass this to the - // object type specific callback. + // object type specific callback. To preserve backward-compatibility we + // pass on BC decorators to node-specific hooks, while we pass on the + // regular entity objects else. $typed_nodes = array(); - foreach ($nodes as $id => $entity) { - $typed_nodes[$entity->type][$id] = $entity; + foreach ($nodes as $id => $node) { + $queried_entities[$id] = $node->getBCEntity(); + $typed_nodes[$node->bundle()][$id] = $queried_entities[$id]; + } + + if ($load_revision) { + field_attach_load_revision($this->entityType, $queried_entities); + } + else { + field_attach_load($this->entityType, $queried_entities); } // Call object type specific callbacks on each typed array of nodes. @@ -55,7 +64,19 @@ protected function attachLoad(&$nodes, $load_revision = FALSE) { // hook_node_load(), containing a list of node types that were loaded. $argument = array_keys($typed_nodes); $this->hookLoadArguments = array($argument); - parent::attachLoad($nodes, $load_revision); + + // Call hook_entity_load(). + foreach (module_implements('entity_load') as $module) { + $function = $module . '_entity_load'; + $function($queried_entities, $this->entityType); + } + // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are + // always the queried entities, followed by additional arguments set in + // $this->hookLoadArguments. + $args = array_merge(array($queried_entities), $this->hookLoadArguments); + foreach (module_implements($this->entityType . '_load') as $module) { + call_user_func_array($module . '_' . $this->entityType . '_load', $args); + } } /** @@ -77,6 +98,8 @@ protected function buildQuery($ids, $revision_id = FALSE) { * Overrides Drupal\Core\Entity\DatabaseStorageController::invokeHook(). */ protected function invokeHook($hook, EntityInterface $node) { + $node = $node->getBCEntity(); + if ($hook == 'insert' || $hook == 'update') { node_invoke($node, $hook); } @@ -86,7 +109,23 @@ protected function invokeHook($hook, EntityInterface $node) { node_invoke($node, 'delete'); } - parent::invokeHook($hook, $node); + // Inline parent::invokeHook() to pass on BC-entities to node-specific + // hooks. + + $function = 'field_attach_' . $hook; + // @todo: field_attach_delete_revision() is named the wrong way round, + // consider renaming it. + if ($function == 'field_attach_revision_delete') { + $function = 'field_attach_delete_revision'; + } + if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { + $function($node); + } + + // Invoke the hook. + module_invoke_all($this->entityType . '_' . $hook, $node); + // Invoke the respective entity-level hook. + module_invoke_all('entity_' . $hook, $node, $this->entityType); } /** @@ -94,7 +133,7 @@ protected function invokeHook($hook, EntityInterface $node) { */ protected function preSave(EntityInterface $node) { // Before saving the node, set changed and revision times. - $node->changed = REQUEST_TIME; + $node->changed->value = REQUEST_TIME; } /** @@ -133,21 +172,22 @@ protected function preSaveRevision(\stdClass $record, EntityInterface $entity) { /** * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave(). */ - function postSave(EntityInterface $node, $update) { + public function postSave(EntityInterface $node, $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 ($node->isDefaultRevision()) { - node_access_acquire_grants($node, $update); + node_access_acquire_grants($node->getBCEntity(), $update); } } + /** * Overrides Drupal\Core\Entity\DatabaseStorageController::preDelete(). */ - function preDelete($entities) { + public function preDelete($entities) { if (module_exists('search')) { foreach ($entities as $id => $entity) { - search_reindex($entity->nid, 'node'); + search_reindex($entity->nid->value, 'node'); } } } @@ -163,4 +203,105 @@ protected function postDelete($nodes) { ->condition('nid', $ids, 'IN') ->execute(); } + + /** + * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions(). + */ + public function baseFieldDefinitions() { + $properties['nid'] = array( + 'label' => t('Node ID'), + 'description' => t('The node ID.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $properties['uuid'] = array( + 'label' => t('UUID'), + 'description' => t('The node UUID.'), + 'type' => 'string_field', + 'read-only' => TRUE, + ); + $properties['vid'] = array( + 'label' => t('Revision ID'), + 'description' => t('The node revision ID.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $properties['type'] = array( + 'label' => t('Type'), + 'description' => t('The node type.'), + 'type' => 'string_field', + 'read-only' => TRUE, + ); + $properties['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The node language code.'), + 'type' => 'language_field', + ); + $properties['title'] = array( + 'label' => t('Title'), + 'description' => t('The title of this node, always treated as non-markup plain text.'), + 'type' => 'string_field', + ); + $properties['uid'] = array( + 'label' => t('User ID'), + 'description' => t('The user ID of the node author.'), + 'type' => 'entity_reference_field', + 'settings' => array('target_type' => 'user'), + ); + $properties['status'] = array( + 'label' => t('Publishing status'), + 'description' => t('A boolean indicating whether the node is published.'), + 'type' => 'boolean_field', + ); + $properties['created'] = array( + 'label' => t('Created'), + 'description' => t('The time that the node was created.'), + 'type' => 'integer_field', + ); + $properties['changed'] = array( + 'label' => t('Changed'), + 'description' => t('The time that the node was last edited.'), + 'type' => 'integer_field', + ); + $properties['comment'] = array( + 'label' => t('Comment'), + 'description' => t('Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).'), + 'type' => 'integer_field', + ); + $properties['promote'] = array( + 'label' => t('Promote'), + 'description' => t('A boolean indicating whether the node should be displayed on the front page.'), + 'type' => 'boolean_field', + ); + $properties['sticky'] = array( + 'label' => t('Sticky'), + 'description' => t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'), + 'type' => 'boolean_field', + ); + $properties['tnid'] = array( + 'label' => t('Translation set ID'), + 'description' => t('The translation set id for this node, which equals the node id of the source post in each set.'), + 'type' => 'integer_field', + ); + $properties['translate'] = array( + 'label' => t('Translate'), + 'description' => t('A boolean indicating whether this translation page needs to be updated.'), + 'type' => 'boolean_field', + ); + $properties['revision_timestamp'] = array( + 'label' => t('Revision timestamp'), + 'description' => t('The time that the current revision was created.'), + 'type' => 'integer_field', + 'queryable' => FALSE, + ); + $properties['revision_uid'] = array( + 'label' => t('Revision user ID'), + 'description' => t('The user ID of the author of the current revision.'), + 'type' => 'entity_reference_field', + 'settings' => array('target_type' => 'user'), + 'queryable' => FALSE, + ); + return $properties; + } + } diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php index a4cf264..e040baf 100644 --- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php @@ -8,7 +8,7 @@ namespace Drupal\node\Plugin\Core\Entity; use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Entity\Entity; +use Drupal\Core\Entity\EntityNG; use Drupal\Core\Annotation\Plugin; use Drupal\Core\Annotation\Translation; @@ -43,7 +43,7 @@ * permission_granularity = "bundle" * ) */ -class Node extends Entity implements ContentEntityInterface { +class Node extends EntityNG implements ContentEntityInterface { /** * The node ID. @@ -67,7 +67,7 @@ class Node extends Entity implements ContentEntityInterface { * * @var boolean */ - public $isDefaultRevision = TRUE; + public $isDefaultRevision; /** * The node UUID. @@ -88,7 +88,7 @@ class Node extends Entity implements ContentEntityInterface { * * @var string */ - public $langcode = LANGUAGE_NOT_SPECIFIED; + public $langcode; /** * The node title. @@ -193,33 +193,54 @@ class Node extends Entity implements ContentEntityInterface { public $revision_uid; /** - * Implements Drupal\Core\Entity\EntityInterface::id(). - */ - public function id() { - return $this->nid; + * The plain data values of the contained properties. + * + * Define default values. + * + * @var array + */ + protected $values = array( + 'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))), + 'isDefaultRevision' => array(LANGUAGE_DEFAULT => array(0 => array('value' => TRUE))), + ); + + /** + * Overrides \Drupal\Core\Entity\EntityNG::init(). + */ + protected function init() { + parent::init(); + // We unset all defined properties, so magic getters apply. + unset($this->nid); + unset($this->vid); + unset($this->isDefaultRevision); + unset($this->uuid); + unset($this->type); + unset($this->title); + unset($this->uid); + unset($this->status); + unset($this->created); + unset($this->changed); + unset($this->comment); + unset($this->promote); + unset($this->sticky); + unset($this->tnid); + unset($this->translate); + unset($this->revision_timestamp); + unset($this->revision_uid); } /** - * Implements Drupal\Core\Entity\EntityInterface::bundle(). - */ - public function bundle() { - return $this->type; - } - - /** - * Overrides Drupal\Core\Entity\Entity::createDuplicate(). + * Implements Drupal\Core\Entity\EntityInterface::id(). */ - public function createDuplicate() { - $duplicate = parent::createDuplicate(); - $duplicate->vid = NULL; - return $duplicate; + public function id() { + return $this->get('nid')->value; } /** * Overrides Drupal\Core\Entity\Entity::getRevisionId(). */ public function getRevisionId() { - return $this->vid; + return $this->get('vid')->value; } } diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php index 1207238..d5e396c 100644 --- a/core/modules/node/node.api.php +++ b/core/modules/node/node.api.php @@ -256,7 +256,7 @@ function hook_node_grants($account, $op) { * * Note: a deny all grant is not written to the database; denies are implicit. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that has just been saved. * * @return @@ -266,7 +266,7 @@ function hook_node_grants($account, $op) { * @see hook_node_access_records_alter() * @ingroup node_access */ -function hook_node_access_records(Drupal\node\Node $node) { +function hook_node_access_records(\Drupal\Core\Entity\EntityInterface $node) { // We only care about the node if it has been marked private. If not, it is // treated just like any other node and we completely ignore it. if ($node->private) { @@ -317,7 +317,7 @@ function hook_node_access_records(Drupal\node\Node $node) { * * @param $grants * The $grants array returned by hook_node_access_records(). - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node for which the grants were acquired. * * The preferred use of this hook is in a module that bridges multiple node @@ -329,7 +329,7 @@ function hook_node_access_records(Drupal\node\Node $node) { * @see hook_node_grants_alter() * @ingroup node_access */ -function hook_node_access_records_alter(&$grants, Drupal\node\Node $node) { +function hook_node_access_records_alter(&$grants, Drupal\Core\Entity\EntityInterface $node) { // Our module allows editors to mark specific articles with the 'is_preview' // field. If the node being saved has a TRUE value for that field, then only // our grants are retained, and other grants are removed. Doing so ensures @@ -459,14 +459,14 @@ function hook_node_operations() { * field_attach_delete() are called, and before the node is removed from the * node table in the database. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is about to be deleted. * * @see hook_node_predelete() * @see node_delete_multiple() * @ingroup node_api_hooks */ -function hook_node_predelete(Drupal\node\Node $node) { +function hook_node_predelete(\Drupal\Core\Entity\EntityInterface $node) { db_delete('mytable') ->condition('nid', $node->nid) ->execute(); @@ -478,14 +478,14 @@ function hook_node_predelete(Drupal\node\Node $node) { * This hook is invoked from node_delete_multiple() after field_attach_delete() * has been called and after the node has been removed from the database. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that has been deleted. * * @see hook_node_predelete() * @see node_delete_multiple() * @ingroup node_api_hooks */ -function hook_node_delete(Drupal\node\Node $node) { +function hook_node_delete(\Drupal\Core\Entity\EntityInterface $node) { drupal_set_message(t('Node: @title has been deleted', array('@title' => $node->label()))); } @@ -496,12 +496,12 @@ function hook_node_delete(Drupal\node\Node $node) { * removed from the node_revision table, and before * field_attach_delete_revision() is called. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node revision (node object) that is being deleted. * * @ingroup node_api_hooks */ -function hook_node_revision_delete(Drupal\node\Node $node) { +function hook_node_revision_delete(\Drupal\Core\Entity\EntityInterface $node) { db_delete('mytable') ->condition('vid', $node->vid) ->execute(); @@ -523,12 +523,12 @@ function hook_node_revision_delete(Drupal\node\Node $node) { * write/update database queries executed from this hook are also not committed * immediately. Check node_save() and db_transaction() for more info. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being created. * * @ingroup node_api_hooks */ -function hook_node_insert(Drupal\node\Node $node) { +function hook_node_insert(\Drupal\Core\Entity\EntityInterface $node) { db_insert('mytable') ->fields(array( 'nid' => $node->nid, @@ -543,12 +543,12 @@ function hook_node_insert(Drupal\node\Node $node) { * This hook runs after a new node object has just been instantiated. It can be * used to set initial values, e.g. to provide defaults. * - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node object. * * @ingroup node_api_hooks */ -function hook_node_create(\Drupal\node\Plugin\Core\Entity\Node $node) { +function hook_node_create(\Drupal\Core\Entity\EntityInterface $node) { if (!isset($node->foo)) { $node->foo = 'some_initial_value'; } @@ -615,7 +615,7 @@ function hook_node_load($nodes, $types) { * the default home page at path 'node', a recent content block, etc.) See * @link node_access Node access rights @endlink for a full explanation. * - * @param Drupal\node\Node|string $node + * @param Drupal\Core\Entity\EntityInterface|string $node * Either a node entity or the machine name of the content type on which to * perform the access check. * @param string $op @@ -669,12 +669,12 @@ function hook_node_access($node, $op, $account, $langcode) { * This hook is invoked from NodeFormController::prepareEntity() after the * type-specific hook_prepare() is invoked. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is about to be shown on the add/edit form. * * @ingroup node_api_hooks */ -function hook_node_prepare(Drupal\node\Node $node) { +function hook_node_prepare(\Drupal\Core\Entity\EntityInterface $node) { if (!isset($node->comment)) { $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN); } @@ -686,7 +686,7 @@ function hook_node_prepare(Drupal\node\Node $node) { * This hook is invoked from node_search_execute(), after node_load() and * node_view() have been called. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being displayed in a search result. * @param $langcode * Language code of result being displayed. @@ -702,7 +702,7 @@ function hook_node_prepare(Drupal\node\Node $node) { * * @ingroup node_api_hooks */ -function hook_node_search_result(Drupal\node\Node $node, $langcode) { +function hook_node_search_result(\Drupal\Core\Entity\EntityInterface $node, $langcode) { $comments = db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = :nid', array('nid' => $node->nid))->fetchField(); return array('comment' => format_plural($comments, '1 comment', '@count comments')); } @@ -713,12 +713,12 @@ function hook_node_search_result(Drupal\node\Node $node, $langcode) { * This hook is invoked from node_save() before the node is saved to the * database. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being inserted or updated. * * @ingroup node_api_hooks */ -function hook_node_presave(Drupal\node\Node $node) { +function hook_node_presave(\Drupal\Core\Entity\EntityInterface $node) { if ($node->nid && $node->moderate) { // Reset votes when node is updated: $node->score = 0; @@ -743,12 +743,12 @@ function hook_node_presave(Drupal\node\Node $node) { * write/update database queries executed from this hook are also not committed * immediately. Check node_save() and db_transaction() for more info. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being updated. * * @ingroup node_api_hooks */ -function hook_node_update(Drupal\node\Node $node) { +function hook_node_update(\Drupal\Core\Entity\EntityInterface $node) { db_update('mytable') ->fields(array('extra' => $node->extra)) ->condition('nid', $node->nid) @@ -761,7 +761,7 @@ function hook_node_update(Drupal\node\Node $node) { * This hook is invoked during search indexing, after node_load(), and after the * result of node_view() is added as $node->rendered to the node object. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being indexed. * @param $langcode * Language code of the variant of the node being indexed. @@ -771,7 +771,7 @@ function hook_node_update(Drupal\node\Node $node) { * * @ingroup node_api_hooks */ -function hook_node_update_index(Drupal\node\Node $node, $langcode) { +function hook_node_update_index(\Drupal\Core\Entity\EntityInterface $node, $langcode) { $text = ''; $comments = db_query('SELECT subject, comment, format FROM {comment} WHERE nid = :nid AND status = :status', array(':nid' => $node->nid, ':status' => COMMENT_PUBLISHED)); foreach ($comments as $comment) { @@ -795,7 +795,7 @@ function hook_node_update_index(Drupal\node\Node $node, $langcode) { * hook_node_presave() instead. If it is really necessary to change the node at * the validate stage, you can use form_set_value(). * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being validated. * @param $form * The form being used to edit the node. @@ -804,7 +804,7 @@ function hook_node_update_index(Drupal\node\Node $node, $langcode) { * * @ingroup node_api_hooks */ -function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) { +function hook_node_validate(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) { if (isset($node->end) && isset($node->start)) { if ($node->start > $node->end) { form_set_error('time', t('An event may not end before it starts.')); @@ -823,7 +823,7 @@ function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) { * properties. See hook_field_attach_extract_form_values() for customizing * field-related properties. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity being updated in response to a form submission. * @param $form * The form being used to edit the node. @@ -832,7 +832,7 @@ function hook_node_validate(Drupal\node\Node $node, $form, &$form_state) { * * @ingroup node_api_hooks */ -function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) { +function hook_node_submit(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) { // Decompose the selected menu parent option into 'menu_name' and 'plid', if // the form used the default parent selection widget. if (!empty($form_state['values']['menu']['parent'])) { @@ -852,7 +852,7 @@ function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) { * the RSS item generated for this node. * For details on how this is used, see node_feed(). * - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being assembled for rendering. * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display * The entity_display object holding the display options configured for the @@ -868,7 +868,7 @@ function hook_node_submit(Drupal\node\Node $node, $form, &$form_state) { * * @ingroup node_api_hooks */ -function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) { +function hook_node_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) { // Only do the extra work if the component is configured to be displayed. // This assumes a 'mymodule_addition' extra field has been defined for the // node type in hook_field_extra_fields(). @@ -895,7 +895,7 @@ function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\enti * * @param $build * A renderable array representing the node content. - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being rendered. * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display * The entity_display object holding the display options configured for the @@ -906,7 +906,7 @@ function hook_node_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\enti * * @ingroup node_api_hooks */ -function hook_node_view_alter(&$build, \Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display) { +function hook_node_view_alter(&$build, \Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display) { if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { // Change its weight. $build['an_additional_field']['#weight'] = -10; @@ -1088,12 +1088,12 @@ function hook_node_type_delete($info) { * removed from the node table in the database, before hook_node_delete() is * invoked, and before field_attach_delete() is called. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being deleted. * * @ingroup node_api_hooks */ -function hook_delete(Drupal\node\Node $node) { +function hook_delete(\Drupal\Core\Entity\EntityInterface $node) { db_delete('mytable') ->condition('nid', $node->nid) ->execute(); @@ -1108,12 +1108,12 @@ function hook_delete(Drupal\node\Node $node) { * This hook is invoked from NodeFormController::prepareEntity() before the * general hook_node_prepare() is invoked. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is about to be shown on the add/edit form. * * @ingroup node_api_hooks */ -function hook_prepare(Drupal\node\Node $node) { +function hook_prepare(\Drupal\Core\Entity\EntityInterface $node) { if ($file = file_check_upload($field_name)) { $file = file_save_upload($field_name, _image_filename($file->filename, NULL, TRUE)); if ($file) { @@ -1144,7 +1144,7 @@ function hook_prepare(Drupal\node\Node $node) { * displayed automatically by the node module. This hook just needs to * return the node title and form editing fields specific to the node type. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being added or edited. * @param $form_state * The form state array. @@ -1155,7 +1155,7 @@ function hook_prepare(Drupal\node\Node $node) { * * @ingroup node_api_hooks */ -function hook_form(Drupal\node\Node $node, &$form_state) { +function hook_form(\Drupal\Core\Entity\EntityInterface $node, &$form_state) { $type = node_type_load($node->type); $form['title'] = array( @@ -1196,12 +1196,12 @@ function hook_form(Drupal\node\Node $node, &$form_state) { * node table in the database, before field_attach_insert() is called, and * before hook_node_insert() is invoked. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being created. * * @ingroup node_api_hooks */ -function hook_insert(Drupal\node\Node $node) { +function hook_insert(\Drupal\Core\Entity\EntityInterface $node) { db_insert('mytable') ->fields(array( 'nid' => $node->nid, @@ -1255,12 +1255,12 @@ function hook_load($nodes) { * node table in the database, before field_attach_update() is called, and * before hook_node_update() is invoked. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node that is being updated. * * @ingroup node_api_hooks */ -function hook_update(Drupal\node\Node $node) { +function hook_update(\Drupal\Core\Entity\EntityInterface $node) { db_update('mytable') ->fields(array('extra' => $node->extra)) ->condition('nid', $node->nid) @@ -1284,7 +1284,7 @@ function hook_update(Drupal\node\Node $node) { * have no effect. The preferred method to change a node's content is to use * hook_node_presave() instead. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node being validated. * @param $form * The form being used to edit the node. @@ -1293,7 +1293,7 @@ function hook_update(Drupal\node\Node $node) { * * @ingroup node_api_hooks */ -function hook_validate(Drupal\node\Node $node, $form, &$form_state) { +function hook_validate(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) { if (isset($node->end) && isset($node->start)) { if ($node->start > $node->end) { form_set_error('time', t('An event may not end before it starts.')); @@ -1311,7 +1311,7 @@ function hook_validate(Drupal\node\Node $node, $form, &$form_state) { * that the node type module can define a custom method for display, or add to * the default display. * - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to be displayed, as returned by node_load(). * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display * The entity_display object holding the display options configured for the @@ -1332,7 +1332,7 @@ function hook_validate(Drupal\node\Node $node, $form, &$form_state) { * * @ingroup node_api_hooks */ -function hook_view(\Drupal\node\Plugin\Core\Entity\Node $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode) { +function hook_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode) { if ($view_mode == 'full' && node_is_page($node)) { $breadcrumb = array(); $breadcrumb[] = l(t('Home'), NULL); diff --git a/core/modules/node/node.module b/core/modules/node/node.module index f2206a0..7d2e263 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -15,11 +15,10 @@ use Drupal\Core\Database\Query\SelectExtender; use Drupal\Core\Database\Query\SelectInterface; use Drupal\Core\Datetime\DrupalDateTime; -use Drupal\Core\Template\Attribute; -use Drupal\node\Plugin\Core\Entity\Node; -use Drupal\file\Plugin\Core\Entity\File; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Template\Attribute; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; +use Drupal\file\Plugin\Core\Entity\File; /** * Denotes that the node is not published. @@ -250,15 +249,15 @@ function node_entity_display_alter(EntityDisplay $display, $context) { /** * Entity URI callback. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * * @return array * An array with 'path' as the key and the path to the node as its value. */ -function node_uri(Node $node) { +function node_uri(EntityInterface $node) { return array( - 'path' => 'node/' . $node->nid, + 'path' => 'node/' . $node->nid->value, ); } @@ -407,7 +406,7 @@ function node_type_get_label($name) { /** * Returns the node type label for the passed node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity to return the node type's label for. * * @return string|false @@ -907,7 +906,7 @@ function node_hook($type, $hook) { /** * Invokes a node hook. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A Node entity. * @param $hook * A string containing the name of the hook. @@ -944,7 +943,12 @@ function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) { * @see Drupal\Core\Entity\Query\EntityQueryInterface */ function node_load_multiple(array $nids = NULL, $reset = FALSE) { - return entity_load_multiple('node', $nids, $reset); + $entities = entity_load_multiple('node', $nids, $reset); + // Return BC-entities. + foreach ($entities as $id => $entity) { + $entities[$id] = $entity->getBCEntity(); + } + return $entities; } /** @@ -960,7 +964,7 @@ function node_load_multiple(array $nids = NULL, $reset = FALSE) { * A fully-populated node entity, or FALSE if the node is not found. */ function node_load($nid = NULL, $reset = FALSE) { - return entity_load('node', $nid, $reset); + return entity_load('node', $nid, $reset)->getBCEntity(); } /** @@ -979,13 +983,13 @@ function node_revision_load($vid = NULL) { /** * Prepares a node for saving by populating the author and creation date. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node object. * * @return Drupal\node\Node * An updated node object. */ -function node_submit(Node $node) { +function node_submit(EntityInterface $node) { global $user; // A user might assign the node author by entering a user name in the node @@ -1020,11 +1024,11 @@ function node_submit(Node $node) { /** * Saves changes to a node or adds a new node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The $node entity to be saved. If $node->nid is * omitted (or $node->is_new is TRUE), a new node will be added. */ -function node_save(Node $node) { +function node_save(EntityInterface $node) { $node->save(); } @@ -1067,7 +1071,7 @@ function node_revision_delete($revision_id) { /** * Page callback: Generates an array which displays a node detail page. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $message * (optional) A flag which sets a page title relevant to the revision being @@ -1078,7 +1082,7 @@ function node_revision_delete($revision_id) { * * @see node_menu() */ -function node_show(Node $node, $message = FALSE) { +function node_show(EntityInterface $node, $message = FALSE) { if ($message) { drupal_set_title(t('Revision of %title from %date', array('%title' => $node->label(), '%date' => format_date($node->revision_timestamp))), PASS_THROUGH); } @@ -1097,13 +1101,13 @@ function node_show(Node $node, $message = FALSE) { /** * Checks whether the current page is the full page view of the passed-in node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * * @return * The ID of the node if this is a full page view, otherwise FALSE. */ -function node_is_page(Node $node) { +function node_is_page(EntityInterface $node) { $page_node = menu_get_object(); return (!empty($page_node) ? $page_node->nid == $node->nid : FALSE); } @@ -1542,7 +1546,7 @@ function theme_node_search_admin($variables) { /** * Access callback: Checks node revision access. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to check. * @param $op * (optional) The specific operation being checked. Defaults to 'view.' @@ -1560,7 +1564,7 @@ function theme_node_search_admin($variables) { * * @see node_menu() */ -function _node_revision_access(Node $node, $op = 'view', $account = NULL, $langcode = NULL) { +function _node_revision_access(EntityInterface $node, $op = 'view', $account = NULL, $langcode = NULL) { $access = &drupal_static(__FUNCTION__, array()); $map = array( @@ -1853,7 +1857,7 @@ function node_type_page_title($type) { /** * Title callback: Displays the node's title. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity. * * @return @@ -1861,7 +1865,7 @@ function node_type_page_title($type) { * * @see node_menu() */ -function node_page_title(Node $node) { +function node_page_title(EntityInterface $node) { return $node->label(); } @@ -1881,13 +1885,13 @@ function node_last_changed($nid) { /** * Returns a list of all the existing revision numbers for the node passed in. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity. * * @return * An associative array keyed by node revision number. */ -function node_revision_list(Node $node) { +function node_revision_list(EntityInterface $node) { $revisions = array(); $result = db_query('SELECT r.vid, r.title, r.log, r.uid, n.vid AS current_vid, r.timestamp, u.name FROM {node_revision} r LEFT JOIN {node} n ON n.vid = r.vid INNER JOIN {users} u ON u.uid = r.uid WHERE r.nid = :nid ORDER BY r.vid DESC', array(':nid' => $node->nid)); foreach ($result as $revision) { @@ -2162,7 +2166,7 @@ function node_feed($nids = FALSE, $channel = array()) { /** * Generates an array for rendering the given node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $view_mode * (optional) View mode, e.g., 'full', 'teaser'... Defaults to 'full.' @@ -2173,7 +2177,7 @@ function node_feed($nids = FALSE, $channel = array()) { * @return * An array as expected by drupal_render(). */ -function node_view(Node $node, $view_mode = 'full', $langcode = NULL) { +function node_view(EntityInterface $node, $view_mode = 'full', $langcode = NULL) { return entity_view($node, $view_mode, $langcode); } @@ -2254,7 +2258,7 @@ function node_page_default() { /** * Page callback: Displays a single node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node entity. * * @return @@ -2262,7 +2266,7 @@ function node_page_default() { * * @see node_menu() */ -function node_page_view(Node $node) { +function node_page_view(EntityInterface $node) { // If there is a menu link to this node, the link becomes the last part // of the active trail, and the link name becomes the page title. // Thus, we must explicitly set the page title to be the node title. @@ -2303,10 +2307,10 @@ function node_update_index() { /** * Indexes a single node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to index. */ -function _node_index_node(Node $node) { +function _node_index_node(EntityInterface $node) { // Save the changed time of the most recent indexed node, for the search // results half-life calculation. @@ -2562,7 +2566,7 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) { * - "update" * - "delete" * - "create" - * @param Drupal\node\Node|string|stdClass $node + * @param Drupal\Core\Entity\EntityInterface|string|stdClass $node * The node entity on which the operation is to be performed, or the node type * object, or node type string (e.g., 'forum') for the 'create' operation. * @param $account @@ -2989,13 +2993,13 @@ function node_query_node_access_alter(AlterableInterface $query) { * via hook_node_access_records_alter() implementations, and saves the collected * and altered grants to the database. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The $node to acquire grants for. * @param $delete * (optional) Whether to delete existing node access records before inserting * new ones. Defaults to TRUE. */ -function node_access_acquire_grants(Node $node, $delete = TRUE) { +function node_access_acquire_grants(EntityInterface $node, $delete = TRUE) { $grants = module_invoke_all('node_access_records', $node); // Let modules alter the grants. drupal_alter('node_access_records', $grants, $node); @@ -3017,7 +3021,7 @@ function node_access_acquire_grants(Node $node, $delete = TRUE) { * Note: Don't call this function directly from a contributed module. Call * node_access_acquire_grants() instead. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node whose grants are being written. * @param $grants * A list of grants to write. Each grant is an array that must contain the @@ -3035,7 +3039,7 @@ function node_access_acquire_grants(Node $node, $delete = TRUE) { * * @see node_access_acquire_grants() */ -function _node_access_write_grants(Node $node, $grants, $realm = NULL, $delete = TRUE) { +function _node_access_write_grants(EntityInterface $node, $grants, $realm = NULL, $delete = TRUE) { if ($delete) { $query = db_delete('node_access')->condition('nid', $node->nid); if ($realm) { @@ -3238,7 +3242,7 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) { /** * Implements hook_form(). */ -function node_content_form(Node $node, $form_state) { +function node_content_form(EntityInterface $node, $form_state) { // @todo It is impossible to define a content type without implementing // hook_form(). Remove this requirement. $form = array(); @@ -3334,7 +3338,7 @@ function node_action_info() { /** * Sets the status of a node to 1 (published). * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3342,7 +3346,7 @@ function node_action_info() { * * @ingroup actions */ -function node_publish_action(Node $node, $context = array()) { +function node_publish_action(EntityInterface $node, $context = array()) { $node->status = NODE_PUBLISHED; watchdog('action', 'Set @type %title to published.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3350,7 +3354,7 @@ function node_publish_action(Node $node, $context = array()) { /** * Sets the status of a node to 0 (unpublished). * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3358,7 +3362,7 @@ function node_publish_action(Node $node, $context = array()) { * * @ingroup actions */ -function node_unpublish_action(Node $node, $context = array()) { +function node_unpublish_action(EntityInterface $node, $context = array()) { $node->status = NODE_NOT_PUBLISHED; watchdog('action', 'Set @type %title to unpublished.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3366,7 +3370,7 @@ function node_unpublish_action(Node $node, $context = array()) { /** * Sets the sticky-at-top-of-list property of a node to 1. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3374,7 +3378,7 @@ function node_unpublish_action(Node $node, $context = array()) { * * @ingroup actions */ -function node_make_sticky_action(Node $node, $context = array()) { +function node_make_sticky_action(EntityInterface $node, $context = array()) { $node->sticky = NODE_STICKY; watchdog('action', 'Set @type %title to sticky.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3382,7 +3386,7 @@ function node_make_sticky_action(Node $node, $context = array()) { /** * Sets the sticky-at-top-of-list property of a node to 0. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3390,7 +3394,7 @@ function node_make_sticky_action(Node $node, $context = array()) { * * @ingroup actions */ -function node_make_unsticky_action(Node $node, $context = array()) { +function node_make_unsticky_action(EntityInterface $node, $context = array()) { $node->sticky = NODE_NOT_STICKY; watchdog('action', 'Set @type %title to unsticky.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3398,7 +3402,7 @@ function node_make_unsticky_action(Node $node, $context = array()) { /** * Sets the promote property of a node to 1. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3406,7 +3410,7 @@ function node_make_unsticky_action(Node $node, $context = array()) { * * @ingroup actions */ -function node_promote_action(Node $node, $context = array()) { +function node_promote_action(EntityInterface $node, $context = array()) { $node->promote = NODE_PROMOTED; watchdog('action', 'Promoted @type %title to front page.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3414,7 +3418,7 @@ function node_promote_action(Node $node, $context = array()) { /** * Sets the promote property of a node to 0. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * @param $context * (optional) Array of additional information about what triggered the action. @@ -3422,7 +3426,7 @@ function node_promote_action(Node $node, $context = array()) { * * @ingroup actions */ -function node_unpromote_action(Node $node, $context = array()) { +function node_unpromote_action(EntityInterface $node, $context = array()) { $node->promote = NODE_NOT_PROMOTED; watchdog('action', 'Removed @type %title from front page.', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3430,12 +3434,12 @@ function node_unpromote_action(Node $node, $context = array()) { /** * Saves a node. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to be saved. * * @ingroup actions */ -function node_save_action(Node $node) { +function node_save_action(EntityInterface $node) { $node->save(); watchdog('action', 'Saved @type %title', array('@type' => node_get_type_label($node), '%title' => $node->label())); } @@ -3443,7 +3447,7 @@ function node_save_action(Node $node) { /** * Assigns ownership of a node to a user. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity to modify. * @param $context * Array of additional information about what triggered the action. Includes @@ -3455,7 +3459,7 @@ function node_save_action(Node $node) { * @see node_assign_owner_action_submit() * @ingroup actions */ -function node_assign_owner_action(Node $node, $context) { +function node_assign_owner_action(EntityInterface $node, $context) { $node->uid = $context['owner_uid']; $owner_name = db_query("SELECT name FROM {users} WHERE uid = :uid", array(':uid' => $context['owner_uid']))->fetchField(); watchdog('action', 'Changed owner of @type %title to uid %name.', array('@type' => node_get_type_label($node), '%title' => $node->label(), '%name' => $owner_name)); @@ -3564,7 +3568,7 @@ function node_unpublish_by_keyword_action_submit($form, $form_state) { /** * Unpublishes a node containing certain keywords. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity to modify. * @param $context * Array of additional information about what triggered the action. Includes @@ -3577,7 +3581,7 @@ function node_unpublish_by_keyword_action_submit($form, $form_state) { * * @ingroup actions */ -function node_unpublish_by_keyword_action(Node $node, $context) { +function node_unpublish_by_keyword_action(EntityInterface $node, $context) { foreach ($context['keywords'] as $keyword) { $elements = node_view(clone $node); if (strpos(drupal_render($elements), $keyword) !== FALSE || strpos($node->label(), $keyword) !== FALSE) { diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 245fef7..cfbf715 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -9,7 +9,7 @@ * @see node_menu() */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Page callback: Presents the node editing form. @@ -106,7 +106,7 @@ function node_add($node_type) { 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'langcode' => $langcode ? $langcode : language_default()->langcode, - )); + ))->getBCEntity(); drupal_set_title(t('Create @name', array('@name' => $node_type->name)), PASS_THROUGH); $output = entity_get_form($node); @@ -116,7 +116,7 @@ function node_add($node_type) { /** * Generates a node preview. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The node to preview. * * @return @@ -124,7 +124,7 @@ function node_add($node_type) { * * @see node_form_build_preview() */ -function node_preview(Node $node) { +function node_preview(EntityInterface $node) { if (node_access('create', $node) || node_access('update', $node)) { _field_invoke_multiple('load', 'node', array($node->nid => $node)); // Load the user's name when needed. diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module index 4efee88..deaf9bb 100644 --- a/core/modules/node/tests/modules/node_access_test/node_access_test.module +++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -9,7 +9,7 @@ * a special 'node test view' permission. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Implements hook_node_grants(). @@ -32,7 +32,7 @@ function node_access_test_node_grants($account, $op) { /** * Implements hook_node_access_records(). */ -function node_access_test_node_access_records(Node $node) { +function node_access_test_node_access_records(EntityInterface $node) { $grants = array(); // For NodeAccessBaseTableTestCase, only set records for private nodes. if (!state()->get('node_access_test.private') || $node->private) { @@ -207,28 +207,28 @@ function node_access_test_node_load($nodes, $types) { * Implements hook_node_predelete(). */ -function node_access_test_node_predelete(Node $node) { +function node_access_test_node_predelete(EntityInterface $node) { db_delete('node_access_test')->condition('nid', $node->nid)->execute(); } /** * Implements hook_node_insert(). */ -function node_access_test_node_insert(Node $node) { +function node_access_test_node_insert(EntityInterface $node) { _node_access_test_node_write($node); } /** * Implements hook_nodeapi_update(). */ -function node_access_test_node_update(Node $node) { +function node_access_test_node_update(EntityInterface $node) { _node_access_test_node_write($node); } /** * Helper for node insert/update. */ -function _node_access_test_node_write(Node $node) { +function _node_access_test_node_write(EntityInterface $node) { if (isset($node->private)) { db_merge('node_access_test') ->key(array('nid' => $node->nid)) diff --git a/core/modules/node/tests/modules/node_test/node_test.module b/core/modules/node/tests/modules/node_test/node_test.module index 36b59c9..467af62 100644 --- a/core/modules/node/tests/modules/node_test/node_test.module +++ b/core/modules/node/tests/modules/node_test/node_test.module @@ -8,7 +8,7 @@ * interaction with the Node module. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; /** @@ -30,7 +30,7 @@ function node_test_node_load($nodes, $types) { /** * Implements hook_node_view(). */ -function node_test_node_view(Node $node, EntityDisplay $display, $view_mode) { +function node_test_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { if ($view_mode == 'rss') { // Add RSS elements and namespaces when building the RSS feed. $node->rss_elements[] = array( @@ -71,7 +71,7 @@ function node_test_node_grants($account, $op) { /** * Implements hook_node_access_records(). */ -function node_test_node_access_records(Node $node) { +function node_test_node_access_records(EntityInterface $node) { // Return nothing when testing for empty responses. if (!empty($node->disable_node_access)) { return; @@ -105,7 +105,7 @@ function node_test_node_access_records(Node $node) { /** * Implements hook_node_access_records_alter(). */ -function node_test_node_access_records_alter(&$grants, Node $node) { +function node_test_node_access_records_alter(&$grants, EntityInterface $node) { if (!empty($grants)) { foreach ($grants as $key => $grant) { // Alter grant from test_page_realm to test_alter_realm and modify the gid. @@ -128,7 +128,7 @@ function node_test_node_grants_alter(&$grants, $account, $op) { /** * Implements hook_node_presave(). */ -function node_test_node_presave(Node $node) { +function node_test_node_presave(EntityInterface $node) { if ($node->title == 'testing_node_presave') { // Sun, 19 Nov 1978 05:00:00 GMT $node->created = 280299600; @@ -146,7 +146,7 @@ function node_test_node_presave(Node $node) { /** * Implements hook_node_update(). */ -function node_test_node_update(Node $node) { +function node_test_node_update(EntityInterface $node) { // Determine changes on update. if (!empty($node->original) && $node->original->title == 'test_changes') { if ($node->original->title != $node->title) { @@ -172,7 +172,7 @@ function node_test_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\Entity * * @see \Drupal\node\Tests\NodeSaveTest::testNodeSaveOnInsert() */ -function node_test_node_insert(Node $node) { +function node_test_node_insert(EntityInterface $node) { // Set the node title to the node ID and save. if ($node->title == 'new') { $node->title = 'Node '. $node->nid; diff --git a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module index 359af1f..9eaa4f1 100644 --- a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module +++ b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module @@ -5,12 +5,12 @@ * A module implementing node related hooks to test API interaction. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Implements hook_node_insert(). */ -function node_test_exception_node_insert(Node $node) { +function node_test_exception_node_insert(EntityInterface $node) { if ($node->title == 'testing_transaction_exception') { throw new Exception('Test exception for rollback.'); } diff --git a/core/modules/path/path.module b/core/modules/path/path.module index 7d3fadd..d58ef1a 100644 --- a/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -5,7 +5,7 @@ * Enables users to rename URLs. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\taxonomy\Plugin\Core\Entity\Term; @@ -187,7 +187,7 @@ function path_form_element_validate($element, &$form_state, $complete_form) { /** * Implements hook_node_insert(). */ -function path_node_insert(Node $node) { +function path_node_insert(EntityInterface $node) { if (isset($node->path)) { $alias = trim($node->path['alias']); // Only save a non-empty alias. @@ -203,7 +203,7 @@ function path_node_insert(Node $node) { /** * Implements hook_node_update(). */ -function path_node_update(Node $node) { +function path_node_update(EntityInterface $node) { if (isset($node->path)) { $path = $node->path; $alias = trim($path['alias']); @@ -224,7 +224,7 @@ function path_node_update(Node $node) { /** * Implements hook_node_predelete(). */ -function path_node_predelete(Node $node) { +function path_node_predelete(EntityInterface $node) { // Delete all aliases associated with this node. drupal_container()->get('path.crud')->delete(array('source' => 'node/' . $node->nid)); } diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php index 45488bd..c413d86 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php @@ -7,7 +7,7 @@ namespace Drupal\rdf\Tests; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\simpletest\WebTestBase; /** @@ -71,10 +71,10 @@ function testAttributesInTracker() { * * Tests the tracker page for RDFa markup. * - * @param Node $node + * @param EntityInterface $node * The node just created. */ - function _testBasicTrackerRdfaMarkup(Node $node) { + function _testBasicTrackerRdfaMarkup(EntityInterface $node) { $node_uri = url('node/' . $node->nid, array('absolute' => TRUE)); $user_uri = url('user/' . $node->uid, array('absolute' => TRUE)); diff --git a/core/modules/search/search.module b/core/modules/search/search.module index 375c43f..85e58d3 100644 --- a/core/modules/search/search.module +++ b/core/modules/search/search.module @@ -5,7 +5,7 @@ * Enables site-wide keyword searching. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Matches all 'N' Unicode character classes (numbers) @@ -792,7 +792,7 @@ function search_touch_node($nid) { /** * Implements hook_node_update_index(). */ -function search_node_update_index(Node $node) { +function search_node_update_index(EntityInterface $node) { // Transplant links to a node into the target node. $result = db_query("SELECT caption FROM {search_node_links} WHERE nid = :nid", array(':nid' => $node->nid), array('target' => 'slave')); $output = array(); @@ -807,7 +807,7 @@ function search_node_update_index(Node $node) { /** * Implements hook_node_update(). */ -function search_node_update(Node $node) { +function search_node_update(EntityInterface $node) { // Reindex the node when it is updated. The node is automatically indexed // when it is added, simply by being added to the node table. search_touch_node($node->nid); diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module index f6a9d48..758f8df 100644 --- a/core/modules/statistics/statistics.module +++ b/core/modules/statistics/statistics.module @@ -5,7 +5,7 @@ * Logs and displays content statistics for a site. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; /** @@ -47,7 +47,7 @@ function statistics_permission() { /** * Implements hook_node_view(). */ -function statistics_node_view(Node $node, EntityDisplay $display, $view_mode) { +function statistics_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { if (!empty($node->nid) && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) { $node->content['#attached']['library'][] = array('statistics', 'drupal.statistics'); $settings = array('data' => array('nid' => $node->nid), 'url' => url(drupal_get_path('module', 'statistics') . '/statistics.php')); @@ -199,7 +199,7 @@ function _statistics_format_item($title, $path) { /** * Implements hook_node_predelete(). */ -function statistics_node_predelete(Node $node) { +function statistics_node_predelete(EntityInterface $node) { // clean up statistics table when node is deleted db_delete('node_counter') ->condition('nid', $node->nid) diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php index e3ad6fe..6f42262 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php @@ -583,4 +583,28 @@ protected function assertComputedProperties($entity_type) { $entity = entity_load($entity_type, $entity->id()); $this->assertEqual($entity->field_test_text->processed, $target, format_string('%entity_type: Text is processed with the default filter.', array('%entity_type' => $entity_type))); } + + /** + * Tests using the entity BC decorator with entity properties. + * + * @todo: Remove once the entit BC decorator is removed. + * @see \Drupal\Core\Entity\EntityBCDecorator + */ + public function testBCDecorator() { + // Test using comment subject via the BC decorator. + module_enable(array('node', 'comment')); + $node = $this->drupalCreateNode(); + $comment = entity_create('comment', array( + 'nid' => $node->nid, + 'subject' => 'old-value', + )); + $comment->save(); + + // Test reading. + $bc_entity = $comment->getBCEntity(); + $this->assertEqual($bc_entity->subject, 'old-value', 'Accessing entity property via BC decorator.'); + // Test writing. + $bc_entity->subject = 'new'; + $this->assertEqual($comment->subject->value, 'new', 'Updated entity property via BC decorator.'); + } } diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 4b1a2b1..8552bf0 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -5,10 +5,9 @@ * Enables the organization of content into categories. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\taxonomy\Plugin\Core\Entity\Term; use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary; -use Drupal\Core\Entity\EntityInterface; /** * Denotes that no term in the vocabulary has a parent. @@ -1375,7 +1374,7 @@ function taxonomy_field_presave(EntityInterface $entity, $field, $instance, $lan /** * Implements hook_node_insert(). */ -function taxonomy_node_insert(Node $node) { +function taxonomy_node_insert(EntityInterface $node) { // Add taxonomy index entries for the node. taxonomy_build_node_index($node); } @@ -1386,7 +1385,7 @@ function taxonomy_node_insert(Node $node) { * The index lists all terms that are related to a given node entity, and is * therefore maintained at the entity level. * - * @param \Drupal\node\Plugin\Core\Entity\Node $node + * @param \Drupal\node\Plugin\Core\Entity\EntityInterface $node * The node entity. */ function taxonomy_build_node_index($node) { @@ -1452,7 +1451,7 @@ function taxonomy_build_node_index($node) { /** * Implements hook_node_update(). */ -function taxonomy_node_update(Node $node) { +function taxonomy_node_update(EntityInterface $node) { // Always rebuild the node's taxonomy index entries on node save. taxonomy_delete_node_index($node); taxonomy_build_node_index($node); @@ -1461,7 +1460,7 @@ function taxonomy_node_update(Node $node) { /** * Implements hook_node_predelete(). */ -function taxonomy_node_predelete(Node $node) { +function taxonomy_node_predelete(EntityInterface $node) { // Clean up the {taxonomy_index} table when nodes are deleted. taxonomy_delete_node_index($node); } @@ -1469,10 +1468,10 @@ function taxonomy_node_predelete(Node $node) { /** * Deletes taxonomy index entries for a given node. * - * @param Drupal\node\Plugin\Core\Entity\Node $node + * @param Drupal\node\Plugin\Core\Entity\EntityInterface $node * The node entity. */ -function taxonomy_delete_node_index(Node $node) { +function taxonomy_delete_node_index(EntityInterface $node) { if (config('taxonomy.settings')->get('maintain_index_table')) { db_delete('taxonomy_index')->condition('nid', $node->nid)->execute(); } diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module index 30a0dbb..125b5da 100644 --- a/core/modules/tracker/tracker.module +++ b/core/modules/tracker/tracker.module @@ -5,7 +5,7 @@ * Tracks recent content posted by a user or users. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Implements hook_help(). @@ -193,7 +193,7 @@ function _tracker_user_access($account) { * * Adds new tracking information for this node since it's new. */ -function tracker_node_insert(Node $node, $arg = 0) { +function tracker_node_insert(EntityInterface $node, $arg = 0) { _tracker_add($node->nid, $node->uid, $node->changed); } @@ -202,7 +202,7 @@ function tracker_node_insert(Node $node, $arg = 0) { * * Adds tracking information for this node since it's been updated. */ -function tracker_node_update(Node $node, $arg = 0) { +function tracker_node_update(EntityInterface $node, $arg = 0) { _tracker_add($node->nid, $node->uid, $node->changed); } @@ -211,7 +211,7 @@ function tracker_node_update(Node $node, $arg = 0) { * * Deletes tracking information for a node. */ -function tracker_node_predelete(Node $node, $arg = 0) { +function tracker_node_predelete(EntityInterface $node, $arg = 0) { db_delete('tracker_node') ->condition('nid', $node->nid) ->execute(); diff --git a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php index 6e3dccf..df2c386 100644 --- a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php +++ b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php @@ -7,7 +7,7 @@ namespace Drupal\translation\Tests; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\simpletest\WebTestBase; /** @@ -362,7 +362,7 @@ function createPage($title, $body, $langcode = NULL) { /** * Creates a translation for a basic page in the specified language. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * The basic page to create the translation for. * @param $title * The title of a basic page in the specified language. @@ -374,7 +374,7 @@ function createPage($title, $body, $langcode = NULL) { * @return * Translation object. */ - function createTranslation(Node $node, $title, $body, $langcode) { + function createTranslation(EntityInterface $node, $title, $body, $langcode) { $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $langcode))); $field_langcode = LANGUAGE_NOT_SPECIFIED; diff --git a/core/modules/translation/tests/translation_test.module b/core/modules/translation/tests/translation_test.module index d5db14d..ac1397f 100644 --- a/core/modules/translation/tests/translation_test.module +++ b/core/modules/translation/tests/translation_test.module @@ -5,11 +5,11 @@ * Mock module for content translation tests. */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Implements hook_node_insert(). */ -function translation_test_node_insert(Node $node) { +function translation_test_node_insert(EntityInterface $node) { drupal_write_record('node', $node, 'nid'); } diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module index a864120..41d8e83 100644 --- a/core/modules/translation/translation.module +++ b/core/modules/translation/translation.module @@ -19,7 +19,7 @@ * date (0) or needs to be updated (1). */ -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; use Drupal\entity\Plugin\Core\Entity\EntityDisplay; /** @@ -248,7 +248,7 @@ function translation_form_node_form_alter(&$form, &$form_state) { * translation set. If no language provider is enabled, "fall back" to simple * links built through the result of translation_node_get_translations(). */ -function translation_node_view(Node $node, EntityDisplay $display, $view_mode) { +function translation_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) { // If the site has no translations or is not multilingual we have no content // translation links to display. if (isset($node->tnid) && language_multilingual() && $translations = translation_node_get_translations($node->tnid)) { @@ -302,7 +302,7 @@ function translation_node_view(Node $node, EntityDisplay $display, $view_mode) { /** * Implements hook_node_prepare(). */ -function translation_node_prepare(Node $node) { +function translation_node_prepare(EntityInterface $node) { // Only act if we are dealing with a content type supporting translations. if (translation_supported_type($node->type) && // And it's a new node. @@ -344,7 +344,7 @@ function translation_node_prepare(Node $node) { /** * Implements hook_node_insert(). */ -function translation_node_insert(Node $node) { +function translation_node_insert(EntityInterface $node) { // Only act if we are dealing with a content type supporting translations. if (translation_supported_type($node->type)) { if (!empty($node->translation_source)) { @@ -379,7 +379,7 @@ function translation_node_insert(Node $node) { /** * Implements hook_node_update(). */ -function translation_node_update(Node $node) { +function translation_node_update(EntityInterface $node) { // Only act if we are dealing with a content type supporting translations. if (translation_supported_type($node->type)) { if (isset($node->translation) && $node->translation && !empty($node->langcode) && $node->tnid) { @@ -408,7 +408,7 @@ function translation_node_update(Node $node) { * * Ensures that duplicate translations can't be created for the same source. */ -function translation_node_validate(Node $node, $form, &$form_state) { +function translation_node_validate(EntityInterface $node, $form, &$form_state) { // Only act on translatable nodes with a tnid or translation_source. $form_node = $form_state['controller']->getEntity($form_state); if (translation_supported_type($node->type) && (!empty($node->tnid) || !empty($form_node->translation_source->nid))) { @@ -423,7 +423,7 @@ function translation_node_validate(Node $node, $form, &$form_state) { /** * Implements hook_node_predelete(). */ -function translation_node_predelete(Node $node) { +function translation_node_predelete(EntityInterface $node) { // Only act if we are dealing with a content type supporting translations. if (translation_supported_type($node->type)) { translation_remove_from_set($node); diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc index 53b91c8..e3ca960 100644 --- a/core/modules/translation/translation.pages.inc +++ b/core/modules/translation/translation.pages.inc @@ -6,12 +6,12 @@ */ use Drupal\Component\Utility\NestedArray; -use Drupal\node\Plugin\Core\Entity\Node; +use Drupal\Core\Entity\EntityInterface; /** * Page callback: Displays a list of a node's translations. * - * @param Drupal\node\Node $node + * @param \Drupal\Core\Entity\EntityInterface $node * A node entity. * * @return @@ -19,7 +19,7 @@ * * @see translation_menu() */ -function translation_node_overview(Node $node) { +function translation_node_overview(EntityInterface $node) { include_once DRUPAL_ROOT . '/core/includes/language.inc'; if ($node->tnid) {