diff --git a/core/modules/moderation/moderation.info.yml b/core/modules/moderation/moderation.info.yml new file mode 100644 index 0000000..b963683 --- /dev/null +++ b/core/modules/moderation/moderation.info.yml @@ -0,0 +1,8 @@ +name: Moderation +type: module +description: 'Moderate revisionable entities between states.' +package: Core +version: VERSION +core: 8.x +dependencies: + - options diff --git a/core/modules/moderation/moderation.links.task.yml b/core/modules/moderation/moderation.links.task.yml new file mode 100644 index 0000000..7957ee9 --- /dev/null +++ b/core/modules/moderation/moderation.links.task.yml @@ -0,0 +1,4 @@ +node.draft: + title: Draft + route_name: node.draft + base_route: entity.node.canonical diff --git a/core/modules/moderation/moderation.module b/core/modules/moderation/moderation.module new file mode 100644 index 0000000..a264243 --- /dev/null +++ b/core/modules/moderation/moderation.module @@ -0,0 +1,49 @@ +getHandlerClasses(); + $handlers['form']['default'] = 'Drupal\moderation\Form\NodeForm'; + $handlers['form']['edit'] = $handlers['form']['default']; + $entity_type->setHandlerClass('form', $handlers['form']); + } +} + +/** + * Determine if the given node has a draft. + * + * Draft is simply defined here as an unpublished revision that is newer than + * the published node. + * + * @param \Drupal\core\NodeInterface $node + * The node object. + * + * @return bool|int + * The revision ID if a draft exists, otherwise FALSE. + */ +function moderation_node_has_draft(NodeInterface $node) { + $current_revision = $node->getRevisionId(); + $node_storage = \Drupal::service('entity.manager')->getStorage('node'); + $vids = $node_storage->revisionIds($node); + + // Filter out vids less than or equal to current revision. + asort($vids); + $filtered = array_filter($vids, function ($var) use ($current_revision) { + return $var > $current_revision; + }); + return array_pop($filtered) ?: FALSE; +} diff --git a/core/modules/moderation/moderation.routing.yml b/core/modules/moderation/moderation.routing.yml new file mode 100644 index 0000000..b52bd23 --- /dev/null +++ b/core/modules/moderation/moderation.routing.yml @@ -0,0 +1,7 @@ +node.draft: + path: '/node/{node}/draft' + defaults: + _controller: 'Drupal\moderation\Controller\DraftController::show' + _title_callback: 'Drupal\moderation\Controller\DraftController::draftPageTitle' + requirements: + _access_node_draft: 'view' diff --git a/core/modules/moderation/moderation.services.yml b/core/modules/moderation/moderation.services.yml new file mode 100644 index 0000000..08193dc --- /dev/null +++ b/core/modules/moderation/moderation.services.yml @@ -0,0 +1,6 @@ +services: + access_check.node.draft: + class: Drupal\moderation\Access\DraftAccess + arguments: ['@entity.manager'] + tags: + - { name: access_check, applies_to: _access_node_draft } diff --git a/core/modules/moderation/src/Access/DraftAccess.php b/core/modules/moderation/src/Access/DraftAccess.php new file mode 100644 index 0000000..9f97c84 --- /dev/null +++ b/core/modules/moderation/src/Access/DraftAccess.php @@ -0,0 +1,54 @@ +nodeStorage = $entity_manager->getStorage('node'); + $this->nodeAccess = $entity_manager->getAccessControlHandler('node'); + } + + /** + * {@inheritdoc} + */ + public function access(Route $route, AccountInterface $account, NodeInterface $node = NULL) { + // @todo needs to check node access as well. + return AccessResult::allowedIf(moderation_node_has_draft($node)); + } + +} diff --git a/core/modules/moderation/src/Controller/DraftController.php b/core/modules/moderation/src/Controller/DraftController.php new file mode 100644 index 0000000..63f7111 --- /dev/null +++ b/core/modules/moderation/src/Controller/DraftController.php @@ -0,0 +1,34 @@ +revisionShow(moderation_node_has_draft($node)); + } + + /** + * Display the title of the draft. + */ + public function draftPageTitle(NodeInterface $node) { + return $this->revisionPageTitle(moderation_node_has_draft($node)); + } + +} diff --git a/core/modules/moderation/src/Form/NodeForm.php b/core/modules/moderation/src/Form/NodeForm.php new file mode 100644 index 0000000..2e5fb71 --- /dev/null +++ b/core/modules/moderation/src/Form/NodeForm.php @@ -0,0 +1,90 @@ +getEntity(); + if (!$node->isNew() && $node->type->entity->isNewRevision() && $revision_id = moderation_node_has_draft($node)) { + /** @var \Drupal\node\NodeStorage $storage */ + $storage = \Drupal::service('entity.manager')->getStorage('node'); + $this->entity = $storage->loadRevision($revision_id); + $this->isDraft = TRUE; + } + } + + /** + * {@inheritdoc} + */ + protected function actions(array $form, FormStateInterface $form_state) { + $element = parent::actions($form, $form_state); + + /** @var \Drupal\node\NodeInterface $node */ + $node = $this->getEntity(); + if (!$node->isNew() && $node->type->entity->isNewRevision() && $node->isPublished()) { + // Add a 'save as draft' action. + $element['draft'] = $element['submit']; + $element['draft']['#access'] = TRUE; + $element['draft']['#dropbutton'] = 'save'; + $element['draft']['#value'] = $this->t('Save as draft'); + array_unshift($element['draft']['#submit'], '::draft'); + + // Put the draft button first. + $element['draft']['#weight'] = -10; + } + + // If this is an existing draft, change the publish button text. + if ($this->isDraft) { + $element['publish']['#value'] = t('Save and publish'); + } + + return $element; + } + + /** + * Save node as a draft. + */ + public function draft(array $form, FormStateInterface $form_state) { + $this->entity->isDefaultRevision(FALSE); + } + + /** + * Set default revision if this was previously a draft, and is now being + * published. + * + * {@inheritdoc} + */ + public function publish(array $form, FormStateInterface $form_state) { + $node = parent::publish($form, $form_state); + if ($this->isDraft) { + $node->isDefaultRevision(TRUE); + } + } + +} + + diff --git a/core/modules/moderation/src/Tests/ModerationNodeTest.php b/core/modules/moderation/src/Tests/ModerationNodeTest.php new file mode 100644 index 0000000..344b959 --- /dev/null +++ b/core/modules/moderation/src/Tests/ModerationNodeTest.php @@ -0,0 +1,130 @@ +nodeType = NodeType::load('article'); + $this->nodeType->setNewRevision(TRUE); + $this->nodeType->save(); + + // Set up an admin user. + $this->adminUser = $this->drupalCreateUser(['bypass node access', 'administer nodes']); + } + + /** + * Checks node edit functionality. + */ + function testBasicForwarRevisions() { + $this->drupalLogin($this->adminUser); + $this->drupalGet('node/add/article'); + + // For new content, the 'Save as draft' button should not be present. + $this->assertButtons([t('Save and publish'), t('Save as unpublished')]); + + // Create an unpublished node. + $unpublished_one_values = [ + // While standard to use randomName() for these values, human-readable + // text is easier to debug in this context. + 'title[0][value]' => 'Unpublished one title', + 'body[0][value]' => 'Unpublished one body', + ]; + $this->drupalPostForm('node/add/article', $unpublished_one_values, t('Save as unpublished')); + $node = $this->drupalGetNodeByTitle($unpublished_one_values['title[0][value]']); + + // Verify that the admin user can see the node's page. + $this->drupalGet('node/' . $node->id()); + $this->assertResponse(200, t('Draft is accessible to the admin user.')); + + // There should not be a draft tab since there is only a single unpublished + // revision. + $this->assertNoLink(t('Draft')); + + // Make another revision and publish. + $this->drupalGet('node/' . $node->id() .'/edit'); + $this->assertButtons([t('Save and keep unpublished'), t('Save and publish')]); + $published_one_values = [ + 'title[0][value]' => 'Published one title', + 'body[0][value]' => 'Published one title', + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $published_one_values, t('Save and publish')); + + // Verify published values are on the node page. + $this->drupalGet('node/' . $node->id()); + $this->assertText($published_one_values['title[0][value]'], 'Published title found'); + $this->assertText($published_one_values['body[0][value]'], t('Published body found')); + + // There should still be no draft tab since the latest revision is + // published. + $this->assertNoLink(t('Draft')); + + // Create a draft. + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertButtons([t('Save as draft'), t('Save and keep published'), t('Save and unpublish')]); + $draft_one_values = [ + 'title[0][value]' => 'Draft one title', + 'body[0][value]' => 'Draft one body', + ]; + $this->drupalPostForm('node/1/edit', $draft_one_values, t('Save as draft')); + + // Now there should be a draft tab. + $this->assertLink(t('Draft')); + + // Verify that the admin user can see the node's page. + $this->drupalGet('node/' . $node->id()); + $this->assertText($published_one_values['title[0][value]'], 'The published title stays the same when a new draft is created.'); + $this->assertText($published_one_values['body[0][value]'], 'The published body stays the same when a new draft is created.'); + + // The draft should be loaded in the edit form. + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->assertRaw($draft_one_values['title[0][value]'], 'The draft title is loaded on the edit form.'); + $this->assertRaw($draft_one_values['body[0][value]'], 'The draft body is loaded on the edit form.'); + $this->assertButtons([t('Save as draft'), t('Save and publish'), t('Save and unpublish')]); + $this->drupalPostForm('node/1/edit', $draft_one_values, t('Save and publish')); + + // Publish the draft. + $this->drupalGet('node/' . $node->id()); + $this->assertText($draft_one_values['title[0][value]'], 'Published title found'); + $this->assertText($draft_one_values['body[0][value]'], t('Published body found')); + } + +} + diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php index 9517b51..29d6c47 100644 --- a/core/modules/node/src/NodeForm.php +++ b/core/modules/node/src/NodeForm.php @@ -352,6 +352,9 @@ public function preview(array $form, FormStateInterface $form_state) { * An associative array containing the structure of the form. * @param $form_state * The current state of the form. + * + * @return \Drupal\node\NodeInterface + * The node object. */ public function publish(array $form, FormStateInterface $form_state) { $node = $this->entity; @@ -366,6 +369,9 @@ public function publish(array $form, FormStateInterface $form_state) { * An associative array containing the structure of the form. * @param $form_state * The current state of the form. + * + * @return \Drupal\node\NodeInterface + * The node object. */ public function unpublish(array $form, FormStateInterface $form_state) { $node = $this->entity; diff --git a/core/modules/node/src/Tests/AssertButtonsTrait.php b/core/modules/node/src/Tests/AssertButtonsTrait.php new file mode 100644 index 0000000..2b54cc7 --- /dev/null +++ b/core/modules/node/src/Tests/AssertButtonsTrait.php @@ -0,0 +1,53 @@ +xpath('//input[@type="submit"][@value="Save"]'); + + // Verify that the number of buttons passed as parameters is + // available in the dropbutton widget. + if ($dropbutton) { + $i = 0; + $count = count($buttons); + + // Assert there is no save button. + $this->assertTrue(empty($save_button)); + + // Dropbutton elements. + $elements = $this->xpath('//div[@class="dropbutton-wrapper"]//input[@type="submit"]'); + $this->assertEqual($count, count($elements)); + foreach ($elements as $element) { + $value = isset($element['value']) ? (string) $element['value'] : ''; + $this->assertEqual($buttons[$i], $value); + $i++; + } + } + else { + // Assert there is a save button. + $this->assertTrue(!empty($save_button)); + $this->assertNoRaw('dropbutton-wrapper'); + } + } + +} diff --git a/core/modules/node/src/Tests/NodeFormButtonsTest.php b/core/modules/node/src/Tests/NodeFormButtonsTest.php index b5c2df5..8fe115a 100644 --- a/core/modules/node/src/Tests/NodeFormButtonsTest.php +++ b/core/modules/node/src/Tests/NodeFormButtonsTest.php @@ -7,6 +7,8 @@ namespace Drupal\node\Tests; +use Drupal\node\Tests\AssertButtonsTrait; + /** * Tests all the different buttons on the node form. * @@ -14,6 +16,8 @@ */ class NodeFormButtonsTest extends NodeTestBase { + use AssertButtonsTrait; + /** * A normal logged in user. * @@ -135,41 +139,4 @@ function testNodeFormButtons() { $this->assertFalse($node_3->isPublished(), 'Node is unpublished'); } - /** - * Assert method to verify the buttons in the dropdown element. - * - * @param array $buttons - * A collection of buttons to assert for on the page. - * @param bool $dropbutton - * Whether to check if the buttons are in a dropbutton widget or not. - */ - public function assertButtons($buttons, $dropbutton = TRUE) { - - // Try to find a Save button. - $save_button = $this->xpath('//input[@type="submit"][@value="Save"]'); - - // Verify that the number of buttons passed as parameters is - // available in the dropbutton widget. - if ($dropbutton) { - $i = 0; - $count = count($buttons); - - // Assert there is no save button. - $this->assertTrue(empty($save_button)); - - // Dropbutton elements. - $elements = $this->xpath('//div[@class="dropbutton-wrapper"]//input[@type="submit"]'); - $this->assertEqual($count, count($elements)); - foreach ($elements as $element) { - $value = isset($element['value']) ? (string) $element['value'] : ''; - $this->assertEqual($buttons[$i], $value); - $i++; - } - } - else { - // Assert there is a save button. - $this->assertTrue(!empty($save_button)); - $this->assertNoRaw('dropbutton-wrapper'); - } - } } diff --git a/modules/custom/moderation/lib/Drupal/moderation/Tests/ModerationNodeTest.php b/modules/custom/moderation/lib/Drupal/moderation/Tests/ModerationNodeTest.php deleted file mode 100644 index 02ee8dc..0000000 --- a/modules/custom/moderation/lib/Drupal/moderation/Tests/ModerationNodeTest.php +++ /dev/null @@ -1,181 +0,0 @@ - 'Node Moderation', - 'description' => 'Create and edit forward revisions of a node.', - 'group' => 'Moderation', - ); - } - - function setUp() { - parent::setUp(); - - // Use revisions by default. - $node_options = variable_get('node_options_article', array('status', 'promote')); - $node_options[] = 'revision'; - variable_set('node_options_article', $node_options); - - // Set up an admin user. - $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes')); - } - - /** - * Helper function for checking if the draft tab exists. - */ - function _checkForDraftTab() { - $this->assertText('View draft', 'Draft Tab is present'); - } - - /** - * Helper function for checking if the draft tab does not exists. - */ - function _checkForNoDraftTab() { - $this->assertNoText('View draft', 'Draft Tab is not present'); - } - - /** - * Checks node edit functionality. - */ - function testBasicForwarRevisions() { - $this->drupalLogin($this->admin_user); - $this->drupalGet('node/add/article'); - - // Verify moderation select list is present. - // @todo, this check will change when the moderation select list is not coming - // from a field. - $this->assertRaw('edit-field-moderation-und', t('Moderation select list is present.')); - - // Verify that the published checkbox is hidden. - // @todo, Show this be an xpath check? - $this->assertNoRaw('id="edit-status"', t('The published checkbox is not present')); - - - // Helper variables for forms. - $langcode = LANGUAGE_NOT_SPECIFIED; - $title_key = "title"; - $body_key = "body[$langcode][0][value]"; - $moderation_key = "field_moderation[$langcode]"; - - /** - * Make a draft revision. - */ - $draft_one_values = array( - // @todo, should these values go in t()? - // It seems to be a standard to use randomName() for these kinds of values. - // Human-readable text seems much easier to debug. - $title_key => 'Draft One Title', - $body_key => 'Draft One Body field', - $moderation_key => 'draft', - ); - $this->drupalPost('node/add/article', $draft_one_values, t('Save')); - - // Verify that the admin user can see the node's page. - $this->drupalGet('node/1'); - $this->assertResponse(200, t('node/1 is accessible to the admin user.')); - $this->_checkForNoDraftTab(); - - // Verify that the anonymous user can't see the node's page. - $this->drupalLogout(); - $this->drupalGet('node/1'); - $this->assertResponse(403, t('node/1 is inaccessible as a 403 to anonymous user.')); - - - /** - * Make another draft revision. These values should be visible at node/1. - */ - $this->drupalLogin($this->admin_user); - $draft_two_values = array( - $title_key => 'Draft Two Title', - $body_key => 'Draft Two Body field', - $moderation_key => 'draft', - ); - $this->drupalPost('node/1/edit', $draft_two_values, t('Save')); - - // Verify that the admin user can see the node's page and sees the published values there. - $this->drupalGet('node/1'); - $this->assertResponse(200, t('node/1 is accessible to the admin user.')); - $this->assertText($draft_two_values[$title_key], t('draft_two_values Title found')); - $this->assertText($draft_two_values[$body_key], t('draft_two_values Body found')); - $this->_checkForNoDraftTab(); - - /** - * Make a published revision. - */ - $published_one_values = array( - $title_key => 'Published One Title', - $body_key => 'Published One Body field', - $moderation_key => 'published', - ); - $this->drupalPost('node/1/edit', $published_one_values, t('Save')); - - // Verify that the admin user can see the node's page. - $this->drupalGet('node/1'); - $this->assertResponse(200, t('node/1 is accessible to the admin user.')); - $this->_checkForNoDraftTab(); - - // Verify that the anonymous user can't see the node's page. - $this->drupalLogout(); - $this->drupalGet('node/1'); - $this->assertResponse(200, t('node/1 is accessible to the anonymous user.')); - - - /** - * Make a draft revision. - */ - $this->drupalLogin($this->admin_user); - $revision_three_values = array( - $title_key => 'Revision Three Title', - $body_key => 'Revision Three Body field', - $moderation_key => 'draft', - ); - $this->drupalPost('node/1/edit', $revision_three_values, t('Save')); - - // Verify that the admin user can see the node's page and sees the published values there. - $this->drupalGet('node/1'); - $this->assertResponse(200, t('node/1 is accessible to the admin user.')); - $this->assertText($published_one_values[$title_key], t('published_one_values Title found')); - $this->assertText($published_one_values[$body_key], t('published_one_values Body found')); - - - // Verify that the admin user sees revision three at node/1/draft. - $this->_checkForDraftTab(); - $this->drupalGet('node/1/draft'); - $this->assertResponse(200, t('node/1/draft is accessible to the admin user.')); - $this->assertText($revision_three_values[$title_key], t('revision_three_values Title found')); - $this->assertText($revision_three_values[$body_key], t('revision_three_values Body found')); - - - /** - * Go to edit page. Verify that draft node loads. - */ - $this->drupalGet('node/1/edit'); - // @todo Is there a better way to check field default values? - $this->assertRaw($revision_three_values[$title_key], 'Draft title is loaded into the form'); - $this->assertRaw($revision_three_values[$body_key], 'Draft body is loaded into the form'); - } -} diff --git a/modules/custom/moderation/moderation.info b/modules/custom/moderation/moderation.info deleted file mode 100644 index 5d98925..0000000 --- a/modules/custom/moderation/moderation.info +++ /dev/null @@ -1,4 +0,0 @@ -name = Moderation -description = Moderate revisionable entities between states. -core = 8.x -dependencies[] = options \ No newline at end of file diff --git a/modules/custom/moderation/moderation.install b/modules/custom/moderation/moderation.install deleted file mode 100644 index ac6daf5..0000000 --- a/modules/custom/moderation/moderation.install +++ /dev/null @@ -1,150 +0,0 @@ - '0', - 'entity_types' => - array ( - ), - 'settings' => - array ( - 'allowed_values' => - array ( - 'draft' => 'Draft', - 'published' => 'Published', - ), - 'allowed_values_function' => '', - 'allowed_values_function_display' => '', - ), - 'storage' => - array ( - 'type' => 'field_sql_storage', - 'settings' => - array ( - ), - 'module' => 'field_sql_storage', - 'active' => '1', - 'details' => - array ( - 'sql' => - array ( - 'FIELD_LOAD_CURRENT' => - array ( - 'field_data_field_moderation' => - array ( - 'value' => 'field_moderation_value', - ), - ), - 'FIELD_LOAD_REVISION' => - array ( - 'field_revision_field_moderation' => - array ( - 'value' => 'field_moderation_value', - ), - ), - ), - ), - ), - 'foreign keys' => - array ( - ), - 'indexes' => - array ( - 'value' => - array ( - 0 => 'value', - ), - ), - 'id' => '6', - 'field_name' => 'field_moderation', - 'type' => 'list_text', - 'module' => 'options', - 'active' => '1', - 'locked' => '0', - 'cardinality' => '1', - 'deleted' => '0', - 'columns' => - array ( - 'value' => - array ( - 'type' => 'varchar', - 'length' => 255, - 'not null' => false, - ), - ), - 'bundles' => - array ( - 'node' => - array ( - 0 => 'article', - ), - ), - ); - - // This code was generated from debug(field_info_instance('node', 'field_moderation', 'article')); - $field_instance = - array ( - 'label' => 'Moderation', - 'widget' => - array ( - 'weight' => 0, - 'type' => 'options_select', - 'module' => 'options', - 'active' => 0, - 'settings' => - array ( - ), - ), - 'settings' => - array ( - 'user_register_form' => false, - ), - 'display' => - array ( - 'default' => - array ( - 'label' => 'above', - 'type' => 'list_default', - 'settings' => - array ( - ), - 'module' => 'options', - 'weight' => 11, - ), - ), - // @todo, this should be required. - 'required' => TRUE, - 'description' => '', - 'default_value' => NULL, - 'id' => '8', - 'field_id' => '6', - 'field_name' => 'field_moderation', - 'entity_type' => 'node', - 'bundle' => 'article', - 'deleted' => '0', - ); - field_cache_clear(); - field_create_field($field_config); - field_cache_clear(); - field_create_instance($field_instance); -} diff --git a/modules/custom/moderation/moderation.module b/modules/custom/moderation/moderation.module deleted file mode 100644 index 3ead5ec..0000000 --- a/modules/custom/moderation/moderation.module +++ /dev/null @@ -1,199 +0,0 @@ -entityType(), moderation_load_active_vid($entity)); - // @todo, hard-coding for nodes might be unavoidable here. - return node_page_edit($active_revision); -} - -/** - * Implements hook_menu(). - */ -function moderation_menu() { - - $items = array(); - - // View the current draft of a node. - $items["node/%node/draft"] = array( - 'title' => 'View draft', - 'page callback' => 'moderation_view_draft', - 'page arguments' => array(1), - 'access callback' => 'moderation_draft_tab_access', - 'access arguments' => array(1), - 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, - 'type' => MENU_LOCAL_TASK, - 'weight' => -9, - ); - - return $items; -} - -/** - * @todo, this should be switched to an entity. - */ -function moderation_draft_tab_access($node) { - - if (node_access('update', $node)) { - $active_vid = moderation_load_active_vid($node); - // return TRUE if the active vid is different from the incoming vid. - return ($active_vid != $node->vid); - } - return FALSE; -} - -/** - * Utility function to load the active/editing revision of an entity. - * - * @param $entity - * The entity being acted upon. - * - * @return - * The entity with the highest revision id. - * @todo, a more intelligent way of determining active vid. - * - * @todo, make tests for just this function. - */ -function moderation_load_active_vid(Drupal\Core\Entity\EntityInterface $entity) { - - // @todo, loading entity info to get things that should be method calls. - $entity_info = entity_get_info($entity->entityType()); - - // The id() check should ensure that this entity has been saved to the db. - // Checking the revision table as a proxy for isRevisionable(). - if ($entity->id() && !empty($entity_info['revision_table'])) { - - // @todo Seems like there should be a method call for these. - if (!empty($entity_info['entity_keys']['id']) && !empty($entity_info['entity_keys']['revision'])) { - $id_key = $entity_info['entity_keys']['id']; - $revision_key = $entity_info['entity_keys']['revision']; - - $revision_table = $entity_info['revision_table']; - // @todo, node_revision can be derived from entity_info. Along with all of the - // other keys here. - $highest_vid = db_select($revision_table, 'rt') - ->fields('rt', array($revision_key)) - ->condition($id_key, $entity->id()) - ->range(0,1) - ->orderBy('rt.' . $revision_key, 'DESC') - ->execute() - ->fetchCol(); - - $highest_vid = reset($highest_vid); - return $highest_vid; - } - } - - // @todo, better error handling? - return FALSE; -} - -/** - * Displays the current draft the node, if it is not published. - * - * @param $node - * The node being acted upon. - * - * @return - * A fully themed node page. - */ -function moderation_view_draft(Drupal\Core\Entity\EntityInterface $entity) { - - // @todo, this function is not tied to nodes but the related functions are. - - // Replace "vid" with something abstracted. - $forward_revision = entity_revision_load($entity->entityType(), moderation_load_active_vid($entity)); - return moderation_router_item_page_callback($forward_revision); -} - -/** - * Get the menu router item for nodes. - * - * @param $node - * The node being acted upon. - * @return - * A fully themed node page. - */ -function moderation_router_item_page_callback($node) { - $router_item = menu_get_item('node/' . $node->nid); - if ($router_item['include_file']) { - require_once DRUPAL_ROOT . '/' . $router_item['include_file']; - } - - // Call whatever function is assigned to the main node path but pass the - // current node as an argument. This approach allows for the reuse of of Panel - // definition acting on node/%node. - return $router_item['page_callback']($node); -} - -/** - * Implements hook_entity_presave(); - **/ -function moderation_entity_presave(Drupal\Core\Entity\EntityInterface $entity) { - - $field_moderation = $entity->get('field_moderation'); - - // @todo, In a full implementation of this module there should be a much cleaner - // way of getting this value. - if (!empty($field_moderation[LANGUAGE_NOT_SPECIFIED][0]['value'])) { - $moderation_value = $field_moderation[LANGUAGE_NOT_SPECIFIED][0]['value']; - - // If "published," set status as TRUE; - // @todo A full implementation of this module would do better than check for a hardcoded string. - // @todo, this might belong better in hook_node_presave() since 'status' - // is a node property here. - if ($moderation_value === 'published') { - $entity->set('status', TRUE); - } else { - $entity->set('status', FALSE); - - // A new revision entity would also be the default entity. - if (!$entity->isNew()) { - - $original_revision = $entity->get('original'); - - if (!empty($original_revision)) { - $entity_status = $original_revision->get('status'); - if (!empty($entity_status)) { - $entity->set('isDefaultRevision', FALSE); - } - } - } - } - } -} - -/** - * Implments hook_form_alter(). - */ -function moderation_form_alter(&$form, &$form_state, $form_id) { - - // @todo, In a real implementation, this would need a more intelligent check for - // whether this is a form that should be altered. - if (!empty($form['field_moderation']) && !empty($form_state['entity'])) { - - // Restrict access to the Published checkbox. Moderation module will take over - // the published behavior. - if (!empty($form['options']['status'])) { - $form['options']['status']['#access'] = FALSE; - // @todo validate the state selected. There could be restrictions on when - // a state can be entered. - // $form['#validate'][] = 'moderation_form_alter_validate'; - } - } -}