Commit 6ad03576 authored by webchick's avatar webchick

Issue #2538000 by phenaproxima, quietone, benjy, mikeryan: The d6_node plugin...

Issue #2538000 by phenaproxima, quietone, benjy, mikeryan: The d6_node plugin should fetch CCK field values
parent d6d3f6a6
id: d6_cck_field_revision
label: Drupal 6 field revisions
migration_tags:
- Drupal 6
load:
plugin: drupal_entity
bundle_migration: d6_node_type
source:
plugin: d6_cck_field_revision
process:
vid: vid
destination:
plugin: entity_revision:node
migration_dependencies:
required:
- d6_cck_field_values
- d6_node_revision:*
id: d6_cck_field_values
label: Drupal 6 field values
migration_tags:
- Drupal 6
load:
plugin: drupal_entity
bundle_migration: d6_node_type
source:
plugin: d6_cck_field_values
process:
nid:
plugin: migration
migration: d6_node
source: nid
destination:
plugin: entity:node
migration_dependencies:
required:
- d6_node:*
- d6_field_formatter_settings
- d6_field_instance_widget_settings
<?php
/**
* @file
* Contains \Drupal\migrate_drupal\Plugin\migrate\source\d6\CckFieldRevision.
*/
namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
/**
* Drupal 6 cck field revision source.
*
* @MigrateSource(
* id = "d6_cck_field_revision"
* )
*/
class CckFieldRevision extends CckFieldValues {
/**
* The join options between the node and the node_revisions_table.
*/
const JOIN = 'n.nid = nr.nid AND n.vid <> nr.vid';
/**
* {@inheritdoc}
*/
public function fields() {
// Use all the node fields plus the vid that identifies the version.
return parent::fields() + array('vid' => t('The primary identifier for this version.'));
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['vid']['type'] = 'integer';
$ids['vid']['alias'] = 'nr';
return $ids;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateCckFieldRevisionTest.
*/
namespace Drupal\migrate_drupal\Tests\d6;
use Drupal\migrate\MigrateExecutable;
use Drupal\node\Tests\Migrate\d6\MigrateNodeTestBase;
/**
* CCK field revision migration.
*
* @group migrate_drupal_6
*/
class MigrateCckFieldRevisionTest extends MigrateNodeTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field', 'filter', 'node', 'text');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test',
'type' => 'text',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_two',
'type' => 'integer',
'cardinality' => -1,
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_two',
'bundle' => 'story',
))->save();
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_cck_field_values' => array(
array(array(1), array(1)),
),
'd6_node' => array(
array(array(1), array(1)),
array(array(2), array(2)),
),
'd6_node_revision' => array(
array(array(1), array(1)),
),
);
$this->prepareMigrations($id_mappings);
$migrations = entity_load_multiple('migration', array('d6_cck_field_revision:*'));
foreach ($migrations as $migration) {
$executable = new MigrateExecutable($migration, $this);
$executable->import();
}
}
/**
* Test CCK revision migration from Drupal 6 to 8.
*/
public function testCckFieldRevision() {
$node = \Drupal::entityManager()->getStorage('node')->loadRevision(2);
$this->assertIdentical('1', $node->id(), 'Node 1 loaded.');
$this->assertIdentical('2', $node->getRevisionId(), 'Node 1 revision 2loaded.');
}
}
<?php
/**
* @file
* Contains \Drupal\migrate_drupal\Tests\d6\MigrateCckFieldValuesTest.
*/
namespace Drupal\migrate_drupal\Tests\d6;
use Drupal\migrate\MigrateExecutable;
use Drupal\node\Entity\Node;
use Drupal\node\Tests\Migrate\d6\MigrateNodeTestBase;
/**
* CCK field content migration.
*
* @group migrate_drupal_6
*/
class MigrateCckFieldValuesTest extends MigrateNodeTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'text', 'filter', 'link', 'file');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
$node = entity_create('node', array(
'type' => 'story',
'nid' => 2,
'vid' => 12,
'revision_log' => '',
'title' => $this->randomString(),
));
$node->enforceIsNew();
$node->save();
$planet_nodes = [
4 => 6,
5 => 8,
6 => 9,
7 => 10,
8 => 11,
];
foreach ($planet_nodes as $nid => $vid) {
$node = entity_create('node', array(
'type' => 'test_planet',
'nid' => $nid,
'vid' => $vid,
'revision_log' => '',
'title' => $this->randomString(),
));
$node->enforceIsNew();
$node->save();
}
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test',
'type' => 'text',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_two',
'type' => 'integer',
'cardinality' => -1,
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_two',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_three',
'type' => 'decimal',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_three',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_integer_selectlist',
'type' => 'integer',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_integer_selectlist',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_exclude_unset',
'type' => 'text',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_exclude_unset',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_multivalue',
'type' => 'decimal',
'precision' => '10',
'scale' => '2',
'cardinality' => -1,
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_multivalue',
'bundle' => 'test_planet',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_identical1',
'type' => 'integer',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_identical1',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_identical2',
'type' => 'integer',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_identical2',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_link',
'type' => 'link',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_link',
'bundle' => 'story',
))->save();
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_filefield',
'type' => 'file',
))->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_name' => 'field_test_filefield',
'bundle' => 'story',
))->save();
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_field_formatter_settings' => array(
array(array('page', 'default', 'node', 'field_test'), array('node', 'page', 'default', 'field_test')),
),
'd6_field_instance_widget_settings' => array(
array(array('page', 'field_test'), array('node', 'page', 'default', 'test')),
),
'd6_node' => array(
array(array(1), array(1)),
array(array(2), array(2)),
array(array(3), array(3)),
),
);
$this->prepareMigrations($id_mappings);
$migrations = entity_load_multiple('migration', array('d6_cck_field_values:*'));
foreach ($migrations as $migration) {
$executable = new MigrateExecutable($migration, $this);
$executable->import();
}
}
/**
* Test CCK migration from Drupal 6 to 8.
*/
public function testCckFields() {
$node = Node::load(1);
$this->assertIdentical('This is a shared text field', $node->field_test->value);
$this->assertIdentical('filtered_html', $node->field_test->format);
$this->assertIdentical('10', $node->field_test_two->value);
$this->assertIdentical('20', $node->field_test_two[1]->value);
$this->assertIdentical('42.42', $node->field_test_three->value, 'Single field second value is correct.');
$this->assertIdentical('3412', $node->field_test_integer_selectlist[0]->value);
$this->assertIdentical('1', $node->field_test_identical1->value, 'Integer value is correct');
$this->assertIdentical('1', $node->field_test_identical2->value, 'Integer value is correct');
$this->assertIdentical('This is a field with exclude unset.', $node->field_test_exclude_unset->value, 'Field with exclude unset is correct.');
// Test that link fields are migrated.
$this->assertIdentical('https://www.drupal.org/project/drupal', $node->field_test_link->uri);
$this->assertIdentical('Drupal project page', $node->field_test_link->title);
$this->assertIdentical(['target' => '_blank'], $node->field_test_link->options['attributes']);
// Test the file field meta.
$this->assertIdentical('desc', $node->field_test_filefield->description);
$this->assertIdentical('5', $node->field_test_filefield->target_id);
$planet_node = Node::load(3);
$value_1 = $planet_node->field_multivalue->value;
$value_2 = $planet_node->field_multivalue[1]->value;
// SQLite does not support scales for float data types so we need to convert
// the value manually.
if ($this->container->get('database')->driver() == 'sqlite') {
$value_1 = sprintf('%01.2f', $value_1);
$value_2 = sprintf('%01.2f', $value_2);
}
$this->assertIdentical('33.00', $value_1);
$this->assertIdentical('44.00', $value_2);
}
}
......@@ -77,8 +77,6 @@ class MigrateDrupal6Test extends MigrateFullDrupalTestBase {
'd6_block_content_type',
'd6_book',
'd6_book_settings',
'd6_cck_field_values:*',
'd6_cck_field_revision:*',
'd6_comment_type',
'd6_comment',
'd6_comment_entity_display',
......
......@@ -32,6 +32,13 @@ class Node extends DrupalSqlBase implements SourceEntityInterface {
*/
protected $filterDefaultFormat;
/**
* Cached field and field instance definitions.
*
* @var array
*/
protected $fieldInfo;
/**
* {@inheritdoc}
*/
......@@ -115,9 +122,130 @@ public function prepareRow(Row $row) {
if ($row->getSourceProperty('format') === '0') {
$row->setSourceProperty('format', $this->filterDefaultFormat);
}
if ($this->moduleExists('content') && $this->getModuleSchemaVersion('content') >= 6001) {
foreach ($this->getFieldValues($row) as $field => $values) {
foreach ($values as $delta => $item) {
foreach ($item as $column => $value) {
if (strpos($column, $field) === 0) {
$key = substr($column, strlen($field) + 1);
$values[$delta][$key] = $value;
unset($values[$delta][$column]);
}
}
}
$row->setSourceProperty($field, $values);
}
}
return parent::prepareRow($row);
}
/**
* Gets CCK field values for a node.
*
* @param \Drupal\migrate\Row $node
* The node.
*
* @return array
* CCK field values, keyed by field name.
*/
protected function getFieldValues(Row $node) {
$values = [];
foreach ($this->getFieldInfo($node->getSourceProperty('type')) as $field => $info) {
$values[$field] = $this->getCckData($info, $node);
}
return $values;
}
/**
* Gets CCK field and instance definitions from the database.
*
* @param string $node_type
* The node type for which to get field info.
*
* @return array
* Field and instance information for the node type, keyed by field name.
*/
protected function getFieldInfo($node_type) {
if (!isset($this->fieldInfo)) {
$this->fieldInfo = [];
// Query the database directly for all CCK field info.
$query = $this->select('content_node_field_instance', 'cnfi');
$query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
$query->fields('cnfi');
$query->fields('cnf');
foreach ($query->execute() as $field) {
$this->fieldInfo[ $field['type_name'] ][ $field['field_name'] ] = $field;
}
foreach ($this->fieldInfo as $type => $fields) {
foreach ($fields as $field => $info) {
foreach ($info as $property => $value) {
if ($property == 'db_columns' || preg_match('/_settings$/', $property)) {
$this->fieldInfo[$type][$field][$property] = unserialize($value);
}
}
}
}
}
return isset($this->fieldInfo[$node_type]) ? $this->fieldInfo[$node_type] : [];
}
/**
* Retrieves raw CCK field data for a node.
*
* @param array $field
* A field and instance definition from getFieldInfo().
* @param \Drupal\migrate\Row $node
* The node.
*
* @return array
* The field values, keyed by delta.
*/
protected function getCckData(array $field, Row $node) {
$field_table = 'content_' . $field['field_name'];
$node_table = 'content_type_' . $node->getSourceProperty('type');
/** @var \Drupal\Core\Database\Schema $db */
$db = $this->getDatabase()->schema();
if ($db->tableExists($field_table)) {
$query = $this->select($field_table, 't')->fields('t');
// If the delta column does not exist, add it as an expression to
// normalize the query results.
if (!$db->fieldExists($field_table, 'delta')) {
$query->addExpression(0, 'delta');
}
}
elseif ($db->tableExists($node_table)) {
$query = $this->select($node_table, 't');
// Add every DB column CCK knows about.
foreach (array_keys($field['db_columns']) as $column) {
$query->addField('t', $field['field_name'] . '_' . $column);
}
// Every row should have a delta of 0.
$query->addExpression(0, 'delta');
}
if (isset($query)) {
return $query
->condition('nid', $node->getSourceProperty('nid'))
->condition('vid', $node->getSourceProperty('vid'))
->execute()
->fetchAllAssoc('delta');
}
else {
return [];
}
}
/**
* {@inheritdoc}
*/
......
......@@ -18,12 +18,8 @@ class NodeTest extends MigrateSqlSourceTestCase {
const PLUGIN_CLASS = 'Drupal\node\Plugin\migrate\source\d6\Node';
// The fake Migration configuration entity.
protected $migrationConfiguration = array(
'id' => 'test',
// Leave it empty for now.
'idlist' => array(),
// The fake configuration for the source.
'source' => array(
'plugin' => 'd6_node',
),
......@@ -79,10 +75,9 @@ class NodeTest extends MigrateSqlSourceTestCase {
'format' => 1,
),
array(
// Node fields.
'nid' => 5,
'vid' => 5,
'type' => 'article',
'type' => 'story',
'language' => 'en',
'title' => 'node title 5',
'uid' => 1,
......@@ -101,6 +96,9 @@ class NodeTest extends MigrateSqlSourceTestCase {
'log' => '',
'timestamp' => 1279308993,
'format' => 1,
'field_test_four' => array(
array('value' => '3.14159'),
),
),
);
......@@ -108,6 +106,50 @@ class NodeTest extends MigrateSqlSourceTestCase {
* {@inheritdoc}
*/
protected function setUp() {
$this->databaseContents['content_node_field'] = array(
array(
'field_name' => 'field_test_four',
'type' => 'number_float',
'global_settings' => 'a:0:{}',
'required' => '0',
'multiple' => '0',
'db_storage' => '1',
'module' => 'number',
'db_columns' => 'a:1:{s:5:"value";a:3:{s:4:"type";s:5:"float";s:8:"not null";b:0;s:8:"sortable";b:1;}}',
'active' => '1',
'locked' => '0',
),
);
$this->databaseContents['content_node_field_instance'] = array(
array(
'field_name' => 'field_test_four',
'type_name' => 'story',
'weight' => '3',
'label' => 'Float Field',
'widget_type' => 'number',
'widget_settings' => 'a:0:{}',
'display_settings' => 'a:0:{}',
'description' => 'An example float field.',
'widget_module' => 'number',
'widget_active' => '1',
),
);
$this->databaseContents['content_type_story'] = array(
array(
'nid' => 5,
'vid' => 5,
'uid' => 5,
'field_test_four_value' => '3.14159',
),
);
$this->databaseContents['system'] = array(
array(
'type' => 'module',
'name' => 'content',
'schema_version' => 6001,
'status' => TRUE,
),
);
foreach ($this->expectedResults as $k => $row) {
foreach (array('nid', 'vid', 'title', 'uid', 'body', 'teaser', 'format', 'timestamp', 'log') as $field) {
$this->databaseContents['node_revisions'][$k][$field] = $row[$field];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment