Issue #2090541 by plopesc, yched: Avoid storing numeric target_id()'s for default values in field instance CMI files.
parent
b469334d39
commit
72c63698c8
|
|
@ -66,7 +66,7 @@ class LegacyFieldTypeDiscoveryDecorator implements DiscoveryInterface {
|
|||
$definition['id'] = $plugin_id;
|
||||
$definition['provider'] = $module;
|
||||
$definition['configurable'] = TRUE;
|
||||
$definition['list_class'] = '\Drupal\Core\Field\Plugin\Field\FieldType\LegacyConfigFieldItemList';
|
||||
$definition += array('list_class' => '\Drupal\Core\Field\Plugin\Field\FieldType\LegacyConfigFieldItemList');
|
||||
$definitions[$plugin_id] = $definition;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ function entity_reference_field_info_alter(&$info) {
|
|||
$info['entity_reference']['instance_settings']['handler_settings'] = array();
|
||||
$info['entity_reference']['default_widget'] = 'entity_reference_autocomplete';
|
||||
$info['entity_reference']['default_formatter'] = 'entity_reference_label';
|
||||
$info['entity_reference']['list_class'] = '\Drupal\entity_reference\Plugin\Field\FieldType\ConfigurableEntityReferenceFieldItemList';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_info_alter().
|
||||
*
|
||||
* Set the "target_type" property definition for entity reference fields.
|
||||
* Set the "target_type" and "list_class" property definition for entity
|
||||
* reference fields.
|
||||
*
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity_reference\Plugin\Field\FieldType\ConfigurableEntityReferenceFieldItemList.
|
||||
*/
|
||||
|
||||
namespace Drupal\entity_reference\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\ConfigFieldItemList;
|
||||
|
||||
/**
|
||||
* Represents a configurable entity_reference entity field.
|
||||
*/
|
||||
class ConfigurableEntityReferenceFieldItemList extends ConfigFieldItemList {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultValue() {
|
||||
$default_value = parent::getDefaultValue();
|
||||
|
||||
if ($default_value) {
|
||||
// Convert UUIDs to numeric IDs.
|
||||
$uuids = array();
|
||||
$fixed = array();
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
if ($properties['target_uuid'] == 'anonymous' || $properties['target_uuid'] == 'administrator') {
|
||||
$fixed[$delta] = ($properties['target_uuid'] == 'anonymous') ? '0' : '1';
|
||||
}
|
||||
else {
|
||||
$uuids[$delta] = $properties['target_uuid'];
|
||||
}
|
||||
}
|
||||
if ($uuids) {
|
||||
$entities = \Drupal::entityManager()
|
||||
->getStorageController($this->getFieldDefinition()->getFieldSetting('target_type'))
|
||||
->loadByProperties(array('uuid' => $uuids));
|
||||
|
||||
foreach ($entities as $id => $entity) {
|
||||
$entity_ids[$entity->uuid()] = $id;
|
||||
}
|
||||
foreach ($uuids as $delta => $uuid) {
|
||||
if ($entity_ids[$uuid]) {
|
||||
$default_value[$delta]['target_id'] = $entity_ids[$uuid];
|
||||
unset($default_value[$delta]['target_uuid']);
|
||||
}
|
||||
else {
|
||||
unset($default_value[$delta]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fixed) {
|
||||
foreach ($fixed as $delta => $id) {
|
||||
$default_value[$delta]['target_id'] = $id;
|
||||
unset($default_value[$delta]['target_uuid']);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we return consecutive deltas, in case we removed unknown UUIDs.
|
||||
$default_value = array_values($default_value);
|
||||
}
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
|
||||
$default_value = parent::defaultValuesFormSubmit($element, $form, $form_state);
|
||||
|
||||
// Convert numeric IDs to UUIDs to ensure config deployability.
|
||||
$ids = array();
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
$ids[] = $properties['target_id'];
|
||||
}
|
||||
$entities = \Drupal::entityManager()
|
||||
->getStorageController($this->getFieldDefinition()->getFieldSetting('target_type'))
|
||||
->loadMultiple($ids);
|
||||
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
$uuid = $entities[$properties['target_id']]->uuid();
|
||||
// @todo Some entities do not have uuid. IE: Anonymous and admin user.
|
||||
// Remove this special case once http://drupal.org/node/2050843
|
||||
// has been fixed.
|
||||
if (!$uuid) {
|
||||
$uuid = ($properties['target_id'] == '0') ? 'anonymous' : 'administrator';
|
||||
}
|
||||
unset($default_value[$delta]['target_id']);
|
||||
$default_value[$delta]['target_uuid'] = $uuid;
|
||||
}
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity_reference\Tests\EntityReferenceFieldDefaultValueTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\entity_reference\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests entity reference field default values storage in CMI.
|
||||
*/
|
||||
class EntityReferenceFieldDefaultValueTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('entity_reference', 'field_ui', 'node', 'options');
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Reference field default value',
|
||||
'description' => 'Tests the entity reference field default values storage in CMI.',
|
||||
'group' => 'Entity Reference',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create default content type.
|
||||
$this->drupalCreateContentType(array('type' => 'reference_content'));
|
||||
$this->drupalCreateContentType(array('type' => 'referenced_content'));
|
||||
|
||||
// Create admin user.
|
||||
$this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'bypass node access'));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that default values are correctly translated to UUIDs in config.
|
||||
*/
|
||||
function testEntityReferenceDefaultValue() {
|
||||
// Create a node to be referenced.
|
||||
$referenced_node = $this->drupalCreateNode(array('type' => 'referenced_content'));
|
||||
|
||||
$this->field = entity_create('field_entity', array(
|
||||
'name' => drupal_strtolower($this->randomName()),
|
||||
'entity_type' => 'node',
|
||||
'type' => 'entity_reference',
|
||||
'settings' => array('target_type' => 'node'),
|
||||
));
|
||||
$this->field->save();
|
||||
$this->instance = entity_create('field_instance', array(
|
||||
'field_name' => $this->field->name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'reference_content',
|
||||
'settings' => array(
|
||||
'handler' => 'default',
|
||||
'handler_settings' => array(
|
||||
'target_bundles' => array('referenced_content'),
|
||||
'sort' => array('field' => '_none'),
|
||||
),
|
||||
),
|
||||
));
|
||||
$this->instance->save();
|
||||
|
||||
// Set created node as default_value.
|
||||
$instance_edit = array(
|
||||
'default_value_input[' . $this->field->name . '][0][target_id]' => $referenced_node->getTitle() . ' (' .$referenced_node->id() . ')',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/reference_content/fields/node.reference_content.' . $this->field->name, $instance_edit, t('Save settings'));
|
||||
|
||||
// Check that default value is selected in default value form.
|
||||
$this->drupalGet('admin/structure/types/manage/reference_content/fields/node.reference_content.' . $this->field->name);
|
||||
$this->assertRaw('name="default_value_input[' . $this->field->name . '][0][target_id]" value="' . $referenced_node->getTitle() .' (' .$referenced_node->id() . ')', 'The default value is selected in instance settings page');
|
||||
|
||||
// Check if the ID has been converted to UUID in config entity.
|
||||
$config_entity = $this->container->get('config.factory')->get('field.instance.node.reference_content.' . $this->field->name)->get();
|
||||
$this->assertTrue(isset($config_entity['default_value'][0]['target_uuid']), 'Default value contains target_uuid property');
|
||||
$this->assertEqual($config_entity['default_value'][0]['target_uuid'], $referenced_node->uuid(), 'Content uuid and config entity uuid are the same');
|
||||
|
||||
// Clean field_info cache in order to avoid stale cache values.
|
||||
field_info_cache_clear();
|
||||
|
||||
// Create a new node to check that UUID has been converted to numeric ID.
|
||||
$new_node = entity_create('node', array('type' => 'reference_content'));
|
||||
$this->assertEqual($new_node->get($this->field->name)->offsetGet(0)->target_id, $referenced_node->id());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\taxonomy\Plugin\Field\FieldType\TaxonomyTermReferenceFieldItemList.
|
||||
*/
|
||||
|
||||
namespace Drupal\taxonomy\Plugin\Field\FieldType;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\LegacyConfigFieldItemList;
|
||||
|
||||
/**
|
||||
* Represents a configurable taxonomy_term_reference entity field.
|
||||
*/
|
||||
class TaxonomyTermReferenceFieldItemList extends LegacyConfigFieldItemList {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultValue() {
|
||||
$default_value = parent::getDefaultValue();
|
||||
|
||||
if ($default_value) {
|
||||
// Convert UUIDs to numeric IDs.
|
||||
$uuids = array();
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
$uuids[$delta] = $properties['target_uuid'];
|
||||
}
|
||||
if ($uuids) {
|
||||
$entities = \Drupal::entityManager()
|
||||
->getStorageController('taxonomy_term')
|
||||
->loadByProperties(array('uuid' => $uuids));
|
||||
|
||||
foreach ($entities as $id => $entity) {
|
||||
$entity_ids[$entity->uuid()] = $id;
|
||||
}
|
||||
foreach ($uuids as $delta => $uuid) {
|
||||
if (isset($entity_ids[$uuid])) {
|
||||
$default_value[$delta]['target_id'] = $entity_ids[$uuid];
|
||||
unset($default_value[$delta]['target_uuid']);
|
||||
}
|
||||
else {
|
||||
unset($default_value[$delta]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we return consecutive deltas, in case we removed unknown UUIDs.
|
||||
$default_value = array_values($default_value);
|
||||
}
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
|
||||
$default_value = parent::defaultValuesFormSubmit($element, $form, $form_state);
|
||||
|
||||
// Convert numeric IDs to UUIDs to ensure config deployability.
|
||||
$ids = array();
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
$ids[] = $properties['target_id'];
|
||||
}
|
||||
$entities = \Drupal::entityManager()
|
||||
->getStorageController('taxonomy_term')
|
||||
->loadMultiple($ids);
|
||||
|
||||
foreach ($default_value as $delta => $properties) {
|
||||
unset($default_value[$delta]['target_id']);
|
||||
$default_value[$delta]['target_uuid'] = $entities[$properties['target_id']]->uuid();
|
||||
}
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\taxonomy\Tests\TaxonomyUpgradePathTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
use Drupal\system\Tests\Upgrade\UpgradePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests upgrade of taxonomy variables.
|
||||
*/
|
||||
class TaxonomyUpgradePathTest extends UpgradePathTestBase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Taxonomy upgrade test',
|
||||
'description' => 'Tests upgrade of Taxonomy module.',
|
||||
'group' => 'Upgrade path',
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
$this->databaseDumpFiles = array(
|
||||
drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz',
|
||||
drupal_get_path('module', 'taxonomy') . '/tests/upgrade/drupal-7.taxonomy.database.php',
|
||||
);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests upgrade of taxonomy_term_reference field default values.
|
||||
*/
|
||||
public function testEntityDisplayUpgrade() {
|
||||
$this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
|
||||
|
||||
// Check that the configuration entries were created.
|
||||
$config_entity = \Drupal::config('field.instance.node.article.field_tags')->get();
|
||||
$this->assertTrue(!empty($config_entity), 'Config entity has been created');
|
||||
$this->assertTrue(!empty($config_entity['default_value'][0]['target_uuid']), 'Default value contains target_uuid property');
|
||||
|
||||
// Load taxonomy term to check UUID conversion.
|
||||
$taxonomy_term = entity_load('taxonomy_term', 2);
|
||||
|
||||
// Check that default_value has been converted to Drupal 8 structure.
|
||||
$this->assertEqual($taxonomy_term->uuid(), $config_entity['default_value'][0]['target_uuid'], 'Default value contains the right target_uuid');
|
||||
$this->assertEqual('', $config_entity['default_value'][0]['revision_id'], 'Default value contains the right revision_id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -396,3 +396,35 @@ function taxonomy_update_8008() {
|
|||
);
|
||||
db_add_field('taxonomy_term_data', 'changed', $spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert numeric IDs to UUIDs to ensure config deployability.
|
||||
*/
|
||||
function taxonomy_update_8009() {
|
||||
foreach (config_get_storage_names_with_prefix('field.instance.') as $instance_config_name) {
|
||||
$instance_config = \Drupal::config($instance_config_name);
|
||||
if ($instance_config->get('field_type') == 'taxonomy_term_reference') {
|
||||
$default_value = $instance_config->get('default_value');
|
||||
$ids = array();
|
||||
// Load all referenced taxonomy_terms in default_value.
|
||||
foreach ($default_value as $delta => $value) {
|
||||
$ids[] = $value['tid'];
|
||||
}
|
||||
if ($ids) {
|
||||
$entities = db_select('taxonomy_term_data', 't')
|
||||
->fields('t', array('tid', 'uuid'))
|
||||
->condition('t.tid', $ids)
|
||||
->execute()->fetchAllAssoc('tid');
|
||||
|
||||
// Convert IDs to UUIDs and save the new default_value.
|
||||
foreach ($default_value as $delta => &$value) {
|
||||
$value = array(
|
||||
'target_uuid' => $entities[$value['tid']]->uuid,
|
||||
'revision_id' => '',
|
||||
);
|
||||
}
|
||||
$instance_config->set('default_value', $default_value)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -845,6 +845,7 @@ function taxonomy_field_info() {
|
|||
),
|
||||
),
|
||||
),
|
||||
'list_class' => '\Drupal\taxonomy\Plugin\Field\FieldType\TaxonomyTermReferenceFieldItemList',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Database additions for taxonomy variables. Used in TaxonomyUpgradePathTest.
|
||||
*
|
||||
* The drupal-7.bare.standard_all.php file is imported before this dump, so the
|
||||
* two form the database structure expected in tests altogether.
|
||||
*/
|
||||
|
||||
// Add a new taxonomy_term in taxonomy_term_data table.
|
||||
db_insert('taxonomy_term_data')
|
||||
->fields(array(
|
||||
'tid',
|
||||
'vid',
|
||||
'name',
|
||||
'description',
|
||||
'format',
|
||||
'weight',
|
||||
))
|
||||
->values(array(
|
||||
'tid' => '2',
|
||||
'vid' => '1',
|
||||
'name' => 'Default term',
|
||||
'description' => '',
|
||||
'format' => NULL,
|
||||
'weight' => '0',
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Add a new taxonomy_term in taxonomy_term_hierarchy table.
|
||||
db_insert('taxonomy_term_hierarchy')
|
||||
->fields(array(
|
||||
'tid',
|
||||
'parent',
|
||||
))
|
||||
->values(array(
|
||||
'tid' => '2',
|
||||
'parent' => '0',
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Set the taxonomy_term added as default value for field_tags instance.
|
||||
db_update('field_config_instance')
|
||||
->fields(array(
|
||||
'data' => 'a:7:{s:5:"label";s:4:"Tags";s:11:"description";s:63:"Enter a comma-separated list of words to describe your content.";s:6:"widget";a:5:{s:6:"weight";i:-4;s:4:"type";s:21:"taxonomy_autocomplete";s:6:"module";s:8:"taxonomy";s:6:"active";i:0;s:8:"settings";a:2:{s:4:"size";i:60;s:17:"autocomplete_path";s:21:"taxonomy/autocomplete";}}s:7:"display";a:2:{s:7:"default";a:5:{s:4:"type";s:28:"taxonomy_term_reference_link";s:6:"weight";i:10;s:5:"label";s:5:"above";s:8:"settings";a:0:{}s:6:"module";s:8:"taxonomy";}s:6:"teaser";a:5:{s:4:"type";s:28:"taxonomy_term_reference_link";s:6:"weight";i:10;s:5:"label";s:5:"above";s:8:"settings";a:0:{}s:6:"module";s:8:"taxonomy";}}s:8:"settings";a:1:{s:18:"user_register_form";b:0;}s:8:"required";i:0;s:13:"default_value";a:1:{i:0;a:8:{s:3:"tid";s:1:"2";s:3:"vid";s:1:"1";s:4:"name";s:12:"Default term";s:11:"description";s:0:"";s:6:"format";s:13:"filtered_html";s:6:"weight";s:1:"0";s:23:"vocabulary_machine_name";s:4:"tags";s:11:"rdf_mapping";a:5:{s:7:"rdftype";a:1:{i:0;s:12:"skos:Concept";}s:4:"name";a:1:{s:10:"predicates";a:2:{i:0;s:10:"rdfs:label";i:1;s:14:"skos:prefLabel";}}s:11:"description";a:1:{s:10:"predicates";a:1:{i:0;s:15:"skos:definition";}}s:3:"vid";a:2:{s:10:"predicates";a:1:{i:0;s:13:"skos:inScheme";}s:4:"type";s:3:"rel";}s:6:"parent";a:2:{s:10:"predicates";a:1:{i:0;s:12:"skos:broader";}s:4:"type";s:3:"rel";}}}}}')
|
||||
)
|
||||
->condition('field_name', 'field_tags')
|
||||
->execute();
|
||||
Loading…
Reference in New Issue