Skip to content
......@@ -9,7 +9,7 @@
/**
* This plugin iterates and processes an array.
*
* @see https://www.drupal.org/node/2135345
* @link https://www.drupal.org/node/2135345 Online handbook documentation for iterator process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "iterator",
......
......@@ -17,6 +17,8 @@
* and replaced by an underscore and multiple underscores are collapsed into
* one.
*
* @link https://www.drupal.org/node/2135323 Online handbook documentation for machine_name process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "machine_name"
* )
......
......@@ -4,7 +4,7 @@
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigratePluginManagerInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\ProcessPluginBase;
......@@ -16,6 +16,8 @@
/**
* Calculates the value of a property based on a previous migration.
*
* @link https://www.drupal.org/node/2149801 Online handbook documentation for migration process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "migration"
* )
......@@ -39,7 +41,7 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManager $process_plugin_manager) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManagerInterface $process_plugin_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migrationPluginManager = $migration_plugin_manager;
$this->migration = $migration;
......
......@@ -11,7 +11,10 @@
use Drupal\migrate\Row;
/**
* @MigrateProcessPlugin(
*
* @link https://www.drupal.org/node/2750777 Online handbook documentation for route process plugin @endlink
*
* * @MigrateProcessPlugin(
* id = "route"
* )
*/
......
......@@ -11,6 +11,8 @@
/**
* If the source evaluates to empty, we skip processing or the whole row.
*
* @link https://www.drupal.org/node/2228793 Online handbook documentation for skip_on_empty process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "skip_on_empty"
* )
......
......@@ -10,6 +10,8 @@
/**
* If the source evaluates to empty, we skip the current row.
*
* @link https://www.drupal.org/node/2345935 Online handbook documentation for skip_row_if_not_set process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "skip_row_if_not_set",
* handle_multiples = TRUE
......
......@@ -12,7 +12,7 @@
/**
* This plugin changes the current value based on a static lookup map.
*
* @see https://www.drupal.org/node/2143521
* @link https://www.drupal.org/node/2143521 Online handbook documentation for static_map process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "static_map"
......
......@@ -11,6 +11,8 @@
/**
* This plugin returns a substring of the current value.
*
* @link https://www.drupal.org/node/2771965 Online handbook documentation for substr process plugin @endlink
*
* @MigrateProcessPlugin(
* id = "substr"
* )
......
......@@ -15,7 +15,7 @@
*
* @ingroup migration
*/
class MigrateCckFieldPluginManager extends MigratePluginManager {
class MigrateCckFieldPluginManager extends MigratePluginManager implements MigrateCckFieldPluginManagerInterface {
/**
* The default version of core to use for cck field plugins.
......@@ -29,7 +29,7 @@ class MigrateCckFieldPluginManager extends MigratePluginManager {
/**
* {@inheritdoc}
*/
public function createInstance($field_type, array $configuration = array(), MigrationInterface $migration = NULL) {
public function getPluginIdFromFieldType($field_type, array $configuration = [], MigrationInterface $migration = NULL) {
$core = static::DEFAULT_CORE_VERSION;
if (!empty($configuration['core'])) {
$core = $configuration['core'];
......@@ -45,7 +45,7 @@ public function createInstance($field_type, array $configuration = array(), Migr
foreach ($this->getDefinitions() as $plugin_id => $definition) {
if (in_array($core, $definition['core'])) {
if (array_key_exists($field_type, $definition['type_map']) || $field_type === $plugin_id) {
return parent::createInstance($plugin_id, $configuration, $migration);
return $plugin_id;
}
}
}
......
<?php
namespace Drupal\migrate_drupal\Plugin;
use Drupal\migrate\Plugin\MigratePluginManagerInterface;
use Drupal\migrate\Plugin\MigrationInterface;
interface MigrateCckFieldPluginManagerInterface extends MigratePluginManagerInterface {
/**
* Get the plugin ID from the field type.
*
* @param string $field_type
* The field type being migrated.
* @param array $configuration
* (optional) An array of configuration relevant to the plugin instance.
* @param \Drupal\migrate\Plugin\MigrationInterface|null $migration
* (optional) The current migration instance.
*
* @return string
* The ID of the plugin for the field_type if available.
*
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* If the plugin cannot be determined, such as if the field type is invalid.
*/
public function getPluginIdFromFieldType($field_type, array $configuration = [], MigrationInterface $migration = NULL);
}
......@@ -2,13 +2,15 @@
namespace Drupal\migrate_drupal\Plugin\migrate;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrateDestinationPluginManager;
use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigratePluginManagerInterface;
use Drupal\migrate\Plugin\Migration;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Plugin\RequirementsInterface;
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -40,7 +42,7 @@ class CckMigration extends Migration implements ContainerFactoryPluginInterface
/**
* The cckfield plugin manager.
*
* @var \Drupal\migrate\Plugin\MigratePluginManager
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
*/
protected $cckPluginManager;
......@@ -53,20 +55,20 @@ class CckMigration extends Migration implements ContainerFactoryPluginInterface
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\migrate\Plugin\MigratePluginManager $cck_manager
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
* The cckfield plugin manager.
* @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
* The migration plugin manager.
* @param \Drupal\migrate\Plugin\MigratePluginManager $source_plugin_manager
* @param \Drupal\migrate\Plugin\MigratePluginManagerInterface $source_plugin_manager
* The source migration plugin manager.
* @param \Drupal\migrate\Plugin\MigratePluginManager $process_plugin_manager
* @param \Drupal\migrate\Plugin\MigratePluginManagerInterface $process_plugin_manager
* The process migration plugin manager.
* @param \Drupal\migrate\Plugin\MigrateDestinationPluginManager $destination_plugin_manager
* The destination migration plugin manager.
* @param \Drupal\migrate\Plugin\MigratePluginManager $idmap_plugin_manager
* @param \Drupal\migrate\Plugin\MigratePluginManagerInterface $idmap_plugin_manager
* The ID map migration plugin manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigratePluginManager $cck_manager, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManager $source_plugin_manager, MigratePluginManager $process_plugin_manager, MigrateDestinationPluginManager $destination_plugin_manager, MigratePluginManager $idmap_plugin_manager) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateCckFieldPluginManagerInterface $cck_manager, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManagerInterface $source_plugin_manager, MigratePluginManagerInterface $process_plugin_manager, MigrateDestinationPluginManager $destination_plugin_manager, MigratePluginManagerInterface $idmap_plugin_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration_plugin_manager, $source_plugin_manager, $process_plugin_manager, $destination_plugin_manager, $idmap_plugin_manager);
$this->cckPluginManager = $cck_manager;
}
......@@ -106,12 +108,19 @@ public function getProcess() {
}
foreach ($source_plugin as $row) {
$field_type = $row->getSourceProperty('type');
if (!isset($this->processedFieldTypes[$field_type]) && $this->cckPluginManager->hasDefinition($field_type)) {
try {
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, [], $this);
}
catch (PluginNotFoundException $ex) {
continue;
}
if (!isset($this->processedFieldTypes[$field_type])) {
$this->processedFieldTypes[$field_type] = TRUE;
// Allow the cckfield plugin to alter the migration as necessary so
// that it knows how to handle fields of this type.
if (!isset($this->cckPluginCache[$field_type])) {
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, [], $this);
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, [], $this);
}
call_user_func([$this->cckPluginCache[$field_type], $this->pluginDefinition['cck_plugin_method']], $this);
}
......
......@@ -3835,6 +3835,18 @@
'body_summary' => '',
'body_format' => 'filtered_html',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'body_value' => "is - ...is that it's the absolute best show ever. Trust me, I would know.",
'body_summary' => '',
'body_format' => 'filtered_html',
))
->execute();
 
$connection->schema()->createTable('field_data_comment_body', array(
......@@ -4930,6 +4942,18 @@
'field_link_title' => 'Home',
'field_link_attributes' => 'a:0:{}',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'field_link_url' => '<front>',
'field_link_title' => 'Home',
'field_link_attributes' => 'a:1:{s:5:"title";s:0:"";}',
))
->execute();
 
$connection->schema()->createTable('field_data_field_long_text', array(
......@@ -5167,6 +5191,16 @@
'delta' => '0',
'field_tags_tid' => '9',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'field_tags_tid' => '9',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
......@@ -5177,6 +5211,16 @@
'delta' => '1',
'field_tags_tid' => '14',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '1',
'field_tags_tid' => '14',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
......@@ -5187,6 +5231,16 @@
'delta' => '2',
'field_tags_tid' => '17',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '2',
'field_tags_tid' => '17',
))
->execute();
 
$connection->schema()->createTable('field_data_field_term_reference', array(
......@@ -5603,6 +5657,18 @@
'body_summary' => '',
'body_format' => 'filtered_html',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'body_value' => "is - ...is that it's the absolute best show ever. Trust me, I would know.",
'body_summary' => '',
'body_format' => 'filtered_html',
))
->execute();
 
$connection->schema()->createTable('field_revision_comment_body', array(
......@@ -6710,6 +6776,18 @@
'field_link_title' => 'Home',
'field_link_attributes' => 'a:0:{}',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'field_link_url' => '<front>',
'field_link_title' => 'Home',
'field_link_attributes' => 'a:1:{s:5:"title";s:0:"";}',
))
->execute();
 
$connection->schema()->createTable('field_revision_field_long_text', array(
......@@ -6950,6 +7028,16 @@
'delta' => '0',
'field_tags_tid' => '9',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '0',
'field_tags_tid' => '9',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
......@@ -6960,6 +7048,16 @@
'delta' => '1',
'field_tags_tid' => '14',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '1',
'field_tags_tid' => '14',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
......@@ -6970,6 +7068,16 @@
'delta' => '2',
'field_tags_tid' => '17',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '3',
'revision_id' => '3',
'language' => 'und',
'delta' => '2',
'field_tags_tid' => '17',
))
->execute();
 
$connection->schema()->createTable('field_revision_field_term_reference', array(
......@@ -29674,7 +29782,23 @@
'comment' => '2',
'promote' => '1',
'sticky' => '0',
'tnid' => '0',
'tnid' => '2',
'translate' => '0',
))
->values(array(
'nid' => '3',
'vid' => '3',
'type' => 'article',
'language' => 'is',
'title' => 'is - The thing about Deep Space 9',
'uid' => '1',
'status' => '1',
'created' => '1471428152',
'changed' => '1471428152',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
'tnid' => '2',
'translate' => '0',
))
->execute();
......@@ -29813,6 +29937,14 @@
'last_comment_uid' => '1',
'comment_count' => '1',
))
->values(array(
'nid' => '3',
'cid' => '0',
'last_comment_timestamp' => '1471428152',
'last_comment_name' => NULL,
'last_comment_uid' => '1',
'comment_count' => '0',
))
->execute();
 
$connection->schema()->createTable('node_counter', array(
......@@ -29864,6 +29996,18 @@
'daycount' => '0',
'timestamp' => '1421727536',
))
->values(array(
'nid' => '2',
'totalcount' => '1',
'daycount' => '1',
'timestamp' => '1471428059',
))
->values(array(
'nid' => '3',
'totalcount' => '1',
'daycount' => '1',
'timestamp' => '1471428153',
))
->execute();
 
$connection->schema()->createTable('node_revision', array(
......@@ -29972,6 +30116,18 @@
'promote' => '1',
'sticky' => '0',
))
->values(array(
'nid' => '3',
'vid' => '3',
'uid' => '1',
'title' => 'is - The thing about Deep Space 9',
'log' => '',
'timestamp' => '1471428152',
'status' => '1',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
))
->execute();
 
$connection->schema()->createTable('node_type', array(
......@@ -40112,6 +40268,24 @@
'sticky' => '0',
'created' => '1441306772',
))
->values(array(
'nid' => '3',
'tid' => '9',
'sticky' => '0',
'created' => '1471428152',
))
->values(array(
'nid' => '3',
'tid' => '14',
'sticky' => '0',
'created' => '1471428152',
))
->values(array(
'nid' => '3',
'tid' => '17',
'sticky' => '0',
'created' => '1471428152',
))
->execute();
 
$connection->schema()->createTable('taxonomy_term_data', array(
......@@ -41342,7 +41516,7 @@
))
->values(array(
'name' => 'language_content_type_article',
'value' => 's:1:"0";',
'value' => 's:1:"2";',
))
->values(array(
'name' => 'language_content_type_blog',
......@@ -41442,7 +41616,7 @@
))
->values(array(
'name' => 'menu_override_parent_selector',
'value' => 'b:1;',
'value' => 'b:0;',
))
->values(array(
'name' => 'menu_parent_article',
......@@ -22,32 +22,33 @@ class MigrateCckFieldPluginManagerTest extends MigrateDrupalTestBase {
public function testPluginSelection() {
$plugin_manager = \Drupal::service('plugin.manager.migrate.cckfield');
$this->assertIdentical('Drupal\\file\\Plugin\\migrate\\cckfield\\d6\\FileField', get_class($plugin_manager->createInstance('filefield', ['core' => 6])));
$plugin_id = $plugin_manager->getPluginIdFromFieldType('filefield', ['core' => 6]);
$this->assertIdentical('Drupal\\file\\Plugin\\migrate\\cckfield\\d6\\FileField', get_class($plugin_manager->createInstance($plugin_id, ['core' => 6])));
try {
// If this test passes, createInstance will raise a
// If this test passes, getPluginIdFromFieldType will raise a
// PluginNotFoundException and we'll never reach fail().
$plugin_manager->createInstance('filefield', ['core' => 7]);
$plugin_manager->getPluginIdFromFieldType('filefield', ['core' => 7]);
$this->fail('Expected Drupal\Component\Plugin\Exception\PluginNotFoundException.');
}
catch (PluginNotFoundException $e) {
$this->assertIdentical($e->getMessage(), "Plugin ID 'filefield' was not found.");
}
$this->assertIdentical('Drupal\\file\\Plugin\\migrate\\cckfield\\d7\\ImageField', get_class($plugin_manager->createInstance('image', ['core' => 7])));
$this->assertIdentical('Drupal\\file\\Plugin\\migrate\\cckfield\\d7\\FileField', get_class($plugin_manager->createInstance('file', ['core' => 7])));
$this->assertIdentical('Drupal\\migrate_cckfield_plugin_manager_test\\Plugin\\migrate\\cckfield\\D6FileField', get_class($plugin_manager->createInstance('file', ['core' => 6])));
$this->assertIdentical('image', $plugin_manager->getPluginIdFromFieldType('image', ['core' => 7]));
$this->assertIdentical('file', $plugin_manager->getPluginIdFromFieldType('file', ['core' => 7]));
$this->assertIdentical('d6_file', $plugin_manager->getPluginIdFromFieldType('file', ['core' => 6]));
$this->assertIdentical('Drupal\\text\\Plugin\\migrate\\cckfield\\TextField', get_class($plugin_manager->createInstance('text', ['core' => 6])));
$this->assertIdentical('Drupal\\text\\Plugin\\migrate\\cckfield\\TextField', get_class($plugin_manager->createInstance('text', ['core' => 7])));
$this->assertIdentical('text', $plugin_manager->getPluginIdFromFieldType('text', ['core' => 6]));
$this->assertIdentical('text', $plugin_manager->getPluginIdFromFieldType('text', ['core' => 7]));
// Test fallback when no core version is specified.
$this->assertIdentical('Drupal\\migrate_cckfield_plugin_manager_test\\Plugin\\migrate\\cckfield\\D6NoCoreVersionSpecified', get_class($plugin_manager->createInstance('d6_no_core_version_specified', ['core' => 6])));
$this->assertIdentical('d6_no_core_version_specified', $plugin_manager->getPluginIdFromFieldType('d6_no_core_version_specified', ['core' => 6]));
try {
// If this test passes, createInstance will raise a
// If this test passes, getPluginIdFromFieldType will raise a
// PluginNotFoundException and we'll never reach fail().
$plugin_manager->createInstance('d6_no_core_version_specified', ['core' => 7]);
$plugin_manager->getPluginIdFromFieldType('d6_no_core_version_specified', ['core' => 7]);
$this->fail('Expected Drupal\Component\Plugin\Exception\PluginNotFoundException.');
}
catch (PluginNotFoundException $e) {
......
......@@ -48,9 +48,9 @@ protected function getEntityCounts() {
'file' => 1,
'filter_format' => 7,
'image_style' => 6,
'language_content_settings' => 1,
'language_content_settings' => 2,
'migration' => 59,
'node' => 2,
'node' => 3,
'node_type' => 6,
'rdf_mapping' => 5,
'search_page' => 2,
......
......@@ -1213,7 +1213,7 @@ function _node_access_rebuild_batch_operation(&$context) {
// Initiate multistep processing.
$context['sandbox']['progress'] = 0;
$context['sandbox']['current_node'] = 0;
$context['sandbox']['max'] = \Drupal::entityQuery('node')->count()->execute();
$context['sandbox']['max'] = \Drupal::entityQuery('node')->accessCheck(FALSE)->count()->execute();
}
// Process the next 20 nodes.
......
......@@ -127,7 +127,7 @@ public function add(NodeTypeInterface $node_type) {
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);
$node_view_controller = new NodeViewController($this->entityManager, $this->renderer, $this->currentUser());
$page = $node_view_controller->view($node);
unset($page['nodes'][$node->id()]['#cache']);
return $page;
......
......@@ -4,12 +4,50 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Controller\EntityViewController;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a controller to render a single node.
*/
class NodeViewController extends EntityViewController {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Creates an NodeViewController object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user. For backwards compatibility this is optional, however
* this will be removed before Drupal 9.0.0.
*/
public function __construct(EntityManagerInterface $entity_manager, RendererInterface $renderer, AccountInterface $current_user = NULL) {
parent::__construct($entity_manager, $renderer);
$this->currentUser = $current_user ?: \Drupal::currentUser();
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('renderer'),
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
......@@ -17,27 +55,44 @@ public function view(EntityInterface $node, $view_mode = 'full', $langcode = NUL
$build = parent::view($node, $view_mode, $langcode);
foreach ($node->uriRelationships() as $rel) {
// Set the node path as the canonical URL to prevent duplicate content.
$build['#attached']['html_head_link'][] = array(
array(
'rel' => $rel,
'href' => $node->url($rel),
),
TRUE,
);
$url = $node->toUrl($rel);
// Add link relationships if the user is authenticated or if the anonymous
// user has access. Access checking must be done for anonymous users to
// avoid traffic to inaccessible pages from web crawlers. For
// authenticated users, showing the links in HTML head does not impact
// user experience or security, since the routes are access checked when
// visited and only visible via view source. This prevents doing
// potentially expensive and hard to cache access checks on every request.
// This means that the page will vary by user.permissions. We also rely on
// the access checking fallback to ensure the correct cacheability
// metadata if we have to check access.
if ($this->currentUser->isAuthenticated() || $url->access($this->currentUser)) {
// Set the node path as the canonical URL to prevent duplicate content.
$build['#attached']['html_head_link'][] = array(
array(
'rel' => $rel,
'href' => $url->toString(),
),
TRUE,
);
}
if ($rel == 'canonical') {
// Set the non-aliased canonical path as a default shortlink.
$build['#attached']['html_head_link'][] = array(
array(
'rel' => 'shortlink',
'href' => $node->url($rel, array('alias' => TRUE)),
'href' => $url->setOption('alias', TRUE)->toString(),
),
TRUE,
);
}
}
// Given this varies by $this->currentUser->isAuthenticated(), add a cache
// context based on the anonymous role.
$build['#cache']['contexts'][] = 'user.roles:anonymous';
return $build;
}
......
......@@ -3,11 +3,12 @@
namespace Drupal\node\Plugin\migrate;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrationDeriverTrait;
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -33,7 +34,7 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
/**
* The CCK plugin manager.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
*/
protected $cckPluginManager;
......@@ -49,12 +50,12 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
*
* @param string $base_plugin_id
* The base plugin ID for the plugin ID.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
* The CCK plugin manager.
* @param bool $translations
* Whether or not to include translations.
*/
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager, $translations) {
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager, $translations) {
$this->basePluginId = $base_plugin_id;
$this->cckPluginManager = $cck_manager;
$this->includeTranslations = $translations;
......@@ -128,14 +129,15 @@ public function getDerivativeDefinitions($base_plugin_definition) {
if (isset($fields[$node_type])) {
foreach ($fields[$node_type] as $field_name => $info) {
$field_type = $info['type'];
if ($this->cckPluginManager->hasDefinition($info['type'])) {
try {
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 6], $migration);
if (!isset($this->cckPluginCache[$field_type])) {
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, ['core' => 6], $migration);
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 6], $migration);
}
$this->cckPluginCache[$field_type]
->processCckFieldValues($migration, $field_name, $info);
}
else {
catch (PluginNotFoundException $ex) {
$migration->setProcessOfProperty($field_name, $field_name);
}
}
......
......@@ -3,11 +3,12 @@
namespace Drupal\node\Plugin\migrate;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrationDeriverTrait;
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -33,7 +34,7 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
/**
* The CCK plugin manager.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
*/
protected $cckPluginManager;
......@@ -42,10 +43,10 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
*
* @param string $base_plugin_id
* The base plugin ID for the plugin ID.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
* The CCK plugin manager.
*/
public function __construct($base_plugin_id, PluginManagerInterface $cck_manager) {
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager) {
$this->basePluginId = $base_plugin_id;
$this->cckPluginManager = $cck_manager;
}
......@@ -98,14 +99,15 @@ public function getDerivativeDefinitions($base_plugin_definition) {
if (isset($fields[$node_type])) {
foreach ($fields[$node_type] as $field_name => $info) {
$field_type = $info['type'];
if ($this->cckPluginManager->hasDefinition($field_type)) {
try {
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration);
if (!isset($this->cckPluginCache[$field_type])) {
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, ['core' => 7], $migration);
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 7], $migration);
}
$this->cckPluginCache[$field_type]
->processCckFieldValues($migration, $field_name, $info);
}
else {
catch (PluginNotFoundException $ex) {
$migration->setProcessOfProperty($field_name, $field_name);
}
}
......
......@@ -2,6 +2,8 @@
namespace Drupal\node\Tests;
use Drupal\node\Entity\NodeType;
/**
* Ensures that node access rebuild functions work correctly even
* when other modules implements hook_node_grants().
......@@ -11,20 +13,27 @@
class NodeAccessRebuildNodeGrantsTest extends NodeTestBase {
/**
* A user to test the rebuild nodes feature.
* A user to create nodes that only it has access to.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* A user to test the rebuild nodes feature which can't access the nodes.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'bypass node access'));
$this->drupalLogin($admin_user);
$this->adminUser = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports'));
$this->drupalLogin($this->adminUser);
$this->webUser = $this->drupalCreateUser();
}
......@@ -34,25 +43,54 @@ protected function setUp() {
*/
public function testNodeAccessRebuildNodeGrants() {
\Drupal::service('module_installer')->install(['node_access_test']);
\Drupal::state()->set('node_access_test.private', TRUE);
node_access_test_add_field(NodeType::load('page'));
$this->resetAll();
$node = $this->drupalCreateNode(array(
'uid' => $this->webUser->id(),
));
// Create 30 nodes so that _node_access_rebuild_batch_operation() has to run
// more than once.
for ($i = 0; $i < 30; $i++) {
$nodes[] = $this->drupalCreateNode(array(
'uid' => $this->webUser->id(),
'private' => [['value' => 1]]
));
}
/** @var \Drupal\node\NodeGrantDatabaseStorageInterface $grant_storage */
$grant_storage = \Drupal::service('node.grant_storage');
// Default realm access and node records are present.
$this->assertTrue(\Drupal::service('node.grant_storage')->access($node, 'view', $this->webUser), 'The expected node access records are present');
foreach ($nodes as $node) {
$this->assertTrue($node->private->value);
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'Prior to rebuilding node access the grant storage returns allowed for the node author.');
$this->assertTrue($grant_storage->access($node, 'view', $this->adminUser)->isAllowed(), 'Prior to rebuilding node access the grant storage returns allowed for the admin user.');
}
$this->assertEqual(1, \Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is an all realm access record');
$this->assertTrue(\Drupal::state()->get('node.node_access_needs_rebuild'), 'Node access permissions need to be rebuilt');
// Rebuild permissions.
$this->drupalGet('admin/reports/status/rebuild');
$this->drupalGet('admin/reports/status');
$this->clickLink(t('Rebuild permissions'));
$this->drupalPostForm(NULL, array(), t('Rebuild permissions'));
$this->assertText(t('The content access permissions have been rebuilt.'));
// Test if the rebuild has been successful.
// Test if the rebuild by user that cannot bypass node access and does not
// have access to the nodes has been successful.
$this->assertFalse($this->adminUser->hasPermission('bypass node access'));
$this->assertNull(\Drupal::state()->get('node.node_access_needs_rebuild'), 'Node access permissions have been rebuilt');
$this->assertTrue(\Drupal::service('node.grant_storage')->access($node, 'view', $this->webUser), 'The expected node access records are present');
foreach ($nodes as $node) {
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'After rebuilding node access the grant storage returns allowed for the node author.');
$this->assertFalse($grant_storage->access($node, 'view', $this->adminUser)->isForbidden(), 'After rebuilding node access the grant storage returns forbidden for the admin user.');
}
$this->assertFalse(\Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is no all realm access record');
// Test an anonymous node access rebuild from code.
$this->drupalLogout();
node_access_rebuild();
foreach ($nodes as $node) {
$this->assertTrue($grant_storage->access($node, 'view', $this->webUser)->isAllowed(), 'After rebuilding node access the grant storage returns allowed for the node author.');
$this->assertFalse($grant_storage->access($node, 'view', $this->adminUser)->isForbidden(), 'After rebuilding node access the grant storage returns forbidden for the admin user.');
}
$this->assertFalse(\Drupal::service('node.grant_storage')->checkAll($this->webUser), 'There is no all realm access record');
}
......