Commit de14b6d1 authored by webchick's avatar webchick

Issue #2590993 by mikeryan, webflo, svendecabooter, dixon_, phenaproxima:...

Issue #2590993 by mikeryan, webflo, svendecabooter, dixon_, phenaproxima: Create stub entities with proper default values
parent 87ac5406
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Migrate\MigrateAggregatorStubTest.
*/
namespace Drupal\aggregator\Tests\Migrate;
use Drupal\migrate\MigrateException;
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
use Drupal\migrate_drupal\Tests\StubTestTrait;
/**
* Test stub creation for aggregator feeds and items.
*
* @group aggregator
*/
class MigrateAggregatorStubTest extends MigrateDrupalTestBase {
use StubTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['aggregator'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('aggregator_feed');
$this->installEntitySchema('aggregator_item');
}
/**
* Tests creation of aggregator feed stubs.
*/
public function testFeedStub() {
$this->performStubTest('aggregator_feed');
}
/**
* Tests creation of aggregator feed items.
*/
public function testItemStub() {
try {
// We expect an exception, because there's no feed to reference.
$this->performStubTest('aggregator_item');
$this->fail('Expected exception has not been thrown.');
}
catch (MigrateException $e) {
$this->assertIdentical($e->getMessage(),
'Stubbing failed, unable to generate value for field fid');
}
// The stub should pass when there's a feed to point to.
$this->createStub('aggregator_feed');
$this->performStubTest('aggregator_item');
}
}
<?php
/**
* @file
* Contains \Drupal\block_content\Tests\Migrate\MigrateBlockContentStubTest.
*/
namespace Drupal\block_content\Tests\Migrate;
use Drupal\block_content\Entity\BlockContentType;
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
use Drupal\migrate_drupal\Tests\StubTestTrait;
/**
* Test stub creation for block_content entities.
*
* @group block_content
*/
class MigrateBlockContentStubTest extends MigrateDrupalTestBase {
use StubTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['block_content'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('block_content');
}
/**
* Tests creation of block content stubs with no block_content_type available.
*/
public function testStubFailure() {
$entity_id = $this->createStub('block_content');
$violations = $this->validateStub('block_content', $entity_id);
$this->assertIdentical(count($violations), 1);
$this->assertEqual($violations[0]->getMessage(), t('The referenced entity (%type: %id) does not exist.', [
'%type' => 'block_content_type',
'%id' => 'block_content',
]));
}
/**
* Tests creation of block content stubs when there is a block_content_type.
*/
public function testStubSuccess() {
BlockContentType::create([
'id' => 'test_block_content_type',
'label' => 'Test block content type',
])->save();
$this->performStubTest('block_content');
}
}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\MigrateException; use Drupal\migrate\MigrateException;
...@@ -62,13 +63,15 @@ class EntityComment extends EntityContentBase { ...@@ -62,13 +63,15 @@ class EntityComment extends EntityContentBase {
* The list of bundles this entity type has. * The list of bundles this entity type has.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager service. * The entity manager service.
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
* The field type plugin manager service.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* The state storage object. * The state storage object.
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query
* The query object that can query the given entity type. * The query object that can query the given entity type.
*/ */
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, StateInterface $state, QueryFactory $entity_query) { public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, StateInterface $state, QueryFactory $entity_query) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager); parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager);
$this->state = $state; $this->state = $state;
$this->entityQuery = $entity_query; $this->entityQuery = $entity_query;
} }
...@@ -86,6 +89,7 @@ public static function create(ContainerInterface $container, array $configuratio ...@@ -86,6 +89,7 @@ public static function create(ContainerInterface $container, array $configuratio
$container->get('entity.manager')->getStorage($entity_type), $container->get('entity.manager')->getStorage($entity_type),
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)), array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
$container->get('entity.manager'), $container->get('entity.manager'),
$container->get('plugin.manager.field.field_type'),
$container->get('state'), $container->get('state'),
$container->get('entity.query') $container->get('entity.query')
); );
...@@ -110,32 +114,9 @@ public function import(Row $row, array $old_destination_id_values = array()) { ...@@ -110,32 +114,9 @@ public function import(Row $row, array $old_destination_id_values = array()) {
*/ */
protected function processStubRow(Row $row) { protected function processStubRow(Row $row) {
parent::processStubRow($row); parent::processStubRow($row);
$stub_commented_entity_type = $row->getDestinationProperty('entity_type'); // Neither uid nor name is required in itself, but it is required to set one
// of them.
// While parent::getEntity() fills the bundle property for stub entities $row->setDestinationProperty('name', 'anonymous_stub');
// if it's still empty, here we must also make sure entity_id/entity_type
// are filled (so $comment->getCommentedEntity() always returns a value).
if (empty($this->stubCommentedEntityIds[$stub_commented_entity_type])) {
// Fill stub entity id. Any id will do, as long as it exists.
$entity_type = $this->entityManager->getDefinition($stub_commented_entity_type);
$id_key = $entity_type->getKey('id');
$result = $this->entityQuery
->get($stub_commented_entity_type)
->range(0, 1)
->execute();
if ($result) {
$this->stubCommentedEntityIds[$stub_commented_entity_type] = array_pop($result);
$row->setSourceProperty($id_key, $this->stubCommentedEntityIds[$stub_commented_entity_type]);
}
else {
throw new MigrateException(t('Could not find parent entity to use for comment %id', ['%id' => implode(':', $row->getSourceIdValues())]), MigrationInterface::MESSAGE_ERROR);
}
}
$row->setDestinationProperty('entity_id', $this->stubCommentedEntityIds[$stub_commented_entity_type]);
$row->setDestinationProperty('entity_type', $stub_commented_entity_type);
$row->setDestinationProperty('created', REQUEST_TIME);
$row->setDestinationProperty('changed', REQUEST_TIME);
} }
} }
<?php
/**
* @file
* Contains \Drupal\comment\Tests\Migrate\MigrateCommentStubTest.
*/
namespace Drupal\comment\Tests\Migrate;
use Drupal\comment\Entity\CommentType;
use Drupal\migrate\MigrateException;
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
use Drupal\migrate_drupal\Tests\StubTestTrait;
use Drupal\node\Entity\NodeType;
/**
* Test stub creation for comment entities.
*
* @group comment
*/
class MigrateCommentStubTest extends MigrateDrupalTestBase {
use StubTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['comment', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('comment');
$this->installEntitySchema('node');
// Make sure uid 0 is created (default uid for comments is 0).
$storage = \Drupal::entityManager()->getStorage('user');
// Insert a row for the anonymous user.
$storage
->create(array(
'uid' => 0,
'status' => 0,
'name' => '',
))
->save();
// Need at least one node type and comment type present.
NodeType::create([
'type' => 'testnodetype',
'name' => 'Test node type',
])->save();
CommentType::create([
'id' => 'testcommenttype',
'label' => 'Test comment type',
'target_entity_type_id' => 'node',
])->save();
}
/**
* Tests creation of comment stubs.
*/
public function testStub() {
try {
// We expect an exception, because there's no node to reference.
$this->performStubTest('comment');
$this->fail('Expected exception has not been thrown.');
}
catch (MigrateException $e) {
$this->assertIdentical($e->getMessage(),
'Stubbing failed, unable to generate value for field entity_id');
}
// The stub should pass when there's a node to point to.
$this->createStub('node');
$this->performStubTest('comment');
}
}
...@@ -22,13 +22,7 @@ class MigrateCommentTest extends MigrateDrupal6TestBase { ...@@ -22,13 +22,7 @@ class MigrateCommentTest extends MigrateDrupal6TestBase {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public static $modules = [ public static $modules = ['comment'];
'comment',
// Directly testing that a stub comment's entity_id is populated upon
// importing is not straightforward, but RDF module serves as an implicit
// test - its hook_comment_storage_load() references a stubbed comment.
'rdf',
];
/** /**
* {@inheritdoc} * {@inheritdoc}
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
use Drupal\Core\File\FileSystemInterface; use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\LocalStream; use Drupal\Core\StreamWrapper\LocalStream;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
...@@ -41,7 +43,7 @@ class EntityFile extends EntityContentBase { ...@@ -41,7 +43,7 @@ class EntityFile extends EntityContentBase {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) { public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) {
$configuration += array( $configuration += array(
'source_base_path' => '', 'source_base_path' => '',
'source_path_property' => 'filepath', 'source_path_property' => 'filepath',
...@@ -49,7 +51,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition ...@@ -49,7 +51,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
'move' => FALSE, 'move' => FALSE,
'urlencode' => FALSE, 'urlencode' => FALSE,
); );
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager); parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager);
$this->streamWrapperManager = $stream_wrappers; $this->streamWrapperManager = $stream_wrappers;
$this->fileSystem = $file_system; $this->fileSystem = $file_system;
...@@ -68,6 +70,7 @@ public static function create(ContainerInterface $container, array $configuratio ...@@ -68,6 +70,7 @@ public static function create(ContainerInterface $container, array $configuratio
$container->get('entity.manager')->getStorage($entity_type), $container->get('entity.manager')->getStorage($entity_type),
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)), array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
$container->get('entity.manager'), $container->get('entity.manager'),
$container->get('plugin.manager.field.field_type'),
$container->get('stream_wrapper_manager'), $container->get('stream_wrapper_manager'),
$container->get('file_system') $container->get('file_system')
); );
...@@ -77,6 +80,12 @@ public static function create(ContainerInterface $container, array $configuratio ...@@ -77,6 +80,12 @@ public static function create(ContainerInterface $container, array $configuratio
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function getEntity(Row $row, array $old_destination_id_values) { protected function getEntity(Row $row, array $old_destination_id_values) {
// For stub rows, there is no real file to deal with, let the stubbing
// process take its default path.
if ($row->isStub()) {
return parent::getEntity($row, $old_destination_id_values);
}
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']); $destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
$entity = $this->storage->loadByProperties(['uri' => $destination]); $entity = $this->storage->loadByProperties(['uri' => $destination]);
if ($entity) { if ($entity) {
...@@ -91,6 +100,12 @@ protected function getEntity(Row $row, array $old_destination_id_values) { ...@@ -91,6 +100,12 @@ protected function getEntity(Row $row, array $old_destination_id_values) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function import(Row $row, array $old_destination_id_values = array()) { public function import(Row $row, array $old_destination_id_values = array()) {
// For stub rows, there is no real file to deal with, let the stubbing
// process create the stub entity.
if ($row->isStub()) {
return parent::import($row, $old_destination_id_values);
}
$file = $row->getSourceProperty($this->configuration['source_path_property']); $file = $row->getSourceProperty($this->configuration['source_path_property']);
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']); $destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
$source = $this->configuration['source_base_path'] . $file; $source = $this->configuration['source_base_path'] . $file;
...@@ -256,4 +271,29 @@ protected function urlencode($filename) { ...@@ -256,4 +271,29 @@ protected function urlencode($filename) {
return $filename; return $filename;
} }
/**
* {@inheritdoc}
*/
protected function processStubRow(Row $row) {
// We stub the uri value ourselves so we can create a real stub file for it.
if (!$row->getDestinationProperty('uri')) {
$field_definitions = $this->entityManager
->getFieldDefinitions($this->storage->getEntityTypeId(),
$this->getKey('bundle'));
$value = UriItem::generateSampleValue($field_definitions['uri']);
if (empty($value)) {
throw new MigrateException('Stubbing failed, unable to generate value for field uri');
}
// generateSampleValue() wraps the value in an array.
$value = reset($value);
// Make it into a proper public file uri, stripping off the existing
// scheme if present.
$value = 'public://' . preg_replace('|^[a-z]+://|i', '', $value);
// Create a real file, so File::preSave() can do filesize() on it.
touch($value);
$row->setDestinationProperty('uri', $value);
}
parent::processStubRow($row);
}
} }
...@@ -24,6 +24,11 @@ class FileUri extends ProcessPluginBase { ...@@ -24,6 +24,11 @@ class FileUri extends ProcessPluginBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
// If we're stubbing a file entity, return a uri of NULL so it will get
// stubbed by the general process.
if ($row->isStub()) {
return NULL;
}
list($filepath, $file_directory_path, $temp_directory_path, $is_public) = $value; list($filepath, $file_directory_path, $temp_directory_path, $is_public) = $value;
// Specific handling using $temp_directory_path for temporary files. // Specific handling using $temp_directory_path for temporary files.
......
<?php
/**
* @file
* Contains \Drupal\file\Tests\Migrate\MigrateFileStubTest.
*/
namespace Drupal\file\Tests\Migrate;
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
use Drupal\migrate_drupal\Tests\StubTestTrait;
/**
* Test stub creation for file entities.
*
* @group file
*/
class MigrateFileStubTest extends MigrateDrupalTestBase {
use StubTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['file'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
}
/**
* Tests creation of file stubs.
*/
public function testStub() {
$this->performStubTest('file');
}
}
<?php
/**
* @file
* Contains \Drupal\menu_link_content\Tests\Migrate\MigrateMenuLinkContentStubTest.
*/
namespace Drupal\menu_link_content\Tests\Migrate;
use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
use Drupal\migrate_drupal\Tests\StubTestTrait;
/**
* Test stub creation for menu link content entities.
*
* @group menu_link_content
*/
class MigrateMenuLinkContentStubTest extends MigrateDrupalTestBase {
use StubTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['menu_link_content', 'link'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('menu_link_content');
}
/**
* Tests creation of menu link content stubs.
*/
public function testStub() {
$this->performStubTest('menu_link_content');
}
}
...@@ -401,8 +401,8 @@ public function processRow(Row $row, array $process = NULL, $value = NULL) { ...@@ -401,8 +401,8 @@ public function processRow(Row $row, array $process = NULL, $value = NULL) {
$multiple = $multiple || $plugin->multiple(); $multiple = $multiple || $plugin->multiple();
} }
} }
// No plugins means do not set. // No plugins or no value means do not set.
if ($plugins) { if ($plugins && !is_null($value)) {
$row->setDestinationProperty($destination, $value); $row->setDestinationProperty($destination, $value);
} }
// Reset the value. // Reset the value.
......
...@@ -136,19 +136,6 @@ protected function getEntityId(Row $row) { ...@@ -136,19 +136,6 @@ protected function getEntityId(Row $row) {
return $row->getDestinationProperty($this->getKey('id')); return $row->getDestinationProperty($this->getKey('id'));
} }
/**
* Process the stub values.
*
* @param \Drupal\migrate\Row $row
* The row of data.
*/
protected function processStubRow(Row $row) {
$bundle_key = $this->getKey('bundle');
if ($bundle_key && empty($row->getDestinationProperty($bundle_key))) {
$row->setDestinationProperty($bundle_key, reset($this->bundles));
}
}
/** /**
* Returns a specific entity key. * Returns a specific entity key.
* *
......
...@@ -7,12 +7,17 @@ ...@@ -7,12 +7,17 @@
namespace Drupal\migrate\Plugin\migrate\destination; namespace Drupal\migrate\Plugin\migrate\destination;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\link\LinkItemInterface;
use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\MigrateException;
use Drupal\migrate\Plugin\MigrateIdMapInterface; use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Row; use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -29,6 +34,13 @@ class EntityContentBase extends Entity { ...@@ -29,6 +34,13 @@ class EntityContentBase extends Entity {
*/ */
protected $entityManager;