Update to Drupal 8.1.8. For more information, see https://www.drupal.org/project/drupal/releases/8.1.8
This commit is contained in:
parent
e9f047ccf8
commit
f9f23cdf38
312 changed files with 6751 additions and 1546 deletions
|
@ -8,6 +8,7 @@ use Drupal\Core\Datetime\DateFormatterInterface;
|
|||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\node\NodeStorageInterface;
|
||||
use Drupal\node\NodeTypeInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -125,6 +126,7 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
|
|||
*/
|
||||
public function revisionShow($node_revision) {
|
||||
$node = $this->entityManager()->getStorage('node')->loadRevision($node_revision);
|
||||
$node = $this->entityManager()->getTranslationFromContext($node);
|
||||
$node_view_controller = new NodeViewController($this->entityManager, $this->renderer);
|
||||
$page = $node_view_controller->view($node);
|
||||
unset($page['nodes'][$node->id()]['#cache']);
|
||||
|
@ -170,12 +172,9 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
|
|||
$delete_permission = (($account->hasPermission("delete $type revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete'));
|
||||
|
||||
$rows = array();
|
||||
|
||||
$vids = $node_storage->revisionIds($node);
|
||||
|
||||
$latest_revision = TRUE;
|
||||
|
||||
foreach (array_reverse($vids) as $vid) {
|
||||
foreach ($this->_getRevisionIds($node, $node_storage) as $vid) {
|
||||
/** @var \Drupal\node\NodeInterface $revision */
|
||||
$revision = $node_storage->loadRevision($vid);
|
||||
// Only show revisions that are affected by the language that is being
|
||||
|
@ -263,6 +262,8 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
|
|||
),
|
||||
);
|
||||
|
||||
$build['pager'] = array('#type' => 'pager');
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
|
@ -279,4 +280,25 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa
|
|||
return $this->t('Create @name', array('@name' => $node_type->label()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of node revision IDs for a specific node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface
|
||||
* The node entity.
|
||||
* @param \Drupal\node\NodeStorageInterface $node_storage
|
||||
* The node storage handler.
|
||||
*
|
||||
* @return int[]
|
||||
* Node revision IDs (in descending order).
|
||||
*/
|
||||
protected function _getRevisionIds(NodeInterface $node, NodeStorageInterface $node_storage) {
|
||||
$result = $node_storage->getQuery()
|
||||
->allRevisions()
|
||||
->condition($node->getEntityType()->getKey('id'), $node->id())
|
||||
->sort($node->getEntityType()->getKey('revision'), 'DESC')
|
||||
->pager(50)
|
||||
->execute();
|
||||
return array_keys($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -146,10 +146,21 @@ class NodeViewBuilder extends EntityViewBuilder {
|
|||
/** @var \Drupal\node\NodeInterface $entity */
|
||||
parent::alterBuild($build, $entity, $display, $view_mode);
|
||||
if ($entity->id()) {
|
||||
$build['#contextual_links']['node'] = array(
|
||||
'route_parameters' => array('node' => $entity->id()),
|
||||
'metadata' => array('changed' => $entity->getChangedTime()),
|
||||
);
|
||||
if ($entity->isDefaultRevision()) {
|
||||
$build['#contextual_links']['node'] = [
|
||||
'route_parameters' => ['node' => $entity->id()],
|
||||
'metadata' => ['changed' => $entity->getChangedTime()],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$build['#contextual_links']['node_revision'] = [
|
||||
'route_parameters' => [
|
||||
'node' => $entity->id(),
|
||||
'node_revision' => $entity->getRevisionId(),
|
||||
],
|
||||
'metadata' => ['changed' => $entity->getChangedTime()],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,13 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
/**
|
||||
* Whether or not to include translations.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $includeTranslations;
|
||||
|
||||
/**
|
||||
* D6NodeDeriver constructor.
|
||||
*
|
||||
|
@ -44,19 +51,24 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
* The base plugin ID for the plugin ID.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
|
||||
* The CCK plugin manager.
|
||||
* @param bool $translations
|
||||
* Whether or not to include translations.
|
||||
*/
|
||||
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager) {
|
||||
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager, $translations) {
|
||||
$this->basePluginId = $base_plugin_id;
|
||||
$this->cckPluginManager = $cck_manager;
|
||||
$this->includeTranslations = $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
// Translations don't make sense unless we have content_translation.
|
||||
return new static(
|
||||
$base_plugin_id,
|
||||
$container->get('plugin.manager.migrate.cckfield')
|
||||
$container->get('plugin.manager.migrate.cckfield'),
|
||||
$container->get('module_handler')->moduleExists('content_translation')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -72,6 +84,11 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
* @see \Drupal\Component\Plugin\Derivative\DeriverBase::getDerivativeDefinition()
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
if ($base_plugin_definition['id'] == 'd6_node_translation' && !$this->includeTranslations) {
|
||||
// Refuse to generate anything.
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
// Read all CCK field instance definitions in the source database.
|
||||
$fields = array();
|
||||
try {
|
||||
|
@ -100,9 +117,10 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
|||
$values['source']['node_type'] = $node_type;
|
||||
$values['destination']['default_bundle'] = $node_type;
|
||||
|
||||
// If this migration is based on the d6_node_revision migration, it
|
||||
// should explicitly depend on the corresponding d6_node variant.
|
||||
if ($base_plugin_definition['id'] == 'd6_node_revision') {
|
||||
// If this migration is based on the d6_node_revision migration or
|
||||
// is for translations of nodes, it should explicitly depend on the
|
||||
// corresponding d6_node variant.
|
||||
if (in_array($base_plugin_definition['id'], ['d6_node_revision', 'd6_node_translation'])) {
|
||||
$values['migration_dependencies']['required'][] = 'd6_node:' . $node_type;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\node\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
|
@ -37,9 +38,11 @@ class Node extends DrupalSqlBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Select node in its last revision.
|
||||
$query = $this->select('node_revisions', 'nr')
|
||||
->fields('n', array(
|
||||
$query = $this->select('node_revisions', 'nr');
|
||||
$query->innerJoin('node', 'n', static::JOIN);
|
||||
$this->handleTranslations($query);
|
||||
|
||||
$query->fields('n', array(
|
||||
'nid',
|
||||
'type',
|
||||
'language',
|
||||
|
@ -54,17 +57,16 @@ class Node extends DrupalSqlBase {
|
|||
'translate',
|
||||
))
|
||||
->fields('nr', array(
|
||||
'vid',
|
||||
'title',
|
||||
'body',
|
||||
'teaser',
|
||||
'log',
|
||||
'timestamp',
|
||||
'format',
|
||||
'vid',
|
||||
));
|
||||
$query->addField('n', 'uid', 'node_uid');
|
||||
$query->addField('nr', 'uid', 'revision_uid');
|
||||
$query->innerJoin('node', 'n', static::JOIN);
|
||||
|
||||
if (isset($this->configuration['node_type'])) {
|
||||
$query->condition('n.type', $this->configuration['node_type']);
|
||||
|
@ -123,6 +125,11 @@ class Node extends DrupalSqlBase {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we always have a translation set.
|
||||
if ($row->getSourceProperty('tnid') == 0) {
|
||||
$row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
|
@ -251,4 +258,22 @@ class Node extends DrupalSqlBase {
|
|||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt our query for translations.
|
||||
*
|
||||
* @param \Drupal\Core\Database\Query\SelectInterface
|
||||
* The generated query.
|
||||
*/
|
||||
protected function handleTranslations(SelectInterface $query) {
|
||||
// Check whether or not we want translations.
|
||||
if (empty($this->configuration['translations'])) {
|
||||
// No translations: Yield untranslated nodes, or default translations.
|
||||
$query->where('n.tnid = 0 OR n.tnid = n.nid');
|
||||
}
|
||||
else {
|
||||
// Translations: Yield only non-default translations.
|
||||
$query->where('n.tnid <> 0 AND n.tnid <> n.nid');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\node\Plugin\migrate\source\d6;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
|
||||
/**
|
||||
* Drupal 6 node revision source from database.
|
||||
|
@ -37,4 +38,11 @@ class NodeRevision extends Node {
|
|||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function handleTranslations(SelectInterface $query) {
|
||||
// @todo in https://www.drupal.org/node/2746541
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,7 +63,9 @@ class Path extends FieldPluginBase {
|
|||
*/
|
||||
public function render(ResultRow $values) {
|
||||
$nid = $this->getValue($values, 'nid');
|
||||
return \Drupal::url('entity.node.canonical', ['node' => $nid], ['absolute' => $this->options['absolute']]);
|
||||
return array(
|
||||
'#markup' => \Drupal::url('entity.node.canonical', ['node' => $nid], ['absolute' => $this->options['absolute']]),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,11 @@ use Drupal\Tests\node\Kernel\Migrate\d6\MigrateNodeTestBase;
|
|||
*/
|
||||
class MigrateNodeRevisionTest extends MigrateNodeTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\node\Tests;
|
||||
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
|
||||
/**
|
||||
* Ensures that data added to nodes by other modules appears in RSS feeds.
|
||||
*
|
||||
|
@ -60,4 +62,47 @@ class NodeRSSContentTest extends NodeTestBase {
|
|||
$this->assertNoText($rss_only_content, 'Node content designed for RSS does not appear when viewing node.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests relative, root-relative, protocol-relative and absolute URLs.
|
||||
*/
|
||||
public function testUrlHandling() {
|
||||
// Only the plain_text text format is available by default, which escapes
|
||||
// all HTML.
|
||||
FilterFormat::create([
|
||||
'format' => 'full_html',
|
||||
'name' => 'Full HTML',
|
||||
'filters' => [],
|
||||
])->save();
|
||||
|
||||
$defaults = [
|
||||
'type' => 'article',
|
||||
'promote' => 1,
|
||||
];
|
||||
$this->drupalCreateNode($defaults + [
|
||||
'body' => [
|
||||
'value' => '<p><a href="' . file_url_transform_relative(file_create_url('public://root-relative')) . '">Root-relative URL</a></p>',
|
||||
'format' => 'full_html',
|
||||
],
|
||||
]);
|
||||
$protocol_relative_url = substr(file_create_url('public://protocol-relative'), strlen(\Drupal::request()->getScheme() . ':'));
|
||||
$this->drupalCreateNode($defaults + [
|
||||
'body' => [
|
||||
'value' => '<p><a href="' . $protocol_relative_url . '">Protocol-relative URL</a></p>',
|
||||
'format' => 'full_html',
|
||||
],
|
||||
]);
|
||||
$absolute_url = file_create_url('public://absolute');
|
||||
$this->drupalCreateNode($defaults + [
|
||||
'body' => [
|
||||
'value' => '<p><a href="' . $absolute_url . '">Absolute URL</a></p>',
|
||||
'format' => 'full_html',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->drupalGet('rss.xml');
|
||||
$this->assertRaw(file_create_url('public://root-relative'), 'Root-relative URL is transformed to absolute.');
|
||||
$this->assertRaw($protocol_relative_url, 'Protocol-relative URL is left untouched.');
|
||||
$this->assertRaw($absolute_url, 'Absolute URL is left untouched.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\node\Tests;
|
||||
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Create a node with revisions and test viewing, saving, reverting, and
|
||||
* deleting revisions for user with access to all.
|
||||
|
@ -15,7 +17,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
|
|||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
|
||||
// Create and log in user.
|
||||
$web_user = $this->drupalCreateUser(
|
||||
array(
|
||||
|
@ -45,17 +47,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
|
|||
for ($i = 0; $i < $revision_count; $i++) {
|
||||
$logs[] = $node->revision_log = $this->randomMachineName(32);
|
||||
|
||||
// Create revision with a random title and body and update variables.
|
||||
$node->title = $this->randomMachineName();
|
||||
$node->body = array(
|
||||
'value' => $this->randomMachineName(32),
|
||||
'format' => filter_default_format(),
|
||||
);
|
||||
$node->setNewRevision();
|
||||
$node->save();
|
||||
|
||||
$node_storage->resetCache(array($node->id()));
|
||||
$node = $node_storage->load($node->id()); // Make sure we get revision information.
|
||||
$node = $this->createNodeRevision($node);
|
||||
$nodes[] = clone $node;
|
||||
}
|
||||
|
||||
|
@ -63,6 +55,28 @@ class NodeRevisionsAllTest extends NodeTestBase {
|
|||
$this->revisionLogs = $logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new revision for a given node.
|
||||
*
|
||||
* @param \Drupal\node\NodeInterface $node
|
||||
* A node object.
|
||||
*
|
||||
* @return \Drupal\node\NodeInterface
|
||||
* A node object with up to date revision information.
|
||||
*/
|
||||
protected function createNodeRevision(NodeInterface $node) {
|
||||
// Create revision with a random title and body and update variables.
|
||||
$node->title = $this->randomMachineName();
|
||||
$node->body = array(
|
||||
'value' => $this->randomMachineName(32),
|
||||
'format' => filter_default_format(),
|
||||
);
|
||||
$node->setNewRevision();
|
||||
$node->save();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks node revision operations.
|
||||
*/
|
||||
|
@ -145,6 +159,29 @@ class NodeRevisionsAllTest extends NodeTestBase {
|
|||
'%title' => $nodes[2]->getTitle(),
|
||||
'%revision-date' => format_date($old_revision_date),
|
||||
)));
|
||||
|
||||
// Create 50 more revisions in order to trigger paging on the revisions
|
||||
// overview screen.
|
||||
$node = $nodes[0];
|
||||
for ($i = 0; $i < 50; $i++) {
|
||||
$logs[] = $node->revision_log = $this->randomMachineName(32);
|
||||
|
||||
$node = $this->createNodeRevision($node);
|
||||
$nodes[] = clone $node;
|
||||
}
|
||||
|
||||
$this->drupalGet('node/' . $node->id() . '/revisions');
|
||||
|
||||
// Check that the pager exists.
|
||||
$this->assertRaw('page=1');
|
||||
|
||||
// Check that the last revision is displayed on the first page.
|
||||
$this->assertText(end($logs));
|
||||
|
||||
// Go to the second page and check that one of the initial three revisions
|
||||
// is displayed.
|
||||
$this->clickLink(t('Page 2'));
|
||||
$this->assertText($logs[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use Drupal\field\Entity\FieldStorageConfig;
|
|||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
|
||||
/**
|
||||
* Create a node with revisions and test viewing, saving, reverting, and
|
||||
|
@ -34,7 +35,7 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('node', 'datetime', 'language', 'content_translation');
|
||||
public static $modules = ['node', 'contextual', 'datetime', 'language', 'content_translation'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -71,6 +72,7 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
'delete page revisions',
|
||||
'edit any page content',
|
||||
'delete any page content',
|
||||
'access contextual links',
|
||||
'translate any entity',
|
||||
'administer content types',
|
||||
)
|
||||
|
@ -152,6 +154,18 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
// Confirm that this is the default revision.
|
||||
$this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.');
|
||||
|
||||
// Confirm that the "Edit" and "Delete" contextual links appear for the
|
||||
// default revision.
|
||||
$ids = ['node:node=' . $node->id() . ':changed=' . $node->getChangedTime()];
|
||||
$json = $this->renderContextualLinks($ids, 'node/' . $node->id());
|
||||
$this->verbose($json[$ids[0]]);
|
||||
|
||||
$expected = '<li class="entitynodeedit-form"><a href="' . base_path() . 'node/' . $node->id() . '/edit">Edit</a></li>';
|
||||
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Edit" contextual link is shown for the default revision.');
|
||||
$expected = '<li class="entitynodedelete-form"><a href="' . base_path() . 'node/' . $node->id() . '/delete">Delete</a></li>';
|
||||
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.');
|
||||
|
||||
|
||||
// Confirm that revisions revert properly.
|
||||
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", array(), t('Revert'));
|
||||
$this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.',
|
||||
|
@ -165,6 +179,16 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
$node = node_revision_load($node->getRevisionId());
|
||||
$this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.');
|
||||
|
||||
// Confirm that "Edit" and "Delete" contextual links don't appear for
|
||||
// non-default revision.
|
||||
$ids = ['node_revision::node=' . $node->id() . '&node_revision=' . $node->getRevisionId() . ':'];
|
||||
$json = $this->renderContextualLinks($ids, 'node/' . $node->id() . '/revisions/' . $node->getRevisionId() . '/view');
|
||||
$this->verbose($json[$ids[0]]);
|
||||
|
||||
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodeedit-form">'), 'The "Edit" contextual link is not shown for a non-default revision.');
|
||||
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodedelete-form">'), 'The "Delete" contextual link is not shown for a non-default revision.');
|
||||
|
||||
|
||||
// Confirm revisions delete properly.
|
||||
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete'));
|
||||
$this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.',
|
||||
|
@ -317,6 +341,27 @@ class NodeRevisionsTest extends NodeTestBase {
|
|||
$this->assertTrue(empty($node_revision->revision_log->value), 'After a new node revision is saved with an empty log message, the log message for the node is empty.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets server-rendered contextual links for the given contextual links IDs.
|
||||
*
|
||||
* @param string[] $ids
|
||||
* An array of contextual link IDs.
|
||||
* @param string $current_path
|
||||
* The Drupal path for the page for which the contextual links are rendered.
|
||||
*
|
||||
* @return string
|
||||
* The decoded JSON response body.
|
||||
*/
|
||||
protected function renderContextualLinks(array $ids, $current_path) {
|
||||
$post = array();
|
||||
for ($i = 0; $i < count($ids); $i++) {
|
||||
$post['ids[' . $i . ']'] = $ids[$i];
|
||||
}
|
||||
$response = $this->drupalPost('contextual/render', 'application/json', $post, ['query' => ['destination' => $current_path]]);
|
||||
|
||||
return Json::decode($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the revision translations are correctly reverted.
|
||||
*/
|
||||
|
|
|
@ -445,4 +445,53 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that revision translations are rendered properly.
|
||||
*/
|
||||
public function testRevisionTranslationRendering() {
|
||||
$storage = \Drupal::entityTypeManager()->getStorage('node');
|
||||
|
||||
// Create a node.
|
||||
$nid = $this->createEntity(['title' => 'First rev en title'], 'en');
|
||||
$node = $storage->load($nid);
|
||||
$original_revision_id = $node->getRevisionId();
|
||||
|
||||
// Add a French translation.
|
||||
$translation = $node->addTranslation('fr');
|
||||
$translation->title = 'First rev fr title';
|
||||
$translation->setNewRevision(FALSE);
|
||||
$translation->save();
|
||||
|
||||
// Create a new revision.
|
||||
$node->title = 'Second rev en title';
|
||||
$node->setNewRevision(TRUE);
|
||||
$node->save();
|
||||
|
||||
// Get an English view of this revision.
|
||||
$original_revision = $storage->loadRevision($original_revision_id);
|
||||
$original_revision_url = $original_revision->toUrl('revision')->toString();
|
||||
|
||||
// Should be different from regular node URL.
|
||||
$this->assertNotIdentical($original_revision_url, $original_revision->toUrl()->toString());
|
||||
$this->drupalGet($original_revision_url);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Contents should be in English, of correct revision.
|
||||
$this->assertText('First rev en title');
|
||||
$this->assertNoText('First rev fr title');
|
||||
|
||||
// Get a French view.
|
||||
$url_fr = $original_revision->getTranslation('fr')->toUrl('revision')->toString();
|
||||
|
||||
// Should have different URL from English.
|
||||
$this->assertNotIdentical($url_fr, $original_revision->toUrl()->toString());
|
||||
$this->assertNotIdentical($url_fr, $original_revision_url);
|
||||
$this->drupalGet($url_fr);
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Contents should be in French, of correct revision.
|
||||
$this->assertText('First rev fr title');
|
||||
$this->assertNoText('First rev en title');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ class NodeTypeTranslationTest extends WebTestBase {
|
|||
* @var array
|
||||
*/
|
||||
public static $modules = array(
|
||||
'block',
|
||||
'config_translation',
|
||||
'field_ui',
|
||||
'node',
|
||||
);
|
||||
|
||||
|
@ -53,6 +55,8 @@ class NodeTypeTranslationTest extends WebTestBase {
|
|||
|
||||
$admin_permissions = array(
|
||||
'administer content types',
|
||||
'administer node fields',
|
||||
'administer languages',
|
||||
'administer site configuration',
|
||||
'administer themes',
|
||||
'translate configuration',
|
||||
|
@ -144,6 +148,29 @@ class NodeTypeTranslationTest extends WebTestBase {
|
|||
$this->assertText('Edited title');
|
||||
$this->drupalGet("$langcode/node/add/$type");
|
||||
$this->assertText('Translated title');
|
||||
|
||||
// Add an e-mail field.
|
||||
$this->drupalPostForm("admin/structure/types/manage/$type/fields/add-field", array('new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email'), 'Save and continue');
|
||||
$this->drupalPostForm(NULL, array(), 'Save field settings');
|
||||
$this->drupalPostForm(NULL, array(), 'Save settings');
|
||||
|
||||
$type = Unicode::strtolower($this->randomMachineName(16));
|
||||
$name = $this->randomString();
|
||||
$this->drupalCreateContentType(array('type' => $type, 'name' => $name));
|
||||
|
||||
// Set tabs.
|
||||
$this->drupalPlaceBlock('local_tasks_block', array('primary' => TRUE));
|
||||
|
||||
// Change default language.
|
||||
$this->drupalPostForm('admin/config/regional/language', array('site_default_language' => 'es'), 'Save configuration');
|
||||
|
||||
// Try re-using the email field.
|
||||
$this->drupalGet("es/admin/structure/types/manage/$type/fields/add-field");
|
||||
$this->drupalPostForm(NULL, array('existing_storage_name' => 'field_email', 'existing_storage_label' => 'Email'), 'Save and continue');
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet("es/admin/structure/types/manage/$type/fields/node.$type.field_email/translate");
|
||||
$this->assertResponse(200);
|
||||
$this->assertText("The configuration objects have different language codes so they cannot be translated");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
77
core/modules/node/src/Tests/Views/PathPluginTest.php
Normal file
77
core/modules/node/src/Tests/Views/PathPluginTest.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\node\Tests\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests the node row plugin.
|
||||
*
|
||||
* @group node
|
||||
*/
|
||||
class PathPluginTest extends NodeTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node');
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('test_node_path_plugin');
|
||||
|
||||
/**
|
||||
* Contains all nodes used by this test.
|
||||
*
|
||||
* @var Node[]
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'article'));
|
||||
|
||||
// Create two nodes.
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$this->nodes[] = $this->drupalCreateNode(
|
||||
array(
|
||||
'type' => 'article',
|
||||
'body' => array(
|
||||
array(
|
||||
'value' => $this->randomMachineName(42),
|
||||
'format' => filter_default_format(),
|
||||
'summary' => $this->randomMachineName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the node path plugin.
|
||||
*/
|
||||
public function testPathPlugin() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$view = Views::getView('test_node_path_plugin');
|
||||
$view->initDisplay();
|
||||
$view->setDisplay('page_1');
|
||||
$view->initStyle();
|
||||
$view->rowPlugin->options['view_mode'] = 'full';
|
||||
|
||||
// Test with view_mode full.
|
||||
$output = $view->preview();
|
||||
$output = $renderer->renderRoot($output);
|
||||
foreach ($this->nodes as $node) {
|
||||
$this->assertTrue(strpos($output, 'This is <strong>not escaped</strong> and this is ' . $node->link('the link')) !== FALSE, 'Make sure path field rewriting is not escaped.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
89
core/modules/node/src/Tests/Views/RevisionLinkTest.php
Normal file
89
core/modules/node/src/Tests/Views/RevisionLinkTest.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\node\Tests\Views;
|
||||
|
||||
/**
|
||||
* Tests the different revision link handlers.
|
||||
*
|
||||
* @group node
|
||||
*
|
||||
* @see \Drupal\node\Plugin\views\field\RevisionLink
|
||||
* @see \Drupal\node\Plugin\views\field\RevisionLinkDelete
|
||||
* @see \Drupal\node\Plugin\views\field\RevisionLinkRevert
|
||||
*/
|
||||
class RevisionLinkTest extends NodeTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_node_revision_links'];
|
||||
|
||||
/**
|
||||
* Tests revision links.
|
||||
*/
|
||||
public function testRevisionLinks() {
|
||||
// Create one user which can view/revert and delete and one which can only
|
||||
// do one of them.
|
||||
$this->drupalCreateContentType(['name' => 'page', 'type' => 'page']);
|
||||
$account = $this->drupalCreateUser(['revert all revisions', 'view all revisions', 'delete all revisions', 'edit any page content', 'delete any page content']);
|
||||
$this->drupalLogin($account);
|
||||
// Create two nodes, one without an additional revision and one with a
|
||||
// revision.
|
||||
$nodes = [
|
||||
$this->drupalCreateNode(),
|
||||
$this->drupalCreateNode(),
|
||||
];
|
||||
|
||||
$first_revision = $nodes[1]->getRevisionId();
|
||||
// Create revision of the node.
|
||||
$nodes[1]->setNewRevision();
|
||||
$nodes[1]->save();
|
||||
$second_revision = $nodes[1]->getRevisionId();
|
||||
|
||||
$this->drupalGet('test-node-revision-links');
|
||||
$this->assertResponse(200, 'Test view can be accessed in the path expected');
|
||||
// The first node revision should link to the node directly as you get an
|
||||
// access denied if you link to the revision.
|
||||
$url = $nodes[0]->urlInfo()->toString();
|
||||
$this->assertLinkByHref($url);
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/view');
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/delete');
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $nodes[0]->getRevisionId() . '/revert');
|
||||
|
||||
// For the second node the current revision got set to the last revision, so
|
||||
// the first one should also link to the node page itself.
|
||||
$url = $nodes[1]->urlInfo()->toString();
|
||||
$this->assertLinkByHref($url);
|
||||
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/view');
|
||||
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/delete');
|
||||
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/revert');
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/view');
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/delete');
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $second_revision . '/revert');
|
||||
|
||||
$accounts = [
|
||||
'view' => $this->drupalCreateUser(['view all revisions']),
|
||||
'revert' => $this->drupalCreateUser(['revert all revisions', 'edit any page content']),
|
||||
'delete' => $this->drupalCreateUser(['delete all revisions', 'delete any page content']),
|
||||
];
|
||||
|
||||
$url = $nodes[1]->urlInfo()->toString();
|
||||
// Render the view with users which can only delete/revert revisions.
|
||||
foreach ($accounts as $allowed_operation => $account) {
|
||||
$this->drupalLogin($account);
|
||||
$this->drupalGet('test-node-revision-links');
|
||||
// Check expected links.
|
||||
foreach (['revert', 'delete'] as $operation) {
|
||||
if ($operation == $allowed_operation) {
|
||||
$this->assertLinkByHref($url . '/revisions/' . $first_revision . '/' . $operation);
|
||||
}
|
||||
else {
|
||||
$this->assertNoLinkByHref($url . '/revisions/' . $first_revision . '/' . $operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue