Update to Drupal 8.0.5. For more information, see https://www.drupal.org/node/2679347
This commit is contained in:
parent
2a9f1f148d
commit
fd3b12cf27
251 changed files with 5439 additions and 957 deletions
|
@ -88,7 +88,10 @@ class BookBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
$depth = 1;
|
||||
while (!empty($book['p' . ($depth + 1)])) {
|
||||
if (!empty($parent_books[$book['p' . $depth]]) && ($parent_book = $parent_books[$book['p' . $depth]])) {
|
||||
if ($parent_book->access('view', $this->account)) {
|
||||
$access = $parent_book->access('view', $this->account, TRUE);
|
||||
$breadcrumb->addCacheableDependency($access);
|
||||
if ($access->isAllowed()) {
|
||||
$breadcrumb->addCacheableDependency($parent_book);
|
||||
$links[] = Link::createFromRoute($parent_book->label(), 'entity.node.canonical', array('node' => $parent_book->id()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -397,7 +397,7 @@ class BookManager implements BookManagerInterface {
|
|||
foreach ($tree as $data) {
|
||||
if ($data['link']['depth'] > $depth_limit) {
|
||||
// Don't iterate through any links on this level.
|
||||
break;
|
||||
return;
|
||||
}
|
||||
if (!in_array($data['link']['nid'], $exclude)) {
|
||||
$nids[] = $data['link']['nid'];
|
||||
|
@ -408,7 +408,8 @@ class BookManager implements BookManagerInterface {
|
|||
|
||||
foreach ($tree as $data) {
|
||||
$nid = $data['link']['nid'];
|
||||
if (in_array($nid, $exclude)) {
|
||||
// Check for excluded or missing node.
|
||||
if (empty($nodes[$nid])) {
|
||||
continue;
|
||||
}
|
||||
$toc[$nid] = $indent . ' ' . Unicode::truncate($nodes[$nid]->label(), 30, TRUE, TRUE);
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\book\BookManagerInterface;
|
|||
use Drupal\Core\Entity\ContentEntityForm;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -91,7 +92,8 @@ class BookOutlineForm extends ContentEntityForm {
|
|||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = $this->entity->book['original_bid'] ? $this->t('Update book outline') : $this->t('Add to book outline');
|
||||
$actions['delete']['#value'] = $this->t('Remove from book outline');
|
||||
$actions['delete']['#title'] = $this->t('Remove from book outline');
|
||||
$actions['delete']['#url'] = new Url('entity.node.book_remove_form', ['node' => $this->entity->book['nid']]);
|
||||
$actions['delete']['#access'] = $this->bookManager->checkNodeIsRemovable($this->entity);
|
||||
return $actions;
|
||||
}
|
||||
|
@ -126,11 +128,4 @@ class BookOutlineForm extends ContentEntityForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(array $form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('book-remove-form'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
209
core/modules/book/src/Tests/BookBreadcrumbTest.php
Normal file
209
core/modules/book/src/Tests/BookBreadcrumbTest.php
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\book\Tests\BookBreadcrumbTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\book\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Create a book, add pages, and test book interface.
|
||||
*
|
||||
* @group book
|
||||
*/
|
||||
class BookBreadcrumbTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('book', 'block', 'book_breadcrumb_test');
|
||||
|
||||
/**
|
||||
* A book node.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface
|
||||
*/
|
||||
protected $book;
|
||||
|
||||
/**
|
||||
* A user with permission to create and edit books.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $bookAuthor;
|
||||
|
||||
/**
|
||||
* A user without the 'node test view' permission.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUserWithoutNodeAccess;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_block');
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
// Create users.
|
||||
$this->bookAuthor = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books'));
|
||||
$this->adminUser = $this->drupalCreateUser(array('create new books', 'create book content', 'edit any book content', 'delete any book content', 'add content to books', 'administer blocks', 'administer permissions', 'administer book outlines', 'administer content types', 'administer site configuration'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new book with a page hierarchy.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface[]
|
||||
* The created book nodes.
|
||||
*/
|
||||
protected function createBreadcrumbBook() {
|
||||
// Create new book.
|
||||
$this->drupalLogin($this->bookAuthor);
|
||||
|
||||
$this->book = $this->createBookNode('new');
|
||||
$book = $this->book;
|
||||
|
||||
/*
|
||||
* Add page hierarchy to book.
|
||||
* Book
|
||||
* |- Node 0
|
||||
* |- Node 1
|
||||
* |- Node 2
|
||||
* |- Node 3
|
||||
* |- Node 4
|
||||
* |- Node 5
|
||||
* |- Node 6
|
||||
*/
|
||||
$nodes = array();
|
||||
$nodes[0] = $this->createBookNode($book->id());
|
||||
$nodes[1] = $this->createBookNode($book->id(), $nodes[0]->id());
|
||||
$nodes[2] = $this->createBookNode($book->id(), $nodes[0]->id());
|
||||
$nodes[3] = $this->createBookNode($book->id(), $nodes[2]->id());
|
||||
$nodes[4] = $this->createBookNode($book->id(), $nodes[3]->id());
|
||||
$nodes[5] = $this->createBookNode($book->id(), $nodes[4]->id());
|
||||
$nodes[6] = $this->createBookNode($book->id());
|
||||
|
||||
$this->drupalLogout();
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a book node.
|
||||
*
|
||||
* @param int|string $book_nid
|
||||
* A book node ID or set to 'new' to create a new book.
|
||||
* @param int|null $parent
|
||||
* (optional) Parent book reference ID. Defaults to NULL.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface
|
||||
* The created node.
|
||||
*/
|
||||
protected function createBookNode($book_nid, $parent = NULL) {
|
||||
// $number does not use drupal_static as it should not be reset since it
|
||||
// uniquely identifies each call to createBookNode(). It is used to ensure
|
||||
// that when sorted nodes stay in same order.
|
||||
static $number = 0;
|
||||
|
||||
$edit = array();
|
||||
$edit['title[0][value]'] = str_pad($number, 2, '0', STR_PAD_LEFT) . ' - SimpleTest test node ' . $this->randomMachineName(10);
|
||||
$edit['body[0][value]'] = 'SimpleTest test body ' . $this->randomMachineName(32) . ' ' . $this->randomMachineName(32);
|
||||
$edit['book[bid]'] = $book_nid;
|
||||
|
||||
if ($parent !== NULL) {
|
||||
$this->drupalPostForm('node/add/book', $edit, t('Change book (update list of parents)'));
|
||||
|
||||
$edit['book[pid]'] = $parent;
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
// Make sure the parent was flagged as having children.
|
||||
$parent_node = \Drupal::entityManager()->getStorage('node')->loadUnchanged($parent);
|
||||
$this->assertFalse(empty($parent_node->book['has_children']), 'Parent node is marked as having children');
|
||||
}
|
||||
else {
|
||||
$this->drupalPostForm('node/add/book', $edit, t('Save'));
|
||||
}
|
||||
|
||||
// Check to make sure the book node was created.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$this->assertNotNull(($node === FALSE ? NULL : $node), 'Book node found in database.');
|
||||
$number++;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the breadcrumb is updated when book content changes.
|
||||
*/
|
||||
public function testBreadcrumbTitleUpdates() {
|
||||
// Create a new book.
|
||||
$nodes = $this->createBreadcrumbBook();
|
||||
$book = $this->book;
|
||||
|
||||
$this->drupalLogin($this->bookAuthor);
|
||||
|
||||
$this->drupalGet($nodes[4]->toUrl());
|
||||
// Fetch each node title in the current breadcrumb.
|
||||
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
|
||||
$got_breadcrumb = array();
|
||||
foreach ($links as $link) {
|
||||
$got_breadcrumb[] = (string) $link;
|
||||
}
|
||||
// Home link and four parent book nodes should be in the breadcrumb.
|
||||
$this->assertEqual(5, count($got_breadcrumb));
|
||||
$this->assertEqual($nodes[3]->getTitle(), end($got_breadcrumb));
|
||||
$edit = [
|
||||
'title[0][value]' => 'Updated node5 title',
|
||||
];
|
||||
$this->drupalPostForm($nodes[3]->toUrl('edit-form'), $edit, 'Save');
|
||||
$this->drupalGet($nodes[4]->toUrl());
|
||||
// Fetch each node title in the current breadcrumb.
|
||||
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
|
||||
$got_breadcrumb = array();
|
||||
foreach ($links as $link) {
|
||||
$got_breadcrumb[] = (string) $link;
|
||||
}
|
||||
$this->assertEqual(5, count($got_breadcrumb));
|
||||
$this->assertEqual($edit['title[0][value]'], end($got_breadcrumb));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the breadcrumb is updated when book access changes.
|
||||
*/
|
||||
public function testBreadcrumbAccessUpdates() {
|
||||
// Create a new book.
|
||||
$nodes = $this->createBreadcrumbBook();
|
||||
$this->drupalLogin($this->bookAuthor);
|
||||
$edit = [
|
||||
'title[0][value]' => "you can't see me",
|
||||
];
|
||||
$this->drupalPostForm($nodes[3]->toUrl('edit-form'), $edit, 'Save');
|
||||
$this->drupalGet($nodes[4]->toUrl());
|
||||
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
|
||||
$got_breadcrumb = array();
|
||||
foreach ($links as $link) {
|
||||
$got_breadcrumb[] = (string) $link;
|
||||
}
|
||||
$this->assertEqual(5, count($got_breadcrumb));
|
||||
$this->assertEqual($edit['title[0][value]'], end($got_breadcrumb));
|
||||
$config = $this->container->get('config.factory')->getEditable('book_breadcrumb_test.settings');
|
||||
$config->set('hide', TRUE)->save();
|
||||
$this->drupalGet($nodes[4]->toUrl());
|
||||
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
|
||||
$got_breadcrumb = array();
|
||||
foreach ($links as $link) {
|
||||
$got_breadcrumb[] = (string) $link;
|
||||
}
|
||||
$this->assertEqual(4, count($got_breadcrumb));
|
||||
$this->assertEqual($nodes[2]->getTitle(), end($got_breadcrumb));
|
||||
$this->drupalGet($nodes[3]->toUrl());
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
||||
}
|
|
@ -443,6 +443,60 @@ class BookTest extends WebTestBase {
|
|||
$this->assertNoText($nodes[0]->label(), 'No links to individual book pages are displayed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BookManager::getTableOfContents().
|
||||
*/
|
||||
public function testGetTableOfContents() {
|
||||
// Create new book.
|
||||
$nodes = $this->createBook();
|
||||
$book = $this->book;
|
||||
|
||||
$this->drupalLogin($this->bookAuthor);
|
||||
|
||||
/*
|
||||
* Add Node 5 under Node 2.
|
||||
* Add Node 6, 7, 8, 9, 10, 11 under Node 3.
|
||||
* Book
|
||||
* |- Node 0
|
||||
* |- Node 1
|
||||
* |- Node 2
|
||||
* |- Node 5
|
||||
* |- Node 3
|
||||
* |- Node 6
|
||||
* |- Node 7
|
||||
* |- Node 8
|
||||
* |- Node 9
|
||||
* |- Node 10
|
||||
* |- Node 11
|
||||
* |- Node 4
|
||||
*/
|
||||
foreach ([5 => 2, 6 => 3, 7 => 6, 8 => 7, 9 => 8, 10 => 9, 11 => 10] as $child => $parent) {
|
||||
$nodes[$child] = $this->createBookNode($book->id(), $nodes[$parent]->id());
|
||||
}
|
||||
$this->drupalGet($nodes[0]->toUrl('edit-form'));
|
||||
// Snice Node 0 has children 2 levels deep, nodes 10 and 11 should not
|
||||
// appear in the selector.
|
||||
$this->assertNoOption('edit-book-pid', $nodes[10]->id());
|
||||
$this->assertNoOption('edit-book-pid', $nodes[11]->id());
|
||||
// Node 9 should be available as an option.
|
||||
$this->assertOption('edit-book-pid', $nodes[9]->id());
|
||||
|
||||
// Get a shallow set of options.
|
||||
/** @var \Drupal\book\BookManagerInterface $manager */
|
||||
$manager = $this->container->get('book.manager');
|
||||
$options = $manager->getTableOfContents($book->id(), 3);
|
||||
$expected_nids = [$book->id(), $nodes[0]->id(), $nodes[1]->id(), $nodes[2]->id(), $nodes[3]->id(), $nodes[6]->id(), $nodes[4]->id()];
|
||||
$this->assertEqual(count($options), count($expected_nids));
|
||||
$diff = array_diff($expected_nids, array_keys($options));
|
||||
$this->assertTrue(empty($diff), 'Found all expected option keys');
|
||||
// Exclude Node 3.
|
||||
$options = $manager->getTableOfContents($book->id(), 3, array($nodes[3]->id()));
|
||||
$expected_nids = array($book->id(), $nodes[0]->id(), $nodes[1]->id(), $nodes[2]->id(), $nodes[4]->id());
|
||||
$this->assertEqual(count($options), count($expected_nids));
|
||||
$diff = array_diff($expected_nids, array_keys($options));
|
||||
$this->assertTrue(empty($diff), 'Found all expected option keys after excluding Node 3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the book navigation block when an access module is installed.
|
||||
*/
|
||||
|
@ -564,6 +618,7 @@ class BookTest extends WebTestBase {
|
|||
$this->drupalGet('node/' . $empty_book->id() . '/outline');
|
||||
$this->assertRaw(t('Book outline'));
|
||||
$this->assertOptionSelected('edit-book-bid', 0, 'Node does not belong to a book');
|
||||
$this->assertNoLink(t('Remove from book outline'));
|
||||
|
||||
$edit = array();
|
||||
$edit['book[bid]'] = '1';
|
||||
|
@ -583,6 +638,8 @@ class BookTest extends WebTestBase {
|
|||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('node/' . $book->id() . '/outline');
|
||||
$this->assertRaw(t('Book outline'));
|
||||
$this->clickLink(t('Remove from book outline'));
|
||||
$this->assertRaw(t('Are you sure you want to remove %title from the book hierarchy?', array('%title' => $book->label())));
|
||||
|
||||
// Create a new node and set the book after the node was created.
|
||||
$node = $this->drupalCreateNode(array('type' => 'book'));
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Book module breadcrumb tests'
|
||||
type: module
|
||||
description: 'Support module for book module breadcrumb testing.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test module for testing the book module breadcrumb.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResultForbidden;
|
||||
use Drupal\Core\Access\AccessResultNeutral;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_node_access().
|
||||
*/
|
||||
function book_breadcrumb_test_node_access(NodeInterface $node, $operation, AccountInterface $account) {
|
||||
$config = \Drupal::config('book_breadcrumb_test.settings');
|
||||
if ($config->get('hide') && $node->getTitle() == "you can't see me" && $operation == 'view') {
|
||||
$access = new AccessResultForbidden();
|
||||
}
|
||||
else {
|
||||
$access = new AccessResultNeutral();
|
||||
}
|
||||
$access->addCacheableDependency($config);
|
||||
$access->addCacheableDependency($node);
|
||||
return $access;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
'hide': false
|
|
@ -0,0 +1,9 @@
|
|||
# Schema for the configuration files of the book_breadcrumb_test module.
|
||||
|
||||
book_breadcrumb_test.settings:
|
||||
type: config_object
|
||||
label: 'Book Breadcrumb Test module settings'
|
||||
mapping:
|
||||
hide:
|
||||
type: boolean
|
||||
label: 'Setting for hiding content'
|
Reference in a new issue