Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663

This commit is contained in:
Greg Anderson 2015-10-08 11:40:12 -07:00
parent eb34d130a8
commit f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions

View file

@ -50,6 +50,9 @@ field.storage.*.*:
persist_with_no_fields:
type: boolean
label: 'Persist field storage with no fields'
custom_storage:
type: boolean
label: 'Enable custom storage'
field.field.*.*.*:
type: field_config_base

View file

@ -1,25 +1,5 @@
# Schema for the views plugins of the Field module.
views.argument.field_list:
type: views.argument.numeric
label: 'List field name'
mapping:
human:
type: boolean
label: 'Display list value as human readable'
views.argument.field_list_string:
type: views.argument.string
label: 'List field name'
mapping:
human:
type: boolean
label: 'Display list value as human readable'
views.filter.field_list:
type: views.filter.many_to_one
label: 'List field'
views.relationship.entity_reverse:
type: views_relationship
label: 'Reverse entity reference'

View file

@ -0,0 +1,70 @@
<?php
/**
* @file
* Install, update and uninstall functions for the field module.
*/
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
/**
* Removes the stale 'target_bundle' storage setting on entity_reference fields.
*/
function field_update_8001() {
$config = \Drupal::configFactory();
/** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
// Iterate on all fields storage.
foreach ($config->listAll('field.storage.') as $field_id) {
$field_storage = $config->getEditable($field_id);
$class = $field_type_manager->getPluginClass($field_storage->get('type'));
// Deal only with entity reference fields and descendants.
if ($class == EntityReferenceItem::class || is_subclass_of($class, EntityReferenceItem::class)) {
// Remove 'target_bundle' from settings.
$field_storage->clear('settings.target_bundle')->save(TRUE);
}
}
}
/**
* The 'entity_reference' field type is now provided by core.
*/
function field_update_8002() {
$config_factory = \Drupal::configFactory();
// Iterate on all configuration entities.
foreach ($config_factory->listAll() as $id) {
$changed = FALSE;
$config = $config_factory->getEditable($id);
// Update field storage configurations.
if (strpos($id, 'field.storage.') === 0) {
// Deal only with entity reference fields.
if ($config->get('type') == 'entity_reference') {
// Fix the type provider.
$config->set('module', 'core');
$changed = TRUE;
}
}
// Remove entity_reference module dependency from any configuration entity.
if ($dependencies = $config->get('dependencies.module')) {
if (($delta = array_search('entity_reference', $dependencies)) !== FALSE) {
unset($dependencies[$delta]);
if ($dependencies) {
$config->set('dependencies.module', array_values($dependencies));
}
else {
$config->clear('dependencies.module');
}
$changed = TRUE;
}
}
if ($changed) {
$config->save(TRUE);
}
}
}

View file

@ -8,10 +8,12 @@ use Drupal\Core\Config\ConfigImporter;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldStorageConfig;
/*
* Load all public Field API functions. Drupal currently has no
@ -66,7 +68,7 @@ function field_help($route_name, RouteMatchInterface $route_match) {
$field_ui_url = \Drupal::moduleHandler()->moduleExists('field_ui') ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#';
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Field module allows custom data fields to be defined for <em>entity</em> types (see below). The Field module takes care of storing, loading, editing, and rendering field data. Most users will not interact with the Field module directly, but will instead use the <a href="!field-ui-help">Field UI module</a> user interface. Module developers can use the Field API to make new entity types "fieldable" and thus allow fields to be attached to them. For more information, see the <a href="!field">online documentation for the Field module</a>.', array('!field-ui-help' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) :'#', '!field' => 'https://www.drupal.org/documentation/modules/field')). '</p>';
$output .= '<p>' . t('The Field module allows custom data fields to be defined for <em>entity</em> types (see below). The Field module takes care of storing, loading, editing, and rendering field data. Most users will not interact with the Field module directly, but will instead use the <a href=":field-ui-help">Field UI module</a> user interface. Module developers can use the Field API to make new entity types "fieldable" and thus allow fields to be attached to them. For more information, see the <a href=":field">online documentation for the Field module</a>.', array(':field-ui-help' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) :'#', ':field' => 'https://www.drupal.org/documentation/modules/field')). '</p>';
$output .= '<h3>' . t('Terminology') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Entities and entity types') . '</dt>';
@ -83,7 +85,7 @@ function field_help($route_name, RouteMatchInterface $route_match) {
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Enabling field types, widgets, and formatters') . '</dt>';
$output .= '<dd>' . t('The Field module provides the infrastructure for fields; the field types, formatters, and widgets are provided by Drupal core or additional modules. Some of the modules are required; the optional modules can be enabled from the <a href="!modules">Extend administration page</a>. Additional fields, formatters, and widgets may be provided by contributed modules, which you can find in the <a href="!contrib">contributed module section of Drupal.org</a>.', array('!modules' => \Drupal::url('system.modules_list'), '!contrib' => 'https://www.drupal.org/project/modules')) . '</dd>';
$output .= '<dd>' . t('The Field module provides the infrastructure for fields; the field types, formatters, and widgets are provided by Drupal core or additional modules. Some of the modules are required; the optional modules can be enabled from the <a href=":modules">Extend administration page</a>. Additional fields, formatters, and widgets may be provided by contributed modules, which you can find in the <a href=":contrib">contributed module section of Drupal.org</a>.', array(':modules' => \Drupal::url('system.modules_list'), ':contrib' => 'https://www.drupal.org/project/modules')) . '</dd>';
$output .= '<h3>' . t('Field, widget, and formatter information') . '</h3>';
@ -128,6 +130,25 @@ function field_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dt>' . t('Provided by Drupal core') . '</dt>';
$output .= '<dd>' . t('As mentioned previously, some field types, widgets, and formatters are provided by Drupal core. Here are some notes on how to use some of these:');
$output .= '<ul>';
$output .= '<li><p>' . t('<strong>Entity Reference</strong> fields allow you to create fields that contain links to other entities (such as content items, taxonomy terms, etc.) within the site. This allows you, for example, to include a link to a user within a content item. For more information, see <a href=":er_do">the online documentation for the Entity Reference module</a>.', array(':er_do' => 'https://drupal.org/documentation/modules/entityreference')) . '</p>';
$output .= '<dl>';
$output .= '<dt>' . t('Managing and displaying entity reference fields') . '</dt>';
$output .= '<dd>' . t('The <em>settings</em> and the <em>display</em> of the entity reference field can be configured separately. See the <a href=":field_ui">Field UI help</a> for more information on how to manage fields and their display.', array(':field_ui' => \Drupal::url('help.page', array('name' => 'field_ui')))) . '</dd>';
$output .= '<dt>' . t('Selecting reference type') . '</dt>';
$output .= '<dd>' . t('In the field settings you can select which entity type you want to create a reference to.') . '</dd>';
$output .= '<dt>' . t('Filtering and sorting reference fields') . '</dt>';
$output .= '<dd>' . t('Depending on the chosen entity type, additional filtering and sorting options are available for the list of entities that can be referred to, in the field settings. For example, the list of users can be filtered by role and sorted by name or ID.') . '</dd>';
$output .= '<dt>' . t('Displaying a reference') . '</dt>';
$output .= '<dd>' . t('An entity reference can be displayed as a simple label with or without a link to the entity. Alternatively, the referenced entity can be displayed as a teaser (or any other available view mode) inside the referencing entity.') . '</dd>';
$output .= '<dt>' . t('Configuring form displays') . '</dt>';
$output .= '<dd>' . t('Reference fields have several widgets available on the <em>Manage form display</em> page:');
$output .= '<ul>';
$output .= '<li>' . t('The <em>Check boxes/radio buttons</em> widget displays the existing entities for the entity type as check boxes or radio buttons based on the <em>Allowed number of values</em> set for the field.') . '</li>';
$output .= '<li>' . t('The <em>Select list</em> widget displays the existing entities in a drop-down list or scrolling list box based on the <em>Allowed number of values</em> setting for the field.') . '</li>';
$output .= '<li>' . t('The <em>Autocomplete</em> widget displays text fields in which users can type entity labels based on the <em>Allowed number of values</em>. The widget can be configured to display all entities that contain the typed characters or restricted to those starting with those characters.') . '</li>';
$output .= '<li>' . t('The <em>Autocomplete (Tags style)</em> widget displays a multi-text field in which users can type in a comma-separated list of entity labels.') . '</li>';
$output .= '</ul></dd>';
$output .= '</dl></li>';
$output .= '<li>' . t('<strong>Number fields</strong>: When you add a number field you can choose from three types: <em>decimal</em>, <em>float</em>, and <em>integer</em>. The <em>decimal</em> number field type allows users to enter exact decimal values, with fixed numbers of decimal places. The <em>float</em> number field type allows users to enter approximate decimal values. The <em>integer</em> number field type allows users to enter whole numbers, such as years (for example, 2012) or values (for example, 1, 2, 5, 305). It does not allow decimals.') . '</li>';
$output .= '</ul></dd>';
$output .= '</dl>';
@ -186,46 +207,63 @@ function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundl
}
}
/**
* Implements hook_entity_bundle_rename().
*/
function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
$fields = entity_load_multiple_by_properties('field_config', array('entity_type' => $entity_type, 'bundle' => $bundle_old, 'include_deleted' => TRUE));
foreach ($fields as $field) {
$id_new = $field->getTargetEntityTypeId() . '.' . $bundle_new . '.' . $field->getName();
$field->set('id', $id_new);
$field->set('bundle', $bundle_new);
// Save non-deleted fields.
if (!$field->isDeleted()) {
$field->allowBundleRename();
$field->save();
}
// Update deleted fields directly in the state storage.
else {
$state = \Drupal::state();
$deleted_fields = $state->get('field.field.deleted') ?: array();
$deleted_fields[$field->uuid] = $field->toArray();
$state->set('field.field.deleted', $deleted_fields);
}
}
}
/**
* Implements hook_entity_bundle_delete().
*
* This deletes the data for the field as well as the field themselves. This
* function actually just marks the data and fields as deleted, leaving the
* garbage collection for a separate process, because it is not always
* possible to delete this much data in a single page request (particularly
* since for some field types, the deletion is more than just a simple DELETE
* query).
*/
function field_entity_bundle_delete($entity_type, $bundle) {
function field_entity_bundle_delete($entity_type_id, $bundle) {
$storage = \Drupal::entityManager()->getStorage('field_config');
// Get the fields on the bundle.
$fields = entity_load_multiple_by_properties('field_config', array('entity_type' => $entity_type, 'bundle' => $bundle));
$fields = $storage->loadByProperties(['entity_type' => $entity_type_id, 'bundle' => $bundle]);
// This deletes the data for the field as well as the field themselves. This
// function actually just marks the data and fields as deleted, leaving the
// garbage collection for a separate process, because it is not always
// possible to delete this much data in a single page request (particularly
// since for some field types, the deletion is more than just a simple DELETE
// query).
foreach ($fields as $field) {
$field->delete();
}
// We are duplicating the work done by
// \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::onDependencyRemoval()
// because we need to take into account bundles that are not provided by a
// config entity type so they are not part of the config dependencies.
// Gather a list of all entity reference fields.
$map = \Drupal::entityManager()->getFieldMapByFieldType('entity_reference');
$ids = [];
foreach ($map as $type => $info) {
foreach ($info as $name => $data) {
foreach ($data['bundles'] as $bundle_name) {
$ids[] = "$type.$bundle_name.$name";
}
}
}
// Update the 'target_bundles' handler setting if needed.
foreach (FieldConfig::loadMultiple($ids) as $field_config) {
if ($field_config->getSetting('target_type') == $entity_type_id) {
$handler_settings = $field_config->getSetting('handler_settings');
if (isset($handler_settings['target_bundles'][$bundle])) {
unset($handler_settings['target_bundles'][$bundle]);
$field_config->setSetting('handler_settings', $handler_settings);
$field_config->save();
// In case we deleted the only target bundle allowed by the field we
// have to log a warning message because the field will not function
// correctly anymore.
if ($handler_settings['target_bundles'] === []) {
\Drupal::logger('entity_reference')->critical('The %target_bundle bundle (entity type: %target_entity_type) was deleted. As a result, the %field_name entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', [
'%target_bundle' => $bundle,
'%target_entity_type' => $entity_type_id,
'%field_name' => $field_config->getName(),
'%entity_type' => $field_config->getTargetEntityTypeId(),
'%bundle' => $field_config->getTargetBundle()
]);
}
}
}
}
}
/**
@ -304,3 +342,65 @@ function field_form_config_admin_import_form_alter(&$form, FormStateInterface $f
}
}
}
/**
* Implements hook_ENTITY_TYPE_update() for 'field_storage_config'.
*
* Reset the field handler settings, when the storage target_type is changed on
* an entity reference field.
*/
function field_field_storage_config_update(FieldStorageConfigInterface $field_storage) {
if ($field_storage->isSyncing()) {
// Don't change anything during a configuration sync.
return;
}
// Act on all sub-types of the entity_reference field type.
/** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
$item_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
$class = $field_type_manager->getPluginClass($field_storage->getType());
if ($class !== $item_class && !is_subclass_of($class, $item_class)) {
return;
}
// If target_type changed, reset the handler in the fields using that storage.
if ($field_storage->getSetting('target_type') !== $field_storage->original->getSetting('target_type')) {
foreach ($field_storage->getBundles() as $bundle) {
$field = FieldConfig::loadByName($field_storage->getTargetEntityTypeId(), $bundle, $field_storage->getName());
// Reset the handler settings. This triggers field_field_config_presave(),
// which will take care of reassigning the handler to the correct
// derivative for the new target_type.
$field->setSetting('handler_settings', []);
$field->save();
}
}
}
/**
* Implements hook_ENTITY_TYPE_presave() for 'field_config'.
*
* Determine the selection handler plugin ID for an entity reference field.
*/
function field_field_config_presave(FieldConfigInterface $field) {
// Don't change anything during a configuration sync.
if ($field->isSyncing()) {
return;
}
// Act on all sub-types of the entity_reference field type.
/** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
$item_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
$class = $field_type_manager->getPluginClass($field->getType());
if ($class !== $item_class && !is_subclass_of($class, $item_class)) {
return;
}
// Make sure the selection handler plugin is the correct derivative for the
// target entity type.
$target_type = $field->getFieldStorageDefinition()->getSetting('target_type');
$selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
list($current_handler) = explode(':', $field->getSetting('handler'), 2);
$field->setSetting('handler', $selection_manager->getPluginId($target_type, $current_handler));
}

View file

@ -0,0 +1,46 @@
<?php
/**
* @file
* Post update functions for Field module.
*/
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
/**
* @addtogroup updates-8.0.0-beta
* @{
*/
/**
* Re-save all field storage config objects to add 'custom_storage' property.
*/
function field_post_update_save_custom_storage_property() {
foreach (FieldStorageConfig::loadMultiple() as $field_storage_config) {
$field_storage_config->save();
}
return t('All field storage configuration objects re-saved.');
}
/**
* Fixes the 'handler' setting for entity reference fields.
*/
function field_post_update_entity_reference_handler_setting() {
foreach (FieldConfig::loadMultiple() as $field_config) {
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
$item_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
$class = $field_type_manager->getPluginClass($field_config->getType());
if ($class === $item_class || is_subclass_of($class, $item_class)) {
// field_field_config_presave() will fix the 'handler' setting on save.
$field_config->save();
}
}
return t('Selection handler for entity reference fields have been adjusted.');
}
/**
* @} End of "addtogroup updates-8.0.0-beta".
*/

View file

@ -1,5 +1,5 @@
id: d6_field
label: Drupal 6 field configuration
label: Field configuration
migration_tags:
- Drupal 6
builder:
@ -128,9 +128,8 @@ process:
settings:
plugin: field_settings
source:
- @type
- '@type'
- global_settings
- widget_settings
destination:
plugin: md_entity:field_storage_config

View file

@ -1,5 +1,5 @@
id: d6_field_formatter_settings
label: Drupal 6 field formatter configuration
label: Field formatter configuration
migration_tags:
- Drupal 6
builder:

View file

@ -1,5 +1,5 @@
id: d6_field_instance
label: Drupal 6 field instance configuration
label: Field instance configuration
migration_tags:
- Drupal 6
builder:

View file

@ -1,5 +1,5 @@
id: d6_field_instance_widget_settings
label: Drupal 6 field instance widget configuration
label: Field instance widget configuration
migration_tags:
- Drupal 6
builder:

View file

@ -1,5 +1,5 @@
id: d7_field
label: Drupal 7 field configuration
label: Field configuration
migration_tags:
- Drupal 7
source:

View file

@ -1,5 +1,5 @@
id: d7_field_formatter_settings
label: Drupal 7 field formatter configuration
label: Field formatter configuration
migration_tags:
- Drupal 7
source:

View file

@ -1,4 +1,5 @@
id: d7_field_instance
label: Field instance configuration
migration_tags:
- Drupal 7
source:

View file

@ -1,5 +1,5 @@
id: d7_field_instance_widget_settings
label: Drupal 7 field instance widget configuration
label: Field instance widget configuration
migration_tags:
- Drupal 7
source:
@ -15,12 +15,12 @@ process:
plugin: migration
migration: d7_field
source:
- entity_type
- field_name
- entity_type
-
plugin: extract
index:
- 1
- 0
-
plugin: skip_on_empty
method: row
@ -44,6 +44,7 @@ process:
phone_textfield: telephone_default
options_onoff: boolean_checkbox
entityreference_autocomplete: entity_reference_autocomplete
taxonomy_autocomplete: entity_reference_autocomplete
'options/settings':
plugin: field_instance_widget_settings
source:

View file

@ -1,5 +1,5 @@
id: d7_view_modes
label: Drupal 7 view modes
label: View modes
migration_tags:
- Drupal 7
source:

View file

@ -167,7 +167,7 @@ class FieldConfig extends FieldConfigBase implements FieldConfigInterface {
if ($this->entity_type != $this->original->entity_type) {
throw new FieldException("Cannot change an existing field's entity_type.");
}
if ($this->bundle != $this->original->bundle && empty($this->bundleRenameAllowed)) {
if ($this->bundle != $this->original->bundle) {
throw new FieldException("Cannot change an existing field's bundle.");
}
if ($storage_definition->uuid() != $this->original->getFieldStorageDefinition()->uuid()) {
@ -187,7 +187,7 @@ class FieldConfig extends FieldConfigBase implements FieldConfigInterface {
parent::calculateDependencies();
// Mark the field_storage_config as a a dependency.
$this->addDependency('config', $this->getFieldStorageDefinition()->getConfigDependencyName());
return $this->dependencies;
return $this;
}
/**

View file

@ -42,6 +42,7 @@ use Drupal\field\FieldStorageConfigInterface;
* "translatable",
* "indexes",
* "persist_with_no_fields",
* "custom_storage",
* }
* )
*/
@ -160,6 +161,13 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
*/
protected $persist_with_no_fields = FALSE;
/**
* A boolean indicating whether or not the field item uses custom storage.
*
* @var bool
*/
public $custom_storage = FALSE;
/**
* The custom storage indexes for the field data storage.
*
@ -335,10 +343,15 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
parent::calculateDependencies();
// Ensure the field is dependent on the providing module.
$this->addDependency('module', $this->getTypeProvider());
// Ask the field type for any additional storage dependencies.
// @see \Drupal\Core\Field\FieldItemInterface::calculateStorageDependencies()
$definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType(), FALSE);
$this->addDependencies($definition['class']::calculateStorageDependencies($this));
// Ensure the field is dependent on the provider of the entity type.
$entity_type = \Drupal::entityManager()->getDefinition($this->entity_type);
$this->addDependency('module', $entity_type->getProvider());
return $this->dependencies;
return $this;
}
/**
@ -436,6 +449,7 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
$schema = $class::schema($this);
// Fill in default values for optional entries.
$schema += array(
'columns' => array(),
'unique keys' => array(),
'indexes' => array(),
'foreign keys' => array(),
@ -455,7 +469,7 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
* {@inheritdoc}
*/
public function hasCustomStorage() {
return FALSE;
return $this->custom_storage;
}
/**
@ -565,7 +579,7 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
* {@inheritdoc}
*/
public function setSettings(array $settings) {
$this->settings = $settings;
$this->settings = $settings + $this->settings;
return $this;
}

View file

@ -22,7 +22,7 @@ class FieldConfigAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
if ($operation == 'delete') {
$field_storage_entity = $entity->getFieldStorageDefinition();
if ($field_storage_entity->isLocked()) {

View file

@ -96,10 +96,32 @@ interface FieldStorageConfigInterface extends ConfigEntityInterface, FieldStorag
public function setSetting($setting_name, $value);
/**
* Sets field settings (overwrites existing settings).
* Sets field storage settings.
*
* Note that the method does not unset existing settings not specified in the
* incoming $settings array.
*
* For example:
* @code
* // Given these are the default settings.
* $storage_definition->getSettings() === [
* 'fruit' => 'apple',
* 'season' => 'summer',
* ];
* // Change only the 'fruit' setting.
* $storage_definition->setSettings(['fruit' => 'banana']);
* // The 'season' setting persists unchanged.
* $storage_definition->getSettings() === [
* 'fruit' => 'banana',
* 'season' => 'summer',
* ];
* @endcode
*
* For clarity, it is preferred to use setSetting() if not all available
* settings are supplied.
*
* @param array $settings
* The array of field settings.
* The array of storage settings.
*
* @return $this
*/

View file

@ -26,8 +26,8 @@ class FieldSettings extends ProcessPluginBase {
* Get the field default/mapped settings.
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
list($field_type, $global_settings, $widget_settings) = $value;
return $this->getSettings($field_type, $global_settings, $widget_settings);
list($field_type, $global_settings) = $value;
return $this->getSettings($field_type, $global_settings);
}
/**
@ -37,13 +37,11 @@ class FieldSettings extends ProcessPluginBase {
* The field type.
* @param array $global_settings
* The field settings.
* @param array $widget_settings
* The widget settings needed for some settings.
*
* @return array
* A valid array of settings.
*/
public function getSettings($field_type, $global_settings, $widget_settings) {
public function getSettings($field_type, $global_settings) {
$max_length = isset($global_settings['max_length']) ? $global_settings['max_length'] : '';
$max_length = empty($max_length) ? 255 : $max_length;
if (isset($global_settings['allowed_values'])) {

View file

@ -24,10 +24,19 @@ class FieldSettings extends ProcessPluginBase {
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$value = $row->getSourceProperty('settings');
if ($row->getSourceProperty('type') == 'image' && !is_array($value['default_image'])) {
$value['default_image'] = array(
'uuid' => '',
);
switch ($row->getSourceProperty('type')) {
case 'image':
if (!is_array($value['default_image'])) {
$value['default_image'] = array('uuid' => '');
}
break;
case 'taxonomy_term_reference':
$value['target_type'] = 'taxonomy_term';
break;
default:
break;
}
return $value;

View file

@ -37,12 +37,9 @@ class Field extends DrupalSqlBase {
'active',
'locked',
))
->fields('cnfi', array(
'widget_type',
'widget_settings',
));
$query->join('content_node_field_instance', 'cnfi', 'cnfi.field_name = cnf.field_name');
$query->orderBy('field_name');
->distinct();
// Only import fields which are actually being used.
$query->innerJoin('content_node_field_instance', 'cnfi', 'cnfi.field_name = cnf.field_name');
return $query;
}
@ -54,6 +51,7 @@ class Field extends DrupalSqlBase {
return array(
'field_name' => $this->t('Field name'),
'type' => $this->t('Type (text, integer, ....)'),
'widget_type' => $this->t('An instance-specific widget type'),
'global_settings' => $this->t('Global settings. Shared with every field instance.'),
'required' => $this->t('Required'),
'multiple' => $this->t('Multiple'),
@ -69,12 +67,32 @@ class Field extends DrupalSqlBase {
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
// The instance widget_type helps determine what D8 field type we'll use.
// Identify the distinct widget_types being used in D6.
$widget_types = $this->select('content_node_field_instance', 'cnfi')
->fields('cnfi', ['widget_type'])
->condition('field_name', $row->getSourceProperty('field_name'))
->distinct()
->orderBy('widget_type')
->execute()
->fetchCol();
// Arbitrarily use the first widget_type - if there are multiples, let the
// migrator know.
$row->setSourceProperty('widget_type', $widget_types[0]);
if (count($widget_types) > 1) {
$this->migration->getIdMap()->saveMessage(
['field_name' => $row->getSourceProperty('field_name')],
$this->t('Widget types @types are used in Drupal 6 field instances: widget type @selected_type applied to the Drupal 8 base field', [
'@types' => implode(', ', $widget_types),
'@selected_type' => $widget_types[0],
])
);
}
// Unserialize data.
$global_settings = unserialize($row->getSourceProperty('global_settings'));
$widget_settings = unserialize($row->getSourceProperty('widget_settings'));
$db_columns = unserialize($row->getSourceProperty('db_columns'));
$row->setSourceProperty('global_settings', $global_settings);
$row->setSourceProperty('widget_settings', $widget_settings);
$row->setSourceProperty('db_columns', $db_columns);
return parent::prepareRow($row);
}

View file

@ -13,7 +13,8 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
* The field instance per form display source class.
*
* @MigrateSource(
* id = "d6_field_instance_per_form_display"
* id = "d6_field_instance_per_form_display",
* source_provider = "content"
* )
*/
class FieldInstancePerFormDisplay extends DrupalSqlBase {

View file

@ -24,6 +24,7 @@ class Field extends DrupalSqlBase {
*/
public function query() {
$query = $this->select('field_config', 'fc')
->distinct()
->fields('fc')
->fields('fci', array('entity_type'))
->condition('fc.active', 1)

View file

@ -28,7 +28,9 @@ class FieldInstance extends DrupalSqlBase {
->condition('fci.deleted', 0)
->condition('fc.active', 1)
->condition('fc.deleted', 0)
->condition('fc.storage_active', 1);
->condition('fc.storage_active', 1)
->fields('fc', array('type'));
$query->innerJoin('field_config', 'fc', 'fci.field_id = fc.id');
// Optionally filter by entity type and bundle.

View file

@ -0,0 +1,471 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceAdminTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Entity\Entity;
use Drupal\field_ui\Tests\FieldUiTestTrait;
use Drupal\node\Entity\Node;
use Drupal\simpletest\WebTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests for the administrative UI.
*
* @group entity_reference
*/
class EntityReferenceAdminTest extends WebTestBase {
use FieldUiTestTrait;
/**
* Modules to install.
*
* Enable path module to ensure that the selection handler does not fail for
* entities with a path field.
* Enable views_ui module to see the no_view_help text.
*
* @var array
*/
public static $modules = ['node', 'field_ui', 'path', 'taxonomy', 'block', 'views_ui'];
/**
* The name of the content type created for testing purposes.
*
* @var string
*/
protected $type;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_breadcrumb_block');
// Create a content type, with underscores.
$type_name = strtolower($this->randomMachineName(8)) . '_test';
$type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
$this->type = $type->id();
// Create test user.
$admin_user = $this->drupalCreateUser(array(
'access content',
'administer node fields',
'administer node display',
'administer views',
'create ' . $type_name . ' content',
'edit own ' . $type_name . ' content',
));
$this->drupalLogin($admin_user);
}
/**
* Tests the Entity Reference Admin UI.
*/
public function testFieldAdminHandler() {
$bundle_path = 'admin/structure/types/manage/' . $this->type;
// First step: 'Add new field' on the 'Manage fields' page.
$this->drupalGet($bundle_path . '/fields/add-field');
// Check if the commonly referenced entity types appear in the list.
$this->assertOption('edit-new-storage-type', 'field_ui:entity_reference:node');
$this->assertOption('edit-new-storage-type', 'field_ui:entity_reference:user');
$this->drupalPostForm(NULL, array(
'label' => 'Test label',
'field_name' => 'test',
'new_storage_type' => 'entity_reference',
), t('Save and continue'));
// Node should be selected by default.
$this->assertFieldByName('settings[target_type]', 'node');
// Check that all entity types can be referenced.
$this->assertFieldSelectOptions('settings[target_type]', array_keys(\Drupal::entityManager()->getDefinitions()));
// Second step: 'Field settings' form.
$this->drupalPostForm(NULL, array(), t('Save field settings'));
// The base handler should be selected by default.
$this->assertFieldByName('settings[handler]', 'default:node');
// The base handler settings should be displayed.
$entity_type_id = 'node';
$bundles = entity_get_bundles($entity_type_id);
foreach ($bundles as $bundle_name => $bundle_info) {
$this->assertFieldByName('settings[handler_settings][target_bundles][' . $bundle_name . ']');
}
reset($bundles);
// Test the sort settings.
// Option 0: no sort.
$this->assertFieldByName('settings[handler_settings][sort][field]', '_none');
$this->assertNoFieldByName('settings[handler_settings][sort][direction]');
// Option 1: sort by field.
$this->drupalPostAjaxForm(NULL, array('settings[handler_settings][sort][field]' => 'nid'), 'settings[handler_settings][sort][field]');
$this->assertFieldByName('settings[handler_settings][sort][direction]', 'ASC');
// Test that a non-translatable base field is a sort option.
$this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='nid']");
// Test that a translatable base field is a sort option.
$this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='title']");
// Test that a configurable field is a sort option.
$this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='body.value']");
// Set back to no sort.
$this->drupalPostAjaxForm(NULL, array('settings[handler_settings][sort][field]' => '_none'), 'settings[handler_settings][sort][field]');
$this->assertNoFieldByName('settings[handler_settings][sort][direction]');
// Third step: confirm.
$this->drupalPostForm(NULL, array(
'required' => '1',
'settings[handler_settings][target_bundles][' . key($bundles) . ']' => key($bundles),
), t('Save settings'));
// Check that the field appears in the overview form.
$this->assertFieldByXPath('//table[@id="field-overview"]//tr[@id="field-test"]/td[1]', 'Test label', 'Field was created and appears in the overview page.');
// Check that the field settings form can be submitted again, even when the
// field is required.
// The first 'Edit' link is for the Body field.
$this->clickLink(t('Edit'), 1);
$this->drupalPostForm(NULL, array(), t('Save settings'));
// Switch the target type to 'taxonomy_term' and check that the settings
// specific to its selection handler are displayed.
$field_name = 'node.' . $this->type . '.field_test';
$edit = array(
'settings[target_type]' => 'taxonomy_term',
);
$this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_name);
$this->assertFieldByName('settings[handler_settings][auto_create]');
// Switch the target type to 'user' and check that the settings specific to
// its selection handler are displayed.
$field_name = 'node.' . $this->type . '.field_test';
$edit = array(
'settings[target_type]' => 'user',
);
$this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_name);
$this->assertFieldByName('settings[handler_settings][filter][type]', '_none');
// Switch the target type to 'node'.
$field_name = 'node.' . $this->type . '.field_test';
$edit = array(
'settings[target_type]' => 'node',
);
$this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings'));
// Try to select the views handler.
$edit = array(
'settings[handler]' => 'views',
);
$this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]');
$this->assertRaw(t('No eligible views were found. <a href=":create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href=":existing">existing view</a>.', array(
':create' => \Drupal::url('views_ui.add'),
':existing' => \Drupal::url('entity.view.collection'),
)));
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// If no eligible view is available we should see a message.
$this->assertText('The views entity selection mode requires a view.');
// Enable the entity_reference_test module which creates an eligible view.
$this->container->get('module_installer')->install(array('entity_reference_test'));
$this->resetAll();
$this->drupalGet($bundle_path . '/fields/' . $field_name);
$this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]');
$edit = array(
'settings[handler_settings][view][view_and_display]' => 'test_entity_reference:entity_reference_1',
);
$this->drupalPostForm(NULL, $edit, t('Save settings'));
$this->assertResponse(200);
// Switch the target type to 'entity_test'.
$edit = array(
'settings[target_type]' => 'entity_test',
);
$this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_name);
$edit = array(
'settings[handler]' => 'views',
);
$this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]');
$edit = array(
'required' => FALSE,
'settings[handler_settings][view][view_and_display]' => 'test_entity_reference_entity_test:entity_reference_1',
);
$this->drupalPostForm(NULL, $edit, t('Save settings'));
$this->assertResponse(200);
// Create a new view and display it as a entity reference.
$edit = array(
'id' => 'node_test_view',
'label' => 'Node Test View',
'show[wizard_key]' => 'node',
'page[create]' => 1,
'page[title]' => 'Test Node View',
'page[path]' => 'test/node/view',
'page[style][style_plugin]' => 'default',
'page[style][row_plugin]' => 'fields',
);
$this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit'));
$this->drupalPostForm(NULL, array(), t('Duplicate as Entity Reference'));
$this->clickLink(t('Settings'));
$edit = array(
'style_options[search_fields][title]' => 'title',
);
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/node_test_view/edit/entity_reference_1', array(), t('Save'));
$this->clickLink(t('Settings'));
// Create a test entity reference field.
$field_name = 'test_entity_ref_field';
$edit = array(
'new_storage_type' => 'field_ui:entity_reference:node',
'label' => 'Test Entity Reference Field',
'field_name' => $field_name,
);
$this->drupalPostForm($bundle_path . '/fields/add-field', $edit, t('Save and continue'));
$this->drupalPostForm(NULL, array(), t('Save field settings'));
// Add the view to the test field.
$edit = array(
'settings[handler]' => 'views',
);
$this->drupalPostAjaxForm(NULL, $edit, 'settings[handler]');
$edit = array(
'required' => FALSE,
'settings[handler_settings][view][view_and_display]' => 'node_test_view:entity_reference_1',
);
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// Create nodes.
$node1 = Node::create([
'type' => $this->type,
'title' => 'Foo Node',
]);
$node1->save();
$node2 = Node::create([
'type' => $this->type,
'title' => 'Foo Node',
]);
$node2->save();
// Try to add a new node and fill the entity reference field.
$this->drupalGet('node/add/' . $this->type);
$result = $this->xpath('//input[@name="field_test_entity_ref_field[0][target_id]" and contains(@data-autocomplete-path, "/entity_reference_autocomplete/node/views/")]');
$target_url = $this->getAbsoluteUrl($result[0]['data-autocomplete-path']);
$this->drupalGet($target_url, array('query' => array('q' => 'Foo')));
$this->assertRaw($node1->getTitle() . ' (' . $node1->id() . ')');
$this->assertRaw($node2->getTitle() . ' (' . $node2->id() . ')');
$edit = array(
'title[0][value]' => 'Example',
'field_test_entity_ref_field[0][target_id]' => 'Test'
);
$this->drupalPostForm('node/add/' . $this->type, $edit, t('Save'));
// Assert that entity reference autocomplete field is validated.
$this->assertText(t('There are no entities matching "@entity"', ['@entity' => 'Test']));
$edit = array(
'title[0][value]' => 'Test',
'field_test_entity_ref_field[0][target_id]' => $node1->getTitle()
);
$this->drupalPostForm('node/add/' . $this->type, $edit, t('Save'));
// Assert the results multiple times to avoid sorting problem of nodes with
// the same title.
$this->assertText(t('Multiple entities match this reference;'));
$this->assertText(t("@node1", ['@node1' => $node1->getTitle() . ' (' . $node1->id() . ')']));
$this->assertText(t("@node2", ['@node2' => $node2->getTitle() . ' (' . $node2->id() . ')']));
$edit = array(
'title[0][value]' => 'Test',
'field_test_entity_ref_field[0][target_id]' => $node1->getTitle() . '(' . $node1->id() . ')'
);
$this->drupalPostForm('node/add/' . $this->type, $edit, t('Save'));
$this->assertLink($node1->getTitle());
// Tests adding default values to autocomplete widgets.
Vocabulary::create(array('vid' => 'tags', 'name' => 'tags'))->save();
$taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', 'tags');
$field_path = 'node.' . $this->type . '.field_' . $taxonomy_term_field_name;
$this->drupalGet($bundle_path . '/fields/' . $field_path . '/storage');
$edit = [
'cardinality' => -1,
];
$this->drupalPostForm(NULL, $edit, t('Save field settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_path);
$term_name = $this->randomString();
$edit = [
// This must be set before new entities will be auto-created.
'settings[handler_settings][auto_create]' => 1,
];
$this->drupalPostForm(NULL, $edit, t('Save settings'));
$this->drupalGet($bundle_path . '/fields/' . $field_path);
$edit = [
// A term that doesn't yet exist.
'default_value_input[field_' . $taxonomy_term_field_name . '][0][target_id]' => $term_name,
];
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// The term should now exist.
$term = taxonomy_term_load_multiple_by_name($term_name, 'tags')[1];
$this->assertIdentical(1, count($term), 'Taxonomy term was auto created when set as field default.');
}
/**
* Tests the formatters for the Entity References.
*/
public function testAvailableFormatters() {
// Create a new vocabulary.
Vocabulary::create(array('vid' => 'tags', 'name' => 'tags'))->save();
// Create entity reference field with taxonomy term as a target.
$taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', 'tags');
// Create entity reference field with user as a target.
$user_field_name = $this->createEntityReferenceField('user');
// Create entity reference field with node as a target.
$node_field_name = $this->createEntityReferenceField('node', $this->type);
// Create entity reference field with date format as a target.
$date_format_field_name = $this->createEntityReferenceField('date_format');
// Display all newly created Entity Reference configuration.
$this->drupalGet('admin/structure/types/manage/' . $this->type . '/display');
// Check for Taxonomy Term select box values.
// Test if Taxonomy Term Entity Reference Field has the correct formatters.
$this->assertFieldSelectOptions('fields[field_' . $taxonomy_term_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'entity_reference_rss_category',
'entity_reference_entity_view',
'hidden',
));
// Test if User Reference Field has the correct formatters.
// Author should be available for this field.
// RSS Category should not be available for this field.
$this->assertFieldSelectOptions('fields[field_' . $user_field_name . '][type]', array(
'author',
'entity_reference_entity_id',
'entity_reference_entity_view',
'entity_reference_label',
'hidden',
));
// Test if Node Entity Reference Field has the correct formatters.
// RSS Category should not be available for this field.
$this->assertFieldSelectOptions('fields[field_' . $node_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'entity_reference_entity_view',
'hidden',
));
// Test if Date Format Reference Field has the correct formatters.
// RSS Category & Entity View should not be available for this field.
// This could be any field without a ViewBuilder.
$this->assertFieldSelectOptions('fields[field_' . $date_format_field_name . '][type]', array(
'entity_reference_label',
'entity_reference_entity_id',
'hidden',
));
}
/**
* Creates a new Entity Reference fields with a given target type.
*
* @param $target_type
* The name of the target type
* @param $bundle
* Name of the bundle
* Default = NULL
* @return string
* Returns the generated field name
*/
public function createEntityReferenceField($target_type, $bundle = NULL) {
// Generates a bundle path for the newly created content type.
$bundle_path = 'admin/structure/types/manage/' . $this->type;
// Generate a random field name, must be only lowercase characters.
$field_name = strtolower($this->randomMachineName());
$storage_edit = $field_edit = array();
$storage_edit['settings[target_type]'] = $target_type;
if ($bundle) {
$field_edit['settings[handler_settings][target_bundles][' . $bundle . ']'] = TRUE;
}
$this->fieldUIAddNewField($bundle_path, $field_name, NULL, 'entity_reference', $storage_edit, $field_edit);
// Returns the generated field name.
return $field_name;
}
/**
* Checks if a select element contains the specified options.
*
* @param string $name
* The field name.
* @param array $expected_options
* An array of expected options.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertFieldSelectOptions($name, array $expected_options) {
$xpath = $this->buildXPathQuery('//select[@name=:name]', array(':name' => $name));
$fields = $this->xpath($xpath);
if ($fields) {
$field = $fields[0];
$options = $this->getAllOptionsList($field);
sort($options);
sort($expected_options);
return $this->assertIdentical($options, $expected_options);
}
else {
return $this->fail('Unable to find field ' . $name);
}
}
/**
* Extracts all options from a select element.
*
* @param \SimpleXMLElement $element
* The select element field information.
*
* @return array
* An array of option values as strings.
*/
protected function getAllOptionsList(\SimpleXMLElement $element) {
$options = array();
// Add all options items.
foreach ($element->option as $option) {
$options[] = (string) $option['value'];
}
// Loops trough all the option groups
foreach ($element->optgroup as $optgroup) {
$options = array_merge($this->getAllOptionsList($optgroup), $options);
}
return $options;
}
}

View file

@ -0,0 +1,137 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceAutoCreateTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\simpletest\WebTestBase;
use Drupal\node\Entity\Node;
/**
* Tests creating new entity (e.g. taxonomy-term) from an autocomplete widget.
*
* @group entity_reference
*/
class EntityReferenceAutoCreateTest extends WebTestBase {
public static $modules = ['node'];
/**
* The name of a content type that will reference $referencedType.
*
* @var string
*/
protected $referencingType;
/**
* The name of a content type that will be referenced by $referencingType.
*
* @var string
*/
protected $referencedType;
protected function setUp() {
parent::setUp();
// Create "referencing" and "referenced" node types.
$referencing = $this->drupalCreateContentType();
$this->referencingType = $referencing->id();
$referenced = $this->drupalCreateContentType();
$this->referencedType = $referenced->id();
entity_create('field_storage_config', array(
'field_name' => 'test_field',
'entity_type' => 'node',
'translatable' => FALSE,
'entity_types' => array(),
'settings' => array(
'target_type' => 'node',
),
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
))->save();
entity_create('field_config', array(
'label' => 'Entity reference field',
'field_name' => 'test_field',
'entity_type' => 'node',
'bundle' => $referencing->id(),
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
// Reference a single vocabulary.
'target_bundles' => array(
$referenced->id(),
),
// Enable auto-create.
'auto_create' => TRUE,
),
),
))->save();
entity_get_display('node', $referencing->id(), 'default')
->setComponent('test_field')
->save();
entity_get_form_display('node', $referencing->id(), 'default')
->setComponent('test_field', array(
'type' => 'entity_reference_autocomplete',
))
->save();
}
/**
* Tests that the autocomplete input element appears and the creation of a new
* entity.
*/
public function testAutoCreate() {
$user1 = $this->drupalCreateUser(array('access content', "create $this->referencingType content"));
$this->drupalLogin($user1);
$this->drupalGet('node/add/' . $this->referencingType);
$this->assertFieldByXPath('//input[@id="edit-test-field-0-target-id" and contains(@class, "form-autocomplete")]', NULL, 'The autocomplete input element appears.');
$new_title = $this->randomMachineName();
// Assert referenced node does not exist.
$base_query = \Drupal::entityQuery('node');
$base_query
->condition('type', $this->referencedType)
->condition('title', $new_title);
$query = clone $base_query;
$result = $query->execute();
$this->assertFalse($result, 'Referenced node does not exist yet.');
$edit = array(
'title[0][value]' => $this->randomMachineName(),
'test_field[0][target_id]' => $new_title,
);
$this->drupalPostForm("node/add/$this->referencingType", $edit, 'Save');
// Assert referenced node was created.
$query = clone $base_query;
$result = $query->execute();
$this->assertTrue($result, 'Referenced node was created.');
$referenced_nid = key($result);
$referenced_node = Node::load($referenced_nid);
// Assert the referenced node is associated with referencing node.
$result = \Drupal::entityQuery('node')
->condition('type', $this->referencingType)
->execute();
$referencing_nid = key($result);
$referencing_node = Node::load($referencing_nid);
$this->assertEqual($referenced_nid, $referencing_node->test_field->target_id, 'Newly created node is referenced from the referencing node.');
// Now try to view the node and check that the referenced node is shown.
$this->drupalGet('node/' . $referencing_node->id());
$this->assertText($referencing_node->label(), 'Referencing node label found.');
$this->assertText($referenced_node->label(), 'Referenced node label found.');
}
}

View file

@ -0,0 +1,161 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceFieldDefaultValueTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Component\Utility\Unicode;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
/**
* Tests entity reference field default values storage in CMI.
*
* @group entity_reference
*/
class EntityReferenceFieldDefaultValueTest extends WebTestBase {
use SchemaCheckTestTrait;
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['field_ui', 'node'];
/**
* A user with permission to administer content types, node fields, etc.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
protected function setUp() {
parent::setUp();
// Create default content type.
$this->drupalCreateContentType(array('type' => 'reference_content'));
$this->drupalCreateContentType(array('type' => 'referenced_content'));
// Create admin user.
$this->adminUser = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'bypass node access'));
$this->drupalLogin($this->adminUser);
}
/**
* 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'));
$field_name = Unicode::strtolower($this->randomMachineName());
$field_storage = entity_create('field_storage_config', array(
'field_name' => $field_name,
'entity_type' => 'node',
'type' => 'entity_reference',
'settings' => array('target_type' => 'node'),
));
$field_storage->save();
$field = entity_create('field_config', array(
'field_storage' => $field_storage,
'bundle' => 'reference_content',
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
'target_bundles' => array('referenced_content'),
'sort' => array('field' => '_none'),
),
),
));
$field->save();
// Set created node as default_value.
$field_edit = array(
'default_value_input[' . $field_name . '][0][target_id]' => $referenced_node->getTitle() . ' (' .$referenced_node->id() . ')',
);
$this->drupalPostForm('admin/structure/types/manage/reference_content/fields/node.reference_content.' . $field_name, $field_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.' . $field_name);
$this->assertRaw('name="default_value_input[' . $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->config('field.field.node.reference_content.' . $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');
// Ensure the configuration has the expected dependency on the entity that
// is being used a default value.
$this->assertEqual(array($referenced_node->getConfigDependencyName()), $config_entity['dependencies']['content']);
// Clear field definitions cache in order to avoid stale cache values.
\Drupal::entityManager()->clearCachedFieldDefinitions();
// 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($field_name)->offsetGet(0)->target_id, $referenced_node->id());
// Ensure that the entity reference config schemas are correct.
$field_config = $this->config('field.field.node.reference_content.' . $field_name);
$this->assertConfigSchema(\Drupal::service('config.typed'), $field_config->getName(), $field_config->get());
$field_storage_config = $this->config('field.storage.node.' . $field_name);
$this->assertConfigSchema(\Drupal::service('config.typed'), $field_storage_config->getName(), $field_storage_config->get());
}
/**
* Tests that dependencies due to default values can be removed.
*
* @see \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::onDependencyRemoval()
*/
function testEntityReferenceDefaultConfigValue() {
// Create a node to be referenced.
$referenced_node_type = $this->drupalCreateContentType(array('type' => 'referenced_config_to_delete'));
$referenced_node_type2 = $this->drupalCreateContentType(array('type' => 'referenced_config_to_preserve'));
$field_name = Unicode::strtolower($this->randomMachineName());
$field_storage = entity_create('field_storage_config', array(
'field_name' => $field_name,
'entity_type' => 'node',
'type' => 'entity_reference',
'settings' => array('target_type' => 'node_type'),
'cardinality' => FieldStorageConfig::CARDINALITY_UNLIMITED,
));
$field_storage->save();
$field = entity_create('field_config', array(
'field_storage' => $field_storage,
'bundle' => 'reference_content',
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
'sort' => array('field' => '_none'),
),
),
));
$field->save();
// Set created node as default_value.
$field_edit = array(
'default_value_input[' . $field_name . '][0][target_id]' => $referenced_node_type->label() . ' (' .$referenced_node_type->id() . ')',
'default_value_input[' . $field_name . '][1][target_id]' => $referenced_node_type2->label() . ' (' .$referenced_node_type2->id() . ')',
);
$this->drupalPostForm('admin/structure/types/manage/reference_content/fields/node.reference_content.' . $field_name, $field_edit, t('Save settings'));
// Check that the field has a dependency on the default value.
$config_entity = $this->config('field.field.node.reference_content.' . $field_name)->get();
$this->assertTrue(in_array($referenced_node_type->getConfigDependencyName(), $config_entity['dependencies']['config'], TRUE), 'The node type referenced_config_to_delete is a dependency of the field.');
$this->assertTrue(in_array($referenced_node_type2->getConfigDependencyName(), $config_entity['dependencies']['config'], TRUE), 'The node type referenced_config_to_preserve is a dependency of the field.');
// Check that the field does not have a dependency on the default value
// after deleting the node type.
$referenced_node_type->delete();
$config_entity = $this->config('field.field.node.reference_content.' . $field_name)->get();
$this->assertFalse(in_array($referenced_node_type->getConfigDependencyName(), $config_entity['dependencies']['config'], TRUE), 'The node type referenced_config_to_delete not a dependency of the field.');
$this->assertTrue(in_array($referenced_node_type2->getConfigDependencyName(), $config_entity['dependencies']['config'], TRUE), 'The node type referenced_config_to_preserve is a dependency of the field.');
}
}

View file

@ -0,0 +1,308 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceFieldTranslatedReferenceViewTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\simpletest\WebTestBase;
/**
* Tests the translation of entity reference field display on nodes.
*
* @group entity_reference
*/
class EntityReferenceFieldTranslatedReferenceViewTest extends WebTestBase {
/**
* Flag indicating whether the field is translatable.
*
* @var bool
*/
protected $translatable = TRUE;
/**
* The langcode of the source language.
*
* @var string
*/
protected $baseLangcode = 'en';
/**
* Target langcode for translation.
*
* @var string
*/
protected $translateToLangcode = 'hu';
/**
* The test entity type name.
*
* @var string
*/
protected $testEntityTypeName = 'node';
/**
* Entity type which have the entity reference field.
*
* @var \Drupal\node\Entity\NodeType
*/
protected $referrerType;
/**
* Entity type which can be referenced.
*
* @var \Drupal\node\Entity\NodeType
*/
protected $referencedType;
/**
* The referrer entity.
*
* @var \Drupal\node\Entity\Node
*/
protected $referrerEntity;
/**
* The entity to refer.
*
* @var \Drupal\node\Entity\Node
*/
protected $referencedEntityWithoutTranslation;
/**
* The entity to refer.
*
* @var \Drupal\node\Entity\Node
*/
protected $referencedEntityWithTranslation;
/**
* The machine name of the entity reference field.
*
* @var string
*/
protected $referenceFieldName = 'test_reference_field';
/**
* The label of the untranslated referenced entity, used in assertions.
*
* @var string
*/
protected $labelOfNotTranslatedReference;
/**
* The original label of the referenced entity, used in assertions.
*
* @var string
*/
protected $originalLabel;
/**
* The translated label of the referenced entity, used in assertions.
*
* @var string
*/
protected $translatedLabel;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'language',
'content_translation',
'node',
);
protected function setUp() {
parent::setUp();
$this->labelOfNotTranslatedReference = $this->randomMachineName();
$this->originalLabel = $this->randomMachineName();
$this->translatedLabel = $this->randomMachineName();
$this->setUpLanguages();
// We setup languages, so we need to ensure that the language manager
// and language path processor is updated.
$this->rebuildContainer();
$this->setUpContentTypes();
$this->enableTranslation();
$this->setUpEntityReferenceField();
$this->createContent();
}
/**
* Tests if the translated entity is displayed in an entity reference field.
*/
public function testTranslatedEntityReferenceDisplay() {
$url = $this->referrerEntity->urlInfo();
$translation_url = $this->referrerEntity->urlInfo('canonical', ['language' => ConfigurableLanguage::load($this->translateToLangcode)]);
$this->drupalGet($url);
$this->assertText($this->labelOfNotTranslatedReference, 'The label of not translated reference is displayed.');
$this->assertText($this->originalLabel, 'The default label of translated reference is displayed.');
$this->assertNoText($this->translatedLabel, 'The translated label of translated reference is not displayed.');
$this->drupalGet($translation_url);
$this->assertText($this->labelOfNotTranslatedReference, 'The label of not translated reference is displayed.');
$this->assertNoText($this->originalLabel, 'The default label of translated reference is not displayed.');
$this->assertText($this->translatedLabel, 'The translated label of translated reference is displayed.');
}
/**
* Adds additional languages.
*/
protected function setUpLanguages() {
ConfigurableLanguage::createFromLangcode($this->translateToLangcode)->save();
}
/**
* Creates a test subject contents, with translation.
*/
protected function createContent() {
$this->referencedEntityWithTranslation = $this->createReferencedEntityWithTranslation();
$this->referencedEntityWithoutTranslation = $this->createNotTranslatedReferencedEntity();
$this->referrerEntity = $this->createReferrerEntity();
}
/**
* Enables translations where it needed.
*/
protected function enableTranslation() {
// Enable translation for the entity types and ensure the change is picked
// up.
\Drupal::service('content_translation.manager')->setEnabled($this->testEntityTypeName, $this->referrerType->id(), TRUE);
\Drupal::service('content_translation.manager')->setEnabled($this->testEntityTypeName, $this->referencedType->id(), TRUE);
drupal_static_reset();
\Drupal::entityManager()->clearCachedDefinitions();
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
}
/**
* Adds term reference field for the article content type.
*/
protected function setUpEntityReferenceField() {
entity_create('field_storage_config', array(
'field_name' => $this->referenceFieldName,
'entity_type' => $this->testEntityTypeName,
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
'translatable' => $this->translatable,
'settings' => array(
'allowed_values' => array(
array(
'target_type' => $this->testEntityTypeName,
),
),
),
))->save();
entity_create('field_config', array(
'field_name' => $this->referenceFieldName,
'bundle' => $this->referrerType->id(),
'entity_type' => $this->testEntityTypeName,
))
->save();
entity_get_form_display($this->testEntityTypeName, $this->referrerType->id(), 'default')
->setComponent($this->referenceFieldName, array(
'type' => 'entity_reference_autocomplete',
))
->save();
entity_get_display($this->testEntityTypeName, $this->referrerType->id(), 'default')
->setComponent($this->referenceFieldName, array(
'type' => 'entity_reference_label',
))
->save();
}
/**
* Create content types.
*/
protected function setUpContentTypes() {
$this->referrerType = $this->drupalCreateContentType(array(
'type' => 'referrer',
'name' => 'Referrer',
));
$this->referencedType = $this->drupalCreateContentType(array(
'type' => 'referenced_page',
'name' => 'Referenced Page',
));
}
/**
* Create a referenced entity with a translation.
*/
protected function createReferencedEntityWithTranslation() {
/** @var \Drupal\node\Entity\Node $node */
$node = entity_create($this->testEntityTypeName, array(
'title' => $this->originalLabel,
'type' => $this->referencedType->id(),
'description' => array(
'value' => $this->randomMachineName(),
'format' => 'basic_html',
),
'langcode' => $this->baseLangcode,
));
$node->save();
$node->addTranslation($this->translateToLangcode, array(
'title' => $this->translatedLabel,
));
$node->save();
return $node;
}
/**
* Create the referenced entity.
*/
protected function createNotTranslatedReferencedEntity() {
/** @var \Drupal\node\Entity\Node $node */
$node = entity_create($this->testEntityTypeName, array(
'title' => $this->labelOfNotTranslatedReference,
'type' => $this->referencedType->id(),
'description' => array(
'value' => $this->randomMachineName(),
'format' => 'basic_html',
),
'langcode' => $this->baseLangcode,
));
$node->save();
return $node;
}
/**
* Create the referrer entity.
*/
protected function createReferrerEntity() {
/** @var \Drupal\node\Entity\Node $node */
$node = entity_create($this->testEntityTypeName, array(
'title' => $this->randomMachineName(),
'type' => $this->referrerType->id(),
'description' => array(
'value' => $this->randomMachineName(),
'format' => 'basic_html',
),
$this->referenceFieldName => array(
array('target_id' => $this->referencedEntityWithTranslation->id()),
array('target_id' => $this->referencedEntityWithoutTranslation->id()),
),
'langcode' => $this->baseLangcode,
));
$node->save();
$node->addTranslation($this->translateToLangcode, $node->toArray());
$node->save();
return $node;
}
}

View file

@ -0,0 +1,131 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceFileUploadTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\simpletest\WebTestBase;
/**
* Tests an autocomplete widget with file upload.
*
* @group entity_reference
*/
class EntityReferenceFileUploadTest extends WebTestBase {
public static $modules = array('entity_reference', 'node', 'file');
/**
* The name of a content type that will reference $referencedType.
*
* @var string
*/
protected $referencingType;
/**
* The name of a content type that will be referenced by $referencingType.
*
* @var string
*/
protected $referencedType;
/**
* Node id.
*
* @var integer
*/
protected $nodeId;
protected function setUp() {
parent::setUp();
// Create "referencing" and "referenced" node types.
$referencing = $this->drupalCreateContentType();
$this->referencingType = $referencing->id();
$referenced = $this->drupalCreateContentType();
$this->referencedType = $referenced->id();
$this->nodeId = $this->drupalCreateNode(array('type' => $referenced->id()))->id();
entity_create('field_storage_config', array(
'field_name' => 'test_field',
'entity_type' => 'node',
'translatable' => FALSE,
'entity_types' => array(),
'settings' => array(
'target_type' => 'node',
),
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
))->save();
entity_create('field_config', array(
'label' => 'Entity reference field',
'field_name' => 'test_field',
'entity_type' => 'node',
'required' => TRUE,
'bundle' => $referencing->id(),
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
// Reference a single vocabulary.
'target_bundles' => array(
$referenced->id(),
),
),
),
))->save();
// Create a file field.
$file_field_name = 'file_field';
$field_storage = entity_create('field_storage_config', array(
'field_name' => $file_field_name,
'entity_type' => 'node',
'type' => 'file'
));
$field_storage->save();
entity_create('field_config', array(
'entity_type' => 'node',
'field_storage' => $field_storage,
'bundle' => $referencing->id(),
'label' => $this->randomMachineName() . '_label',
))->save();
entity_get_display('node', $referencing->id(), 'default')
->setComponent('test_field')
->setComponent($file_field_name)
->save();
entity_get_form_display('node', $referencing->id(), 'default')
->setComponent('test_field', array(
'type' => 'entity_reference_autocomplete',
))
->setComponent($file_field_name, array(
'type' => 'file_generic',
))
->save();
}
/**
* Tests that the autocomplete input element does not cause ajax fatal.
*/
public function testFileUpload() {
$user1 = $this->drupalCreateUser(array('access content', "create $this->referencingType content"));
$this->drupalLogin($user1);
$test_file = current($this->drupalGetTestFiles('text'));
$edit['files[file_field_0]'] = drupal_realpath($test_file->uri);
$this->drupalPostForm('node/add/' . $this->referencingType, $edit, 'Upload');
$this->assertResponse(200);
$edit = array(
'title[0][value]' => $this->randomMachineName(),
'test_field[0][target_id]' => $this->nodeId,
);
$this->drupalPostForm(NULL, $edit, 'Save');
$this->assertResponse(200);
}
}

View file

@ -10,7 +10,6 @@ namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\filter\Entity\FilterFormat;
use Drupal\system\Tests\Entity\EntityUnitTestBase;
@ -62,13 +61,6 @@ class EntityReferenceFormatterTest extends EntityUnitTestBase {
*/
protected $unsavedReferencedEntity;
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('entity_reference');
protected function setUp() {
parent::setUp();

View file

@ -0,0 +1,223 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceIntegrationTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\config\Tests\AssertConfigEntityImportTrait;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\field\Entity\FieldConfig;
use Drupal\simpletest\WebTestBase;
/**
* Tests various Entity reference UI components.
*
* @group entity_reference
*/
class EntityReferenceIntegrationTest extends WebTestBase {
use AssertConfigEntityImportTrait;
use EntityReferenceTestTrait;
/**
* The entity type used in this test.
*
* @var string
*/
protected $entityType = 'entity_test';
/**
* The bundle used in this test.
*
* @var string
*/
protected $bundle = 'entity_test';
/**
* The name of the field used in this test.
*
* @var string
*/
protected $fieldName;
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['config_test', 'entity_test', 'field_ui'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create a test user.
$web_user = $this->drupalCreateUser(array('administer entity_test content', 'administer entity_test fields', 'view test entity'));
$this->drupalLogin($web_user);
}
/**
* Tests the entity reference field with all its supported field widgets.
*/
public function testSupportedEntityTypesAndWidgets() {
foreach ($this->getTestEntities() as $key => $referenced_entities) {
$this->fieldName = 'field_test_' . $referenced_entities[0]->getEntityTypeId();
// Create an Entity reference field.
$this->createEntityReferenceField($this->entityType, $this->bundle, $this->fieldName, $this->fieldName, $referenced_entities[0]->getEntityTypeId(), 'default', array(), 2);
// Test the default 'entity_reference_autocomplete' widget.
entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName)->save();
$entity_name = $this->randomMachineName();
$edit = array(
'name[0][value]' => $entity_name,
$this->fieldName . '[0][target_id]' => $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')',
// Test an input of the entity label without a ' (entity_id)' suffix.
$this->fieldName . '[1][target_id]' => $referenced_entities[1]->label(),
);
$this->drupalPostForm($this->entityType . '/add', $edit, t('Save'));
$this->assertFieldValues($entity_name, $referenced_entities);
// Try to post the form again with no modification and check if the field
// values remain the same.
$entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name)));
$this->drupalGet($this->entityType . '/manage/' . $entity->id());
$this->assertFieldByName($this->fieldName . '[0][target_id]', $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')');
$this->assertFieldByName($this->fieldName . '[1][target_id]', $referenced_entities[1]->label() . ' (' . $referenced_entities[1]->id() . ')');
$this->drupalPostForm(NULL, array(), t('Save'));
$this->assertFieldValues($entity_name, $referenced_entities);
// Test the 'entity_reference_autocomplete_tags' widget.
entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName, array(
'type' => 'entity_reference_autocomplete_tags',
))->save();
$entity_name = $this->randomMachineName();
$target_id = $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')';
// Test an input of the entity label without a ' (entity_id)' suffix.
$target_id .= ', ' . $referenced_entities[1]->label();
$edit = array(
'name[0][value]' => $entity_name,
$this->fieldName . '[target_id]' => $target_id,
);
$this->drupalPostForm($this->entityType . '/add', $edit, t('Save'));
$this->assertFieldValues($entity_name, $referenced_entities);
// Try to post the form again with no modification and check if the field
// values remain the same.
$entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name)));
$this->drupalGet($this->entityType . '/manage/' . $entity->id());
$this->assertFieldByName($this->fieldName . '[target_id]', $target_id . ' (' . $referenced_entities[1]->id() . ')');
$this->drupalPostForm(NULL, array(), t('Save'));
$this->assertFieldValues($entity_name, $referenced_entities);
// Test all the other widgets supported by the entity reference field.
// Since we don't know the form structure for these widgets, just test
// that editing and saving an already created entity works.
$exclude = array('entity_reference_autocomplete', 'entity_reference_autocomplete_tags');
$entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name)));
$supported_widgets = \Drupal::service('plugin.manager.field.widget')->getOptions('entity_reference');
$supported_widget_types = array_diff(array_keys($supported_widgets), $exclude);
foreach ($supported_widget_types as $widget_type) {
entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName, array(
'type' => $widget_type,
))->save();
$this->drupalPostForm($this->entityType . '/manage/' . $entity->id(), array(), t('Save'));
$this->assertFieldValues($entity_name, $referenced_entities);
}
// Reset to the default 'entity_reference_autocomplete' widget.
entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName)->save();
// Set first entity as the default_value.
$field_edit = array(
'default_value_input[' . $this->fieldName . '][0][target_id]' => $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')',
);
if ($key == 'content') {
$field_edit['settings[handler_settings][target_bundles][' . $referenced_entities[0]->getEntityTypeId() . ']'] = TRUE;
}
$this->drupalPostForm($this->entityType . '/structure/' . $this->bundle .'/fields/' . $this->entityType . '.' . $this->bundle . '.' . $this->fieldName, $field_edit, t('Save settings'));
// Ensure the configuration has the expected dependency on the entity that
// is being used a default value.
$field = FieldConfig::loadByName($this->entityType, $this->bundle, $this->fieldName);
$this->assertTrue(in_array($referenced_entities[0]->getConfigDependencyName(), $field->getDependencies()[$key]), SafeMarkup::format('Expected @type dependency @name found', ['@type' => $key, '@name' => $referenced_entities[0]->getConfigDependencyName()]));
// Ensure that the field can be imported without change even after the
// default value deleted.
$referenced_entities[0]->delete();
// Reload the field since deleting the default value can change the field.
\Drupal::entityManager()->getStorage($field->getEntityTypeId())->resetCache([$field->id()]);
$field = FieldConfig::loadByName($this->entityType, $this->bundle, $this->fieldName);
$this->assertConfigEntityImport($field);
// Once the default value has been removed after saving the dependency
// should be removed.
$field = FieldConfig::loadByName($this->entityType, $this->bundle, $this->fieldName);
$field->save();
$dependencies = $field->getDependencies();
$this->assertFalse(isset($dependencies[$key]) && in_array($referenced_entities[0]->getConfigDependencyName(), $dependencies[$key]), SafeMarkup::format('@type dependency @name does not exist.', ['@type' => $key, '@name' => $referenced_entities[0]->getConfigDependencyName()]));
}
}
/**
* Asserts that the reference field values are correct.
*
* @param string $entity_name
* The name of the test entity.
* @param \Drupal\Core\Entity\EntityInterface[] $referenced_entities
* An array of referenced entities.
*/
protected function assertFieldValues($entity_name, $referenced_entities) {
$entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name)));
$this->assertTrue($entity, format_string('%entity_type: Entity found in the database.', array('%entity_type' => $this->entityType)));
$this->assertEqual($entity->{$this->fieldName}->target_id, $referenced_entities[0]->id());
$this->assertEqual($entity->{$this->fieldName}->entity->id(), $referenced_entities[0]->id());
$this->assertEqual($entity->{$this->fieldName}->entity->label(), $referenced_entities[0]->label());
$this->assertEqual($entity->{$this->fieldName}[1]->target_id, $referenced_entities[1]->id());
$this->assertEqual($entity->{$this->fieldName}[1]->entity->id(), $referenced_entities[1]->id());
$this->assertEqual($entity->{$this->fieldName}[1]->entity->label(), $referenced_entities[1]->label());
}
/**
* Creates two content and two config test entities.
*
* @return array
* An array of entity objects.
*/
protected function getTestEntities() {
$config_entity_1 = entity_create('config_test', array('id' => $this->randomMachineName(), 'label' => $this->randomMachineName()));
$config_entity_1->save();
$config_entity_2 = entity_create('config_test', array('id' => $this->randomMachineName(), 'label' => $this->randomMachineName()));
$config_entity_2->save();
$content_entity_1 = entity_create('entity_test', array('name' => $this->randomMachineName()));
$content_entity_1->save();
$content_entity_2 = entity_create('entity_test', array('name' => $this->randomMachineName()));
$content_entity_2->save();
return array(
'config' => array(
$config_entity_1,
$config_entity_2,
),
'content' => array(
$content_entity_1,
$content_entity_2,
),
);
}
}

View file

@ -10,9 +10,8 @@ namespace Drupal\field\Tests\EntityReference;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestStringId;
use Drupal\field\Entity\FieldConfig;
@ -36,7 +35,7 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
*
* @var array
*/
public static $modules = array('entity_reference', 'taxonomy', 'text', 'filter', 'views');
public static $modules = ['taxonomy', 'text', 'filter', 'views', 'field'];
/**
* The taxonomy vocabulary to test with.
@ -114,7 +113,7 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
$this->assertEqual($entity->field_test_taxonomy_term->entity->uuid(), $this->term->uuid());
// Verify that the label for the target ID property definition is correct.
$label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel();
$this->assertTrue($label instanceof TranslationWrapper);
$this->assertTrue($label instanceof TranslatableMarkup);
$this->assertEqual($label->render(), 'Taxonomy term ID');
// Change the name of the term via the reference.
@ -185,7 +184,7 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
$this->assertEqual($this->entityStringId->id(), $storage->load($entity->id())->field_test_entity_test_string_id->target_id);
// Verify that the label for the target ID property definition is correct.
$label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel();
$this->assertTrue($label instanceof TranslationWrapper);
$this->assertTrue($label instanceof TranslatableMarkup);
$this->assertEqual($label->render(), 'Taxonomy term ID');
}
@ -236,6 +235,30 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
$entity->save();
}
/**
* Tests entity auto create.
*/
public function testEntityAutoCreate() {
// The term entity is unsaved here.
$term = Term::create(array(
'name' => $this->randomMachineName(),
'vid' => $this->term->bundle(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
));
$entity = EntityTest::create();
// Now assign the unsaved term to the field.
$entity->field_test_taxonomy_term->entity = $term;
$entity->name->value = $this->randomMachineName();
// This is equal to storing an entity to tempstore or cache and retrieving
// it back. An example for this is node preview.
$entity = serialize($entity);
$entity = unserialize($entity);
// And then the entity.
$entity->save();
$term = \Drupal::entityManager()->loadEntityByUuid($term->getEntityTypeId(), $term->uuid());
$this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id());
}
/**
* Test saving order sequence doesn't matter.
*/
@ -250,6 +273,12 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
// Now assign the unsaved term to the field.
$entity->field_test_taxonomy_term->entity = $term;
$entity->name->value = $this->randomMachineName();
// Now get the field value.
$value = $entity->get('field_test_taxonomy_term');
$this->assertTrue(empty($value['target_id']));
$this->assertNull($entity->field_test_taxonomy_term->target_id);
// And then set it.
$entity->field_test_taxonomy_term = $value;
// Now save the term.
$term->save();
// And then the entity.
@ -273,20 +302,71 @@ class EntityReferenceItemTest extends FieldUnitTestBase {
$field_storage->save();
// Do not specify any value for the 'handler' setting in order to verify
// that the default value is properly used.
// that the default handler with the correct derivative is used.
$field = FieldConfig::create(array(
'field_storage' => $field_storage,
'bundle' => 'entity_test',
));
$field->save();
$field = FieldConfig::load($field->id());
$this->assertTrue($field->getSetting('handler') == 'default:entity_test');
$this->assertEqual($field->getSetting('handler'), 'default:entity_test');
// Change the target_type in the field storage, and check that the handler
// was correctly reassigned in the field.
$field_storage->setSetting('target_type', 'entity_test_rev');
$field_storage->save();
$field = FieldConfig::load($field->id());
$this->assertEqual($field->getSetting('handler'), 'default:entity_test_rev');
// Change the handler to another, non-derivative plugin.
$field->setSetting('handler', 'views');
$field->save();
$field = FieldConfig::load($field->id());
$this->assertTrue($field->getSetting('handler') == 'views');
$this->assertEqual($field->getSetting('handler'), 'views');
// Change the target_type in the field storage again, and check that the
// non-derivative handler was unchanged.
$field_storage->setSetting('target_type', 'entity_test_rev');
$field_storage->save();
$field = FieldConfig::load($field->id());
$this->assertEqual($field->getSetting('handler'), 'views');
}
/**
* Tests validation constraint.
*/
public function testValidation() {
// The term entity is unsaved here.
$term = Term::create(array(
'name' => $this->randomMachineName(),
'vid' => $this->term->bundle(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
));
$entity = EntityTest::create([
'field_test_taxonomy_term' => [
'entity' => $term,
'target_id' => NULL,
],
]);
$errors = $entity->validate();
// Using target_id of NULL is valid with an unsaved entity.
$this->assertEqual(0, count($errors));
// Using target_id of NULL is not valid with a saved entity.
$term->save();
$entity = EntityTest::create([
'field_test_taxonomy_term' => [
'entity' => $term,
'target_id' => NULL,
],
]);
$errors = $entity->validate();
$this->assertEqual(1, count($errors));
$this->assertEqual($errors[0]->getMessage(), 'This value should not be null.');
$this->assertEqual($errors[0]->getPropertyPath(), 'field_test_taxonomy_term.0');
// This should rectify the issue, favoring the entity over the target_id.
$entity->save();
$errors = $entity->validate();
$this->assertEqual(0, count($errors));
}
}

View file

@ -0,0 +1,129 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceSettingsTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\simpletest\KernelTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests entity reference field settings.
*
* @group field
*/
class EntityReferenceSettingsTest extends KernelTestBase {
use EntityReferenceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'taxonomy', 'field', 'user', 'text', 'entity_reference', 'entity_test'];
/**
* Testing node type.
*
* @var \Drupal\node\Entity\NodeType
*/
protected $nodeType;
/**
* Testing vocabulary.
*
* @var \Drupal\taxonomy\Entity\Vocabulary
*/
protected $vocabulary;
/**
* An entity bundle that is not stored as a configuration entity.
*
* @var string
*/
protected $customBundle;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setup();
$this->installEntitySchema('node');
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('entity_test');
$this->nodeType = NodeType::create([
'type' => Unicode::strtolower($this->randomMachineName()),
'name' => $this->randomString(),
]);
$this->nodeType->save();
$this->vocabulary = Vocabulary::create([
'vid' => Unicode::strtolower($this->randomMachineName()),
'name' => $this->randomString(),
]);
$this->vocabulary->save();
// Create a custom bundle.
$this->customBundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName());
entity_test_create_bundle($this->customBundle, NULL, 'entity_test');
}
/**
* Tests that config bundle deletions are mirrored in field config settings.
*/
public function testConfigTargetBundleDeletion() {
// Attach an entity reference field to $this->nodeType.
$name = Unicode::strtolower($this->randomMachineName());
$label = $this->randomString();
$vid = $this->vocabulary->id();
$handler_settings = ['target_bundles' => [$vid => $vid]];
$this->createEntityReferenceField('node', $this->nodeType->id(), $name, $label, 'taxonomy_term', 'default', $handler_settings);
// Check that the 'target_bundle' setting contains the vocabulary.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
$actual_handler_settings = $field_config->getSetting('handler_settings');
$this->assertEqual($handler_settings, $actual_handler_settings);
// Delete the vocabulary.
$this->vocabulary->delete();
// Check that the deleted vocabulary is no longer present in the
// 'target_bundles' field setting.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
$handler_settings = $field_config->getSetting('handler_settings');
$this->assertTrue(empty($handler_settings['target_bundles']));
}
/**
* Tests that deletions of custom bundles are mirrored in field settings.
*/
public function testCustomTargetBundleDeletion() {
// Attach an entity reference field to $this->nodeType.
$name = Unicode::strtolower($this->randomMachineName());
$label = $this->randomString();
$handler_settings = ['target_bundles' => [$this->customBundle => $this->customBundle]];
$this->createEntityReferenceField('node', $this->nodeType->id(), $name, $label, 'entity_test', 'default', $handler_settings);
// Check that the 'target_bundle' setting contains the custom bundle.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
$actual_handler_settings = $field_config->getSetting('handler_settings');
$this->assertEqual($handler_settings, $actual_handler_settings);
// Delete the custom bundle.
entity_test_delete_bundle($this->customBundle, 'entity_test');
// Check that the deleted bundle is no longer present in the
// 'target_bundles' field setting.
$field_config = FieldConfig::loadByName('node', $this->nodeType->id(), $name);
$handler_settings = $field_config->getSetting('handler_settings');
$this->assertTrue(empty($handler_settings['target_bundles']));
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceTestTrait.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Provides common functionality for the EntityReference test classes.
*/
trait EntityReferenceTestTrait {
/**
* Creates a field of an entity reference field storage on the specified bundle.
*
* @param string $entity_type
* The type of entity the field will be attached to.
* @param string $bundle
* The bundle name of the entity the field will be attached to.
* @param string $field_name
* The name of the field; if it already exists, a new instance of the existing
* field will be created.
* @param string $field_label
* The label of the field.
* @param string $target_entity_type
* The type of the referenced entity.
* @param string $selection_handler
* The selection handler used by this field.
* @param array $selection_handler_settings
* An array of settings supported by the selection handler specified above.
* (e.g. 'target_bundles', 'sort', 'auto_create', etc).
* @param int $cardinality
* The cardinality of the field.
*
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase::buildConfigurationForm()
*/
protected function createEntityReferenceField($entity_type, $bundle, $field_name, $field_label, $target_entity_type, $selection_handler = 'default', $selection_handler_settings = array(), $cardinality = 1) {
// Look for or add the specified field to the requested entity bundle.
if (!FieldStorageConfig::loadByName($entity_type, $field_name)) {
FieldStorageConfig::create(array(
'field_name' => $field_name,
'type' => 'entity_reference',
'entity_type' => $entity_type,
'cardinality' => $cardinality,
'settings' => array(
'target_type' => $target_entity_type,
),
))->save();
}
if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) {
FieldConfig::create(array(
'field_name' => $field_name,
'entity_type' => $entity_type,
'bundle' => $bundle,
'label' => $field_label,
'settings' => array(
'handler' => $selection_handler,
'handler_settings' => $selection_handler_settings,
),
))->save();
}
}
}

View file

@ -0,0 +1,82 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\EntityReferenceXSSTest.
*/
namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\simpletest\WebTestBase;
/**
* Tests possible XSS security issues in entity references.
*
* @group entity_reference
*/
class EntityReferenceXSSTest extends WebTestBase {
use EntityReferenceTestTrait;
/**
* Modules to enable.
*
* @var array
*/
protected static $modules = ['node'];
/**
* Tests markup is escaped in the entity reference select and label formatter.
*/
public function testEntityReferenceXSS() {
$this->drupalCreateContentType(['type' => 'article']);
// Create a node with markup in the title.
$node_type_one = $this->drupalCreateContentType();
$node = [
'type' => $node_type_one->id(),
'title' => '<em>I am kitten</em>',
];
$referenced_node = $this->drupalCreateNode($node);
$node_type_two = $this->drupalCreateContentType(['name' => '<em>bundle with markup</em>']);
$this->drupalCreateNode([
'type' => $node_type_two->id(),
'title' => 'My bundle has markup',
]);
$this->createEntityReferenceField('node', 'article', 'entity_reference_test', 'Entity Reference test', 'node', 'default', ['target_bundles' => [$node_type_one->id(), $node_type_two->id()]]);
EntityFormDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'options_select'])
->save();
EntityViewDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'entity_reference_label'])
->save();
// Create a node and reference the node with markup in the title.
$this->drupalLogin($this->rootUser);
$this->drupalGet('node/add/article');
$this->assertEscaped($referenced_node->getTitle());
$this->assertEscaped($node_type_two->label());
$edit = [
'title[0][value]' => $this->randomString(),
'entity_reference_test' => $referenced_node->id()
];
$this->drupalPostForm(NULL, $edit, 'Save and publish');
$this->assertEscaped($referenced_node->getTitle());
// Test the options_buttons type.
EntityFormDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'options_buttons'])
->save();
$this->drupalGet('node/add/article');
$this->assertEscaped($referenced_node->getTitle());
// options_buttons does not support optgroups.
$this->assertNoText('bundle with markup');
}
}

View file

@ -0,0 +1,233 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\Views\EntityReferenceRelationshipTest.
*/
namespace Drupal\field\Tests\EntityReference\Views;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Tests\ViewKernelTestBase;
use Drupal\views\Views;
/**
* Tests entity reference relationship data.
*
* @group entity_reference
*
* @see core_field_views_data()
*/
class EntityReferenceRelationshipTest extends ViewKernelTestBase {
use EntityReferenceTestTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array(
'test_entity_reference_entity_test_view',
'test_entity_reference_reverse_entity_test_view',
'test_entity_reference_entity_test_mul_view',
'test_entity_reference_reverse_entity_test_mul_view',
);
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['user', 'field', 'entity_test', 'views', 'entity_reference_test_views'];
/**
* The entity_test entities used by the test.
*
* @var array
*/
protected $entities = array();
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installEntitySchema('entity_test_mul');
// Create reference from entity_test to entity_test_mul.
$this->createEntityReferenceField('entity_test','entity_test','field_test_data','field_test_data','entity_test_mul');
// Create reference from entity_test_mul to entity_test.
$this->createEntityReferenceField('entity_test_mul', 'entity_test_mul', 'field_data_test', 'field_data_test', 'entity_test');
ViewTestData::createTestViews(get_class($this), array('entity_reference_test_views'));
}
/**
* Tests using the views relationship.
*/
public function testNoDataTableRelationship() {
// Create some test entities which link each other.
$referenced_entity = EntityTestMul::create();
$referenced_entity->save();
$entity = EntityTest::create();
$entity->field_test_data->target_id = $referenced_entity->id();
$entity->save();
$this->assertEqual($entity->field_test_data[0]->entity->id(), $referenced_entity->id());
$this->entities[] = $entity;
$entity = EntityTest::create();
$entity->field_test_data->target_id = $referenced_entity->id();
$entity->save();
$this->assertEqual($entity->field_test_data[0]->entity->id(), $referenced_entity->id());
$this->entities[] = $entity;
Views::viewsData()->clear();
// Check the generated views data.
$views_data = Views::viewsData()->get('entity_test__field_test_data');
$this->assertEqual($views_data['field_test_data']['relationship']['id'], 'standard');
$this->assertEqual($views_data['field_test_data']['relationship']['base'], 'entity_test_mul_property_data');
$this->assertEqual($views_data['field_test_data']['relationship']['base field'], 'id');
$this->assertEqual($views_data['field_test_data']['relationship']['relationship field'], 'field_test_data_target_id');
$this->assertEqual($views_data['field_test_data']['relationship']['entity type'], 'entity_test_mul');
// Check the backwards reference.
$views_data = Views::viewsData()->get('entity_test_mul_property_data');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['id'], 'entity_reverse');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['base'], 'entity_test');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['base field'], 'id');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['field table'], 'entity_test__field_test_data');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['field field'], 'field_test_data_target_id');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['field_name'], 'field_test_data');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['entity_type'], 'entity_test');
$this->assertEqual($views_data['reverse__entity_test__field_test_data']['relationship']['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
// Check an actual test view.
$view = Views::getView('test_entity_reference_entity_test_view');
$this->executeView($view);
/** @var \Drupal\views\ResultRow $row */
foreach ($view->result as $index => $row) {
// Check that the actual ID of the entity is the expected one.
$this->assertEqual($row->id, $this->entities[$index]->id());
// Also check that we have the correct result entity.
$this->assertEqual($row->_entity->id(), $this->entities[$index]->id());
// Test the forward relationship.
$this->assertEqual($row->entity_test_mul_property_data_entity_test__field_test_data_i, 1);
// Test that the correct relationship entity is on the row.
$this->assertEqual($row->_relationship_entities['field_test_data']->id(), 1);
$this->assertEqual($row->_relationship_entities['field_test_data']->bundle(), 'entity_test_mul');
}
// Check the backwards reference view.
$view = Views::getView('test_entity_reference_reverse_entity_test_view');
$this->executeView($view);
/** @var \Drupal\views\ResultRow $row */
foreach ($view->result as $index => $row) {
$this->assertEqual($row->id, 1);
$this->assertEqual($row->_entity->id(), 1);
// Test the backwards relationship.
$this->assertEqual($row->field_test_data_entity_test_mul_property_data_id, $this->entities[$index]->id());
// Test that the correct relationship entity is on the row.
$this->assertEqual($row->_relationship_entities['reverse__entity_test__field_test_data']->id(), $this->entities[$index]->id());
$this->assertEqual($row->_relationship_entities['reverse__entity_test__field_test_data']->bundle(), 'entity_test');
}
}
/**
* Tests views data generated for relationship.
*
* @see entity_reference_field_views_data()
*/
public function testDataTableRelationship() {
// Create some test entities which link each other.
$referenced_entity = EntityTest::create();
$referenced_entity->save();
$entity = EntityTestMul::create();
$entity->field_data_test->target_id = $referenced_entity->id();
$entity->save();
$this->assertEqual($entity->field_data_test[0]->entity->id(), $referenced_entity->id());
$this->entities[] = $entity;
$entity = EntityTestMul::create();
$entity->field_data_test->target_id = $referenced_entity->id();
$entity->save();
$this->assertEqual($entity->field_data_test[0]->entity->id(), $referenced_entity->id());
$this->entities[] = $entity;
Views::viewsData()->clear();
// Check the generated views data.
$views_data = Views::viewsData()->get('entity_test_mul__field_data_test');
$this->assertEqual($views_data['field_data_test']['relationship']['id'], 'standard');
$this->assertEqual($views_data['field_data_test']['relationship']['base'], 'entity_test');
$this->assertEqual($views_data['field_data_test']['relationship']['base field'], 'id');
$this->assertEqual($views_data['field_data_test']['relationship']['relationship field'], 'field_data_test_target_id');
$this->assertEqual($views_data['field_data_test']['relationship']['entity type'], 'entity_test');
// Check the backwards reference.
$views_data = Views::viewsData()->get('entity_test');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['id'], 'entity_reverse');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['base'], 'entity_test_mul_property_data');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['base field'], 'id');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['field table'], 'entity_test_mul__field_data_test');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['field field'], 'field_data_test_target_id');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['field_name'], 'field_data_test');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['entity_type'], 'entity_test_mul');
$this->assertEqual($views_data['reverse__entity_test_mul__field_data_test']['relationship']['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]);
// Check an actual test view.
$view = Views::getView('test_entity_reference_entity_test_mul_view');
$this->executeView($view);
/** @var \Drupal\views\ResultRow $row */
foreach ($view->result as $index => $row) {
// Check that the actual ID of the entity is the expected one.
$this->assertEqual($row->id, $this->entities[$index]->id());
// Also check that we have the correct result entity.
$this->assertEqual($row->_entity->id(), $this->entities[$index]->id());
// Test the forward relationship.
$this->assertEqual($row->entity_test_entity_test_mul__field_data_test_id, 1);
// Test that the correct relationship entity is on the row.
$this->assertEqual($row->_relationship_entities['field_data_test']->id(), 1);
$this->assertEqual($row->_relationship_entities['field_data_test']->bundle(), 'entity_test');
}
// Check the backwards reference view.
$view = Views::getView('test_entity_reference_reverse_entity_test_mul_view');
$this->executeView($view);
/** @var \Drupal\views\ResultRow $row */
foreach ($view->result as $index => $row) {
$this->assertEqual($row->id, 1);
$this->assertEqual($row->_entity->id(), 1);
// Test the backwards relationship.
$this->assertEqual($row->field_data_test_entity_test_id, $this->entities[$index]->id());
// Test that the correct relationship entity is on the row.
$this->assertEqual($row->_relationship_entities['reverse__entity_test_mul__field_data_test']->id(), $this->entities[$index]->id());
$this->assertEqual($row->_relationship_entities['reverse__entity_test_mul__field_data_test']->bundle(), 'entity_test_mul');
}
}
}

View file

@ -0,0 +1,147 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\EntityReference\Views\SelectionTest.
*/
namespace Drupal\field\Tests\EntityReference\Views;
use Drupal\simpletest\WebTestBase;
use Drupal\views\Views;
/**
* Tests entity reference selection handler.
*
* @group entity_reference
*/
class SelectionTest extends WebTestBase {
public static $modules = ['node', 'views', 'entity_reference_test', 'entity_test'];
/**
* Nodes for testing.
*
* @var array
*/
protected $nodes = array();
/**
* The entity reference field to test.
*
* @var \Drupal\Core\Field\FieldDefinitionInterface
*/
protected $field;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Create nodes.
$type = $this->drupalCreateContentType()->id();
$node1 = $this->drupalCreateNode(array('type' => $type));
$node2 = $this->drupalCreateNode(array('type' => $type));
$node3 = $this->drupalCreateNode();
foreach (array($node1, $node2, $node3) as $node) {
$this->nodes[$node->getType()][$node->id()] = $node->label();
}
// Create a field.
$field_storage = entity_create('field_storage_config', array(
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'translatable' => FALSE,
'settings' => array(
'target_type' => 'node',
),
'type' => 'entity_reference',
'cardinality' => '1',
));
$field_storage->save();
$field = entity_create('field_config', array(
'field_storage' => $field_storage,
'bundle' => 'test_bundle',
'settings' => array(
'handler' => 'views',
'handler_settings' => array(
'view' => array(
'view_name' => 'test_entity_reference',
'display_name' => 'entity_reference_1',
'arguments' => array(),
),
),
),
));
$field->save();
$this->field = $field;
}
/**
* Confirm the expected results are returned.
*
* @param array $result
* Query results keyed by node type and nid.
*/
protected function assertResults(array $result) {
$success = FALSE;
foreach ($result as $node_type => $values) {
foreach ($values as $nid => $label) {
if (!$success = $this->nodes[$node_type][$nid] == trim(strip_tags($label))) {
// There was some error, so break.
break;
}
}
}
$this->assertTrue($success, 'Views selection handler returned expected values.');
}
/**
* Tests the selection handler.
*/
public function testSelectionHandler() {
// Get values from selection handler.
$handler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($this->field);
$result = $handler->getReferenceableEntities();
$this->assertResults($result);
}
/**
* Tests the selection handler with a relationship.
*/
public function testSelectionHandlerRelationship() {
// Add a relationship to the view.
$view = Views::getView('test_entity_reference');
$view->setDisplay();
$view->displayHandlers->get('default')->setOption('relationships', array(
'test_relationship' => array(
'id' => 'uid',
'table' => 'node_field_data',
'field' => 'uid',
),
));
// Add a filter depending on the relationship to the test view.
$view->displayHandlers->get('default')->setOption('filters', array(
'uid' => array(
'id' => 'uid',
'table' => 'users_field_data',
'field' => 'uid',
'relationship' => 'test_relationship',
)
));
// Set view to distinct so only one row per node is returned.
$query_options = $view->display_handler->getOption('query');
$query_options['options']['distinct'] = TRUE;
$view->display_handler->setOption('query', $query_options);
$view->save();
// Get values from the selection handler.
$handler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($this->field);
$result = $handler->getReferenceableEntities();
$this->assertResults($result);
}
}

View file

@ -275,9 +275,9 @@ class FieldAttachStorageTest extends FieldUnitTestBase {
}
/**
* Test entity_bundle_create() and entity_bundle_rename().
* Test entity_bundle_create().
*/
function testEntityCreateRenameBundle() {
function testEntityCreateBundle() {
$entity_type = 'entity_test_rev';
$this->createFieldWithStorage('', $entity_type);
$cardinality = $this->fieldTestData->field_storage->getCardinality();
@ -298,20 +298,6 @@ class FieldAttachStorageTest extends FieldUnitTestBase {
// Verify the field data is present on load.
$entity = $this->entitySaveReload($entity);
$this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Data is retrieved for the new bundle");
// Rename the bundle.
$new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName());
entity_test_rename_bundle($this->fieldTestData->field_definition['bundle'], $new_bundle, $entity_type);
// Check that the field definition has been updated.
$this->fieldTestData->field = FieldConfig::loadByName($entity_type, $new_bundle, $this->fieldTestData->field_name);
$this->assertIdentical($this->fieldTestData->field->getTargetBundle(), $new_bundle, "Bundle name has been updated in the field.");
// Verify the field data is present on load.
$controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId());
$controller->resetCache();
$entity = $controller->load($entity->id());
$this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Bundle name has been updated in the field storage");
}
/**

View file

@ -10,6 +10,7 @@ namespace Drupal\field\Tests;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Field\FieldException;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
@ -137,6 +138,44 @@ class FieldCrudTest extends FieldUnitTestBase {
// TODO: test other failures.
}
/**
* Test creating a field with custom storage set.
*/
public function testCreateFieldCustomStorage() {
$field_name = Unicode::strtolower($this->randomMachineName());
\Drupal::state()->set('field_test_custom_storage', $field_name);
$field_storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'test_field',
'custom_storage' => TRUE,
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => $field_storage->getName(),
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field->save();
\Drupal::entityManager()->clearCachedFieldDefinitions();
// Check that no table has been created for the field.
$this->assertFalse(\Drupal::database()->schema()->tableExists('entity_test__' . $field_storage->getName()));
// Save an entity with a value in the custom storage field and verify no
// data is retrieved on load.
$entity = EntityTest::create(['name' => $this->randomString(), $field_name => 'Test value']);
$this->assertIdentical('Test value', $entity->{$field_name}->value, 'The test value is set on the field.');
$entity->save();
$entity = EntityTest::load($entity->id());
$this->assertNull($entity->{$field_name}->value, 'The loaded entity field value is NULL.');
}
/**
* Test reading back a field definition.
*/

View file

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\FieldDefaultValueCallbackProvider.
*/
namespace Drupal\field\Tests;
/**
* Helper class for \Drupal\field\Tests\FieldDefaultValueCallbackTest.
*/
class FieldDefaultValueCallbackProvider {
/**
* Helper callback calculating a default value.
*/
public static function calculateDefaultValue() {
return [['value' => 'Calculated default value']];
}
}

View file

@ -0,0 +1,94 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\FieldDefaultValueCallbackTest.
*/
namespace Drupal\field\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
/**
* Tests the default value callback.
*
* @group field
*/
class FieldDefaultValueCallbackTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'field_test', 'field_ui');
/**
* The field name.
*
* @var string
*/
private $fieldName;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->fieldName = 'field_test';
// Create Article node types.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(array(
'type' => 'article',
'name' => 'Article',
));
}
}
public function testDefaultValueCallbackForm() {
// Create a field and storage for checking.
/** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'text',
])->save();
/** @var \Drupal\field\Entity\FieldConfig $field_config */
$field_config = FieldConfig::create([
'entity_type' => 'node',
'field_name' => $this->fieldName,
'bundle' => 'article',
]);
$field_config->save();
$this->drupalLogin($this->rootUser);
// Check that the default field form is visible when no callback is set.
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', NULL, 'The default field form is visible.');
// Set a different field value, it should be on the field.
$default_value = $this->randomString();
$field_config->setDefaultValue([['value' => $default_value]])->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', $default_value, 'The default field form is visible.');
// Set a different field value to the field directly, instead of an array.
$default_value = $this->randomString();
$field_config->setDefaultValue($default_value)->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertFieldByName('default_value_input[field_test][0][value]', $default_value, 'The default field form is visible.');
// Set a default value callback instead, and the default field form should
// not be visible.
$field_config->setDefaultValueCallback('\Drupal\field\Tests\FieldDefaultValueCallbackProvider::calculateDefaultValue')->save();
$this->drupalGet('/admin/structure/types/manage/article/fields/node.article.field_test');
$this->assertNoFieldByName('default_value_input[field_test][0][value]', 'Calculated default value', 'The default field form is not visible when a callback is defined.');
}
}

View file

@ -44,17 +44,57 @@ class FieldDefinitionIntegrityTest extends KernelTestBase {
* Tests the integrity of field plugin definitions.
*/
public function testFieldPluginDefinitionIntegrity() {
// Load the IDs of all available field type plugins.
$available_field_type_ids = [];
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
$field_formatter_manager = \Drupal::service('plugin.manager.field.formatter');
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
$field_widget_manager = \Drupal::service('plugin.manager.field.widget');
// Load the IDs of all available field type plugins.
$available_field_type_ids = [];
foreach ($field_type_manager->getDefinitions() as $definition) {
$available_field_type_ids[] = $definition['id'];
}
// Load the IDs of all available field widget plugins.
$available_field_widget_ids = [];
foreach ($field_widget_manager->getDefinitions() as $definition) {
$available_field_widget_ids[] = $definition['id'];
}
// Load the IDs of all available field formatter plugins.
$available_field_formatter_ids = [];
foreach ($field_formatter_manager->getDefinitions() as $definition) {
$available_field_formatter_ids[] = $definition['id'];
}
// Test the field type plugins.
foreach ($field_type_manager->getDefinitions() as $definition) {
// Test default field widgets.
if (isset($definition['default_widget'])) {
if (in_array($definition['default_widget'], $available_field_widget_ids)) {
$this->pass(sprintf('Field type %s uses an existing field widget by default.', $definition['id']));
}
else {
$this->fail(sprintf('Field type %s uses a non-existent field widget by default: %s', $definition['id'], $definition['default_widget']));
}
}
// Test default field formatters.
if (isset($definition['default_formatter'])) {
if (in_array($definition['default_formatter'], $available_field_formatter_ids)) {
$this->pass(sprintf('Field type %s uses an existing field formatter by default.', $definition['id']));
}
else {
$this->fail(sprintf('Field type %s uses a non-existent field formatter by default: %s', $definition['id'], $definition['default_formatter']));
}
}
}
// Test the field widget plugins.
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_widget_manager */
$field_widget_manager = \Drupal::service('plugin.manager.field.widget');
foreach ($field_widget_manager->getDefinitions() as $definition) {
$missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
if ($missing_field_type_ids) {
@ -66,8 +106,6 @@ class FieldDefinitionIntegrityTest extends KernelTestBase {
}
// Test the field formatter plugins.
/** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_formatter_manager */
$field_formatter_manager = \Drupal::service('plugin.manager.field.formatter');
foreach ($field_formatter_manager->getDefinitions() as $definition) {
$missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
if ($missing_field_type_ids) {

View file

@ -37,16 +37,16 @@ class FieldImportChangeTest extends FieldUnitTestBase {
$field_config_name = "field.field.$field_id";
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
// Save as files in the staging directory.
// Save as files in the sync directory.
$field = $active->read($field_config_name);
$new_label = 'Test update import field';
$field['label'] = $new_label;
$staging->write($field_config_name, $field);
$sync->write($field_config_name, $field);
// Import the content of the staging directory.
// Import the content of the sync directory.
$this->configImporter()->import();
// Check that the updated config was correctly imported.

View file

@ -77,14 +77,14 @@ class FieldImportCreateTest extends FieldUnitTestBase {
*/
function testImportCreate() {
// A field storage with one single field.
$field_name = 'field_test_import_staging';
$field_name = 'field_test_import_sync';
$field_storage_id = "entity_test.$field_name";
$field_id = "entity_test.entity_test.$field_name";
$field_storage_config_name = "field.storage.$field_storage_id";
$field_config_name = "field.field.$field_id";
// A field storage with two fields.
$field_name_2 = 'field_test_import_staging_2';
$field_name_2 = 'field_test_import_sync_2';
$field_storage_id_2 = "entity_test.$field_name_2";
$field_id_2a = "entity_test.test_bundle.$field_name_2";
$field_id_2b = "entity_test.test_bundle_2.$field_name_2";
@ -93,32 +93,32 @@ class FieldImportCreateTest extends FieldUnitTestBase {
$field_config_name_2b = "field.field.$field_id_2b";
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
// Add the new files to the staging directory.
$src_dir = drupal_get_path('module', 'field_test_config') . '/staging';
$target_dir = $this->configDirectories[CONFIG_STAGING_DIRECTORY];
// Add the new files to the sync directory.
$src_dir = drupal_get_path('module', 'field_test_config') . '/sync';
$target_dir = $this->configDirectories[CONFIG_SYNC_DIRECTORY];
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name.yml", "$target_dir/$field_storage_config_name.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name_2.yml", "$target_dir/$field_storage_config_name_2.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2a.yml", "$target_dir/$field_config_name_2a.yml"));
$this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2b.yml", "$target_dir/$field_config_name_2b.yml"));
// Import the content of the staging directory.
// Import the content of the sync directory.
$this->configImporter()->import();
// Check that the field and storage were created.
$field_storage = FieldStorageConfig::load($field_storage_id);
$this->assertTrue($field_storage, 'Test import storage field from staging exists');
$this->assertTrue($field_storage, 'Test import storage field from sync exists');
$field = FieldConfig::load($field_id);
$this->assertTrue($field, 'Test import field from staging exists');
$this->assertTrue($field, 'Test import field from sync exists');
$field_storage = FieldStorageConfig::load($field_storage_id_2);
$this->assertTrue($field_storage, 'Test import storage field 2 from staging exists');
$this->assertTrue($field_storage, 'Test import storage field 2 from sync exists');
$field = FieldConfig::load($field_id_2a);
$this->assertTrue($field, 'Test import field 2a from staging exists');
$this->assertTrue($field, 'Test import field 2a from sync exists');
$field = FieldConfig::load($field_id_2b);
$this->assertTrue($field, 'Test import field 2b from staging exists');
$this->assertTrue($field, 'Test import field 2b from sync exists');
}
}

View file

@ -63,18 +63,18 @@ class FieldImportDeleteTest extends FieldUnitTestBase {
$field_storage_uuid_2 = FieldStorageConfig::load($field_storage_id_2)->uuid();
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$this->assertTrue($staging->delete($field_storage_config_name), SafeMarkup::format('Deleted field storage: !field_storage', array('!field_storage' => $field_storage_config_name)));
$this->assertTrue($staging->delete($field_storage_config_name_2), SafeMarkup::format('Deleted field storage: !field_storage', array('!field_storage' => $field_storage_config_name_2)));
$this->assertTrue($staging->delete($field_config_name), SafeMarkup::format('Deleted field: !field', array('!field' => $field_config_name)));
$this->assertTrue($staging->delete($field_config_name_2a), SafeMarkup::format('Deleted field: !field', array('!field' => $field_config_name_2a)));
$this->assertTrue($staging->delete($field_config_name_2b), SafeMarkup::format('Deleted field: !field', array('!field' => $field_config_name_2b)));
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
$this->assertTrue($sync->delete($field_storage_config_name), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name)));
$this->assertTrue($sync->delete($field_storage_config_name_2), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name_2)));
$this->assertTrue($sync->delete($field_config_name), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name)));
$this->assertTrue($sync->delete($field_config_name_2a), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2a)));
$this->assertTrue($sync->delete($field_config_name_2b), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2b)));
$deletes = $this->configImporter()->getUnprocessedConfiguration('delete');
$this->assertEqual(count($deletes), 5, 'Importing configuration will delete 3 fields and 2 field storages.');
// Import the content of the staging directory.
// Import the content of the sync directory.
$this->configImporter()->import();
// Check that the field storages and fields are gone.

View file

@ -81,17 +81,17 @@ class FieldImportDeleteUninstallTest extends FieldUnitTestBase {
$unrelated_field_storage->delete();
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
// Stage uninstall of the Telephone module.
$core_extension = $this->config('core.extension')->get();
unset($core_extension['module']['telephone']);
$staging->write('core.extension', $core_extension);
$sync->write('core.extension', $core_extension);
// Stage the field deletion
$staging->delete('field.storage.entity_test.field_test');
$staging->delete('field.field.entity_test.entity_test.field_test');
$sync->delete('field.storage.entity_test.field_test');
$sync->delete('field.field.entity_test.entity_test.field_test');
$steps = $this->configImporter()->initialize();
$this->assertIdentical($steps[0], array('\Drupal\field\ConfigImporterFieldPurger', 'process'), 'The additional process configuration synchronization step has been added.');
@ -143,13 +143,13 @@ class FieldImportDeleteUninstallTest extends FieldUnitTestBase {
$field_storage->delete();
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
// Stage uninstall of the Telephone module.
$core_extension = $this->config('core.extension')->get();
unset($core_extension['module']['telephone']);
$staging->write('core.extension', $core_extension);
$sync->write('core.extension', $core_extension);
$deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array();
$this->assertTrue(isset($deleted_storages[$field_storage_uuid]), 'Field has been deleted and needs purging before configuration synchronization.');

View file

@ -79,17 +79,17 @@ class FieldImportDeleteUninstallUiTest extends FieldTestBase {
$this->assertEqual($entity->field_tel[0]->value, $value);
$active = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
$this->copyConfig($active, $staging);
$sync = $this->container->get('config.storage.sync');
$this->copyConfig($active, $sync);
// Stage uninstall of the Telephone module.
$core_extension = $this->config('core.extension')->get();
unset($core_extension['module']['telephone']);
$staging->write('core.extension', $core_extension);
$sync->write('core.extension', $core_extension);
// Stage the field deletion
$staging->delete('field.storage.entity_test.field_tel');
$staging->delete('field.field.entity_test.entity_test.field_tel');
$sync->delete('field.storage.entity_test.field_tel');
$sync->delete('field.field.entity_test.entity_test.field_tel');
$this->drupalGet('admin/config/development/configuration');
// Test that the message for one field being purged during a configuration
// synchronization is correct.
@ -98,7 +98,7 @@ class FieldImportDeleteUninstallUiTest extends FieldTestBase {
// Stage an uninstall of the datetime module to test the message for
// multiple fields.
unset($core_extension['module']['datetime']);
$staging->write('core.extension', $core_extension);
$sync->write('core.extension', $core_extension);
$this->drupalGet('admin/config/development/configuration');
$this->assertText('This synchronization will delete data from the fields: entity_test.field_tel, entity_test.field_date.');

View file

@ -46,11 +46,11 @@ abstract class FieldTestBase extends WebTestBase {
* The array of expected values.
* @param $langcode
* (Optional) The language code for the values. Defaults to
* \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED.
* \Drupal\Core\Language\LanguageInterface::LANGCODE_DEFAULT.
* @param $column
* (Optional) The name of the column to check. Defaults to 'value'.
*/
function assertFieldValues(EntityInterface $entity, $field_name, $expected_values, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $column = 'value') {
function assertFieldValues(EntityInterface $entity, $field_name, $expected_values, $langcode = LanguageInterface::LANGCODE_DEFAULT, $column = 'value') {
// Re-load the entity to make sure we have the latest changes.
\Drupal::entityManager()->getStorage($entity->getEntityTypeId())->resetCache(array($entity->id()));
$e = entity_load($entity->getEntityTypeId(), $entity->id());

View file

@ -22,7 +22,7 @@ abstract class FieldUnitTestBase extends KernelTestBase {
*
* @var array
*/
public static $modules = array('user', 'system', 'field', 'text', 'entity_test', 'field_test', 'entity_reference');
public static $modules = ['user', 'system', 'field', 'text', 'entity_test', 'field_test'];
/**
* Bag of created field storages and fields.

View file

@ -23,9 +23,11 @@ class FormTest extends FieldTestBase {
/**
* Modules to enable.
*
* Locale is installed so that TranslatableMarkup actually does something.
*
* @var array
*/
public static $modules = array('node', 'field_test', 'options', 'entity_test');
public static $modules = array('node', 'field_test', 'options', 'entity_test', 'locale');
/**
* An array of values defining a field single.
@ -208,7 +210,7 @@ class FormTest extends FieldTestBase {
// Submit with missing required value.
$edit = array();
$this->drupalPostForm('entity_test/add', $edit, t('Save'));
$this->assertRaw(t('!name field is required.', array('!name' => $this->field['label'])), 'Required field with no value fails validation');
$this->assertRaw(t('@name field is required.', array('@name' => $this->field['label'])), 'Required field with no value fails validation');
// Create an entity
$value = mt_rand(1, 127);
@ -228,7 +230,7 @@ class FormTest extends FieldTestBase {
"{$field_name}[0][value]" => $value,
);
$this->drupalPostForm('entity_test/manage/' . $id, $edit, t('Save'));
$this->assertRaw(t('!name field is required.', array('!name' => $this->field['label'])), 'Required field with no value fails validation');
$this->assertRaw(t('@name field is required.', array('@name' => $this->field['label'])), 'Required field with no value fails validation');
}
// function testFieldFormMultiple() {
@ -254,6 +256,10 @@ class FormTest extends FieldTestBase {
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
$this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
// Check if aria-describedby attribute is placed on multiple value widgets.
$elements = $this->xpath('//table[@id="field-unlimited-values" and @aria-describedby="edit-field-unlimited--description"]');
$this->assertTrue(isset($elements[0]), t('aria-describedby attribute is properly placed on multiple value widgets.'));
// Press 'add more' button -> 2 widgets.
$this->drupalPostForm(NULL, array(), t('Add another item'));
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
@ -613,7 +619,7 @@ class FormTest extends FieldTestBase {
// Update the field to remove the default value, and switch to the default
// widget.
$this->field->default_value = array();
$this->field->setDefaultValue(array());
$this->field->save();
entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
->setComponent($this->field->getName(), array(

View file

@ -7,7 +7,9 @@
namespace Drupal\field\Tests\Migrate\d6;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\Entity\EntityViewMode;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
@ -17,54 +19,12 @@ use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
*/
class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'field', 'datetime', 'image', 'text', 'link', 'file', 'telephone');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['node']);
entity_create('node_type', array('type' => 'test_page'))->save();
entity_create('node_type', array('type' => 'story'))->save();
// Create the node preview view mode.
EntityViewMode::create(array('id' => 'node.preview', 'targetEntityType' => 'node'))->save();
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_view_modes' => array(
array(array(1), array('node', 'preview')),
array(array(4), array('node', 'rss')),
array(array('teaser'), array('node', 'teaser')),
array(array('full'), array('node', 'full')),
),
'd6_field_instance' => array(
array(array('fieldname', 'page'), array('node', 'fieldname', 'page')),
),
'd6_field' => array(
array(array('field_test'), array('node', 'field_test')),
array(array('field_test_two'), array('node', 'field_test_two')),
array(array('field_test_three'), array('node', 'field_test_three')),
array(array('field_test_email'), array('node', 'field_test_email')),
array(array('field_test_link'), array('node', 'field_test_link')),
array(array('field_test_filefield'), array('node', 'field_test_filefield')),
array(array('field_test_imagefield'), array('node', 'field_test_imagefield')),
array(array('field_test_phone'), array('node', 'field_test_phone')),
array(array('field_test_date'), array('node', 'field_test_date')),
array(array('field_test_datestamp'), array('node', 'field_test_datestamp')),
array(array('field_test_datetime'), array('node', 'field_test_datetime')),
array(array('field_test_exclude_unset'), array('node', 'field_test_exclude_unset')),
),
);
$this->prepareMigrations($id_mappings);
$this->executeMigration('d6_field_formatter_settings');
$this->migrateFields();
}
/**
@ -82,23 +42,23 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
);
// Can we load any entity display.
$display = entity_load('entity_view_display', 'node.story.teaser');
$display = EntityViewDisplay::load('node.story.teaser');
$this->assertIdentical($expected, $display->getComponent($field_name));
// Test migrate worked with multiple bundles.
$display = entity_load('entity_view_display', 'node.test_page.teaser');
$display = EntityViewDisplay::load('node.test_page.teaser');
$expected['weight'] = 35;
$this->assertIdentical($expected, $display->getComponent($field_name));
// Test RSS because that has been converted from 4 to rss.
$display = entity_load('entity_view_display', 'node.story.rss');
$display = EntityViewDisplay::load('node.story.rss');
$expected['weight'] = 1;
$this->assertIdentical($expected, $display->getComponent($field_name));
// Test the default format with text_default which comes from a static map.
$expected['type'] = 'text_default';
$expected['settings'] = array();
$display = entity_load('entity_view_display', 'node.story.default');
$display = EntityViewDisplay::load('node.story.default');
$this->assertIdentical($expected, $display->getComponent($field_name));
// Check that we can migrate multiple fields.
@ -150,7 +110,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$this->assertIdentical($expected, $component);
$expected['settings']['url_only'] = FALSE;
$expected['settings']['url_plain'] = FALSE;
$display = entity_load('entity_view_display', 'node.story.teaser');
$display = EntityViewDisplay::load('node.story.teaser');
$component = $display->getComponent('field_test_link');
$this->assertIdentical($expected, $component);
@ -160,7 +120,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$expected['settings'] = array();
$component = $display->getComponent('field_test_filefield');
$this->assertIdentical($expected, $component);
$display = entity_load('entity_view_display', 'node.story.default');
$display = EntityViewDisplay::load('node.story.default');
$expected['type'] = 'file_url_plain';
$component = $display->getComponent('field_test_filefield');
$this->assertIdentical($expected, $component);
@ -171,7 +131,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$expected['settings'] = array('image_style' => '', 'image_link' => '');
$component = $display->getComponent('field_test_imagefield');
$this->assertIdentical($expected, $component);
$display = entity_load('entity_view_display', 'node.story.teaser');
$display = EntityViewDisplay::load('node.story.teaser');
$expected['settings']['image_link'] = 'file';
$component = $display->getComponent('field_test_imagefield');
$this->assertIdentical($expected, $component);
@ -190,7 +150,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$expected['settings'] = array('format_type' => 'fallback') + $defaults;
$component = $display->getComponent('field_test_date');
$this->assertIdentical($expected, $component);
$display = entity_load('entity_view_display', 'node.story.default');
$display = EntityViewDisplay::load('node.story.default');
$expected['settings']['format_type'] = 'long';
$component = $display->getComponent('field_test_date');
$this->assertIdentical($expected, $component);
@ -200,7 +160,7 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$expected['settings']['format_type'] = 'fallback';
$component = $display->getComponent('field_test_datestamp');
$this->assertIdentical($expected, $component);
$display = entity_load('entity_view_display', 'node.story.teaser');
$display = EntityViewDisplay::load('node.story.teaser');
$expected['settings'] = array('format_type' => 'medium') + $defaults;
$component = $display->getComponent('field_test_datestamp');
$this->assertIdentical($expected, $component);
@ -210,19 +170,19 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal6TestBase {
$expected['settings'] = array('format_type' => 'short') + $defaults;
$component = $display->getComponent('field_test_datetime');
$this->assertIdentical($expected, $component);
$display = entity_load('entity_view_display', 'node.story.default');
$display = EntityViewDisplay::load('node.story.default');
$expected['settings']['format_type'] = 'fallback';
$component = $display->getComponent('field_test_datetime');
$this->assertIdentical($expected, $component);
// Test a date field with a random format which should be mapped
// to datetime_default.
$display = entity_load('entity_view_display', 'node.story.rss');
$display = EntityViewDisplay::load('node.story.rss');
$expected['settings']['format_type'] = 'fallback';
$component = $display->getComponent('field_test_datetime');
$this->assertIdentical($expected, $component);
// Test that our Id map has the correct data.
$this->assertIdentical(array('node', 'story', 'teaser', 'field_test'), entity_load('migration', 'd6_field_formatter_settings')->getIdMap()->lookupDestinationID(array('story', 'teaser', 'node', 'field_test')));
$this->assertIdentical(array('node', 'story', 'teaser', 'field_test'), Migration::load('d6_field_formatter_settings')->getIdMap()->lookupDestinationID(array('story', 'teaser', 'node', 'field_test')));
}
}

View file

@ -10,6 +10,7 @@ namespace Drupal\field\Tests\Migrate\d6;
use Drupal\field\Entity\FieldConfig;
use Drupal\link\LinkItemInterface;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
use Drupal\node\Entity\Node;
/**
* Migrate field instances.
@ -18,63 +19,19 @@ use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
*/
class MigrateFieldInstanceTest extends MigrateDrupal6TestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'telephone',
'link',
'file',
'image',
'datetime',
'node',
'field',
'text',
);
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_field' => array(
array(array('field_test'), array('node', 'field_test')),
array(array('field_test_two'), array('node', 'field_test_two')),
array(array('field_test_three'), array('node', 'field_test_three')),
array(array('field_test_four'), array('node', 'field_test_four')),
array(array('field_test_email'), array('node', 'field_test_email')),
array(array('field_test_link'), array('node', 'field_test_link')),
array(array('field_test_filefield'), array('node', 'field_test_filefield')),
array(array('field_test_imagefield'), array('node', 'field_test_imagefield')),
array(array('field_test_phone'), array('node', 'field_test_phone')),
array(array('field_test_date'), array('node', 'field_test_date')),
array(array('field_test_datestamp'), array('node', 'field_test_datestamp')),
array(array('field_test_datetime'), array('node', 'field_test_datetime')),
),
'd6_node_type' => array(
array(array('page'), array('page')),
array(array('story'), array('story')),
array(array('test_page'), array('test_page')),
),
);
$this->prepareMigrations($id_mappings);
entity_create('node_type', array('type' => 'page'))->save();
entity_create('node_type', array('type' => 'story'))->save();
entity_create('node_type', array('type' => 'test_page'))->save();
$this->createFields();
$this->executeMigration('d6_field_instance');
$this->migrateFields();
}
/**
* Tests migration of file variables to file.settings.yml.
*/
public function testFieldInstanceSettings() {
$entity = entity_create('node', array('type' => 'story'));
$entity = Node::create(['type' => 'story']);
// Test a text field.
$field = FieldConfig::load('node.story.field_test');
$this->assertIdentical('Text Field', $field->label());
@ -122,11 +79,8 @@ class MigrateFieldInstanceTest extends MigrateDrupal6TestBase {
'display_field' => FALSE,
'display_default' => FALSE,
'uri_scheme' => 'public',
// This value should be 'default:file' but the test does not migrate field
// storages so we end up with the default value for this setting.
'handler' => 'default:node',
'handler' => 'default:file',
'handler_settings' => array(),
'target_bundle' => NULL,
);
$field_settings = $field->getSettings();
ksort($expected);
@ -144,32 +98,4 @@ class MigrateFieldInstanceTest extends MigrateDrupal6TestBase {
$this->assertIdentical([], $entity->field_test_link->options['attributes']);
}
/**
* Helper to create fields.
*/
protected function createFields() {
$fields = array(
'field_test' => 'text',
'field_test_two' => 'integer',
'field_test_three' => 'decimal',
'field_test_four' => 'float',
'field_test_email' => 'email',
'field_test_link' => 'link',
'field_test_filefield' => 'file',
'field_test_imagefield' => 'image',
'field_test_phone' => 'telephone',
'field_test_date' => 'datetime',
'field_test_datestamp' => 'datetime',
'field_test_datetime' => 'datetime',
);
foreach ($fields as $name => $type) {
entity_create('field_storage_config', array(
'field_name' => $name,
'entity_type' => 'node',
'type' => $type,
))->save();
}
}
}

View file

@ -8,6 +8,7 @@
namespace Drupal\field\Tests\Migrate\d6;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
@ -17,13 +18,6 @@ use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
*/
class MigrateFieldTest extends MigrateDrupal6TestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field', 'telephone', 'link', 'file', 'image', 'datetime', 'node', 'options', 'text');
/**
* {@inheritdoc}
*/
@ -102,6 +96,18 @@ class MigrateFieldTest extends MigrateDrupal6TestBase {
$field_storage = FieldStorageConfig::load('node.field_test_text_single_checkbox');
$this->assertIdentical("boolean", $field_storage->getType(), t('Field type is @fieldtype. It should be boolean.', array('@fieldtype' => $field_storage->getType())));
// Validate that the source count and processed count match up.
/** @var \Drupal\migrate\Entity\MigrationInterface $migration */
$migration = Migration::load('d6_field');
$this->assertIdentical($migration->getSourcePlugin()->count(), $migration->getIdMap()->processedCount());
// Check that we've reported on a conflict in widget_types.
$messages = [];
foreach ($migration->getIdMap()->getMessageIterator() as $message_row) {
$messages[] = $message_row->message;
}
$this->assertIdentical(count($messages), 1);
$this->assertIdentical($messages[0], 'Widget types optionwidgets_onoff, text_textfield are used in Drupal 6 field instances: widget type optionwidgets_onoff applied to the Drupal 8 base field');
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\field\Tests\Migrate\d6;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
@ -16,52 +17,12 @@ use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
*/
class MigrateFieldWidgetSettingsTest extends MigrateDrupal6TestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'field',
'telephone',
'link',
'file',
'image',
'datetime',
'node',
'text',
);
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
entity_create('node_type', array('type' => 'test_page'))->save();
entity_create('node_type', array('type' => 'story'))->save();
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_field_instance' => array(
array(array('fieldname', 'page'), array('node', 'fieldname', 'page')),
),
'd6_field' => array(
array(array('field_test'), array('node', 'field_test')),
array(array('field_test_two'), array('node', 'field_test_two')),
array(array('field_test_three'), array('node', 'field_test_three')),
array(array('field_test_email'), array('node', 'field_test_email')),
array(array('field_test_link'), array('node', 'field_test_link')),
array(array('field_test_filefield'), array('node', 'field_test_filefield')),
array(array('field_test_imagefield'), array('node', 'field_test_imagefield')),
array(array('field_test_phone'), array('node', 'field_test_phone')),
array(array('field_test_date'), array('node', 'field_test_date')),
array(array('field_test_datestamp'), array('node', 'field_test_datestamp')),
array(array('field_test_datetime'), array('node', 'field_test_datetime')),
),
);
$this->prepareMigrations($id_mappings);
$this->executeMigration('d6_field_instance_widget_settings');
$this->migrateFields();
}
/**
@ -69,7 +30,7 @@ class MigrateFieldWidgetSettingsTest extends MigrateDrupal6TestBase {
*/
public function testWidgetSettings() {
// Test the config can be loaded.
$form_display = entity_load('entity_form_display', 'node.story.default');
$form_display = EntityFormDisplay::load('node.story.default');
$this->assertIdentical(FALSE, is_null($form_display), "Form display node.story.default loaded with config.");
// Text field.
@ -138,7 +99,6 @@ class MigrateFieldWidgetSettingsTest extends MigrateDrupal6TestBase {
$component = $form_display->getComponent('field_test_datetime');
$expected['weight'] = 12;
$this->assertIdentical($expected, $component);
}
}

View file

@ -24,11 +24,11 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal7TestBase {
public static $modules = [
'comment',
'datetime',
'entity_reference',
'file',
'image',
'link',
'node',
'taxonomy',
'telephone',
'text',
];
@ -38,7 +38,11 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal7TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('comment');
$this->installEntitySchema('taxonomy_term');
CommentType::create([
'id' => 'comment_node_page',
'label' => $this->randomMachineName(),
@ -64,7 +68,6 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal7TestBase {
'label' => $this->randomMachineName(),
])->save();
$this->installEntitySchema('node');
NodeType::create([
'type' => 'page',
'label' => $this->randomMachineName(),
@ -147,10 +150,12 @@ class MigrateFieldFormatterSettingsTest extends MigrateDrupal7TestBase {
->condition('field_name', 'body')
->execute();
$this->executeMigration('d7_field');
$this->executeMigration('d7_field_instance');
$this->executeMigration('d7_view_modes');
$this->executeMigration('d7_field_formatter_settings');
$this->executeMigrations([
'd7_field',
'd7_field_instance',
'd7_view_modes',
'd7_field_formatter_settings',
]);
}
/**

View file

@ -28,7 +28,6 @@ class MigrateFieldInstanceTest extends MigrateDrupal7TestBase {
static $modules = array(
'comment',
'datetime',
'entity_reference',
'file',
'image',
'link',
@ -51,8 +50,7 @@ class MigrateFieldInstanceTest extends MigrateDrupal7TestBase {
$this->createType('book');
$this->createType('forum');
$this->createType('test_content_type');
$this->executeMigration('d7_field');
$this->executeMigration('d7_field_instance');
$this->executeMigrations(['d7_field', 'd7_field_instance']);
}
/**

View file

@ -10,7 +10,6 @@ namespace Drupal\field\Tests\Migrate\d7;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase;
use Drupal\node\Entity\NodeType;
/**
* Migrate field widget settings.
@ -25,29 +24,18 @@ class MigrateFieldInstanceWidgetSettingsTest extends MigrateDrupal7TestBase {
* @var array
*/
public static $modules = array(
'comment',
'datetime',
'field',
'telephone',
'link',
'file',
'image',
'datetime',
'link',
'node',
'taxonomy',
'telephone',
'text',
);
/**
* Creates a node type.
*
* @param string $id
* The node type ID.
*/
protected function createNodeType($id) {
NodeType::create(array(
'type' => $id,
'label' => $this->randomString(),
))->save();
}
/**
* {@inheritdoc}
*/
@ -55,46 +43,17 @@ class MigrateFieldInstanceWidgetSettingsTest extends MigrateDrupal7TestBase {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('comment');
$this->installEntitySchema('taxonomy_term');
$this->installConfig(static::$modules);
$this->createNodeType('page');
$this->createNodeType('article');
$this->createNodeType('blog');
$this->createNodeType('book');
$this->createNodeType('forum');
$this->createNodeType('test_content_type');
// Add some id mappings for the dependent migrations.
$id_mappings = [
'd7_field' => [
[['comment', 'comment_body'], ['comment', 'comment_body']],
[['node', 'body'], ['node', 'body']],
[['node', 'field_tags'], ['node', 'field_tags']],
[['node', 'field_image'], ['node', 'field_image']],
[['node', 'taxonomy_forums'], ['node', 'taxonomy_forums']],
[['node', 'field_boolean'], ['node', 'field_boolean']],
[['node', 'field_email'], ['node', 'field_email']],
[['node', 'field_phone'], ['node', 'field_phone']],
[['node', 'field_date'], ['node', 'field_date']],
[['node', 'field_date_with_end_time'], ['node', 'field_date_with_end_time']],
[['node', 'field_file'], ['node', 'field_file']],
[['node', 'field_float'], ['node', 'field_float']],
[['node', 'field_images'], ['node', 'field_images']],
[['node', 'field_integer'], ['node', 'field_integer']],
[['node', 'field_link'], ['node', 'field_link']],
[['node', 'field_text_list'], ['node', 'field_text_list']],
[['node', 'field_integer_list'], ['node', 'field_integer_list']],
[['node', 'field_long_text'], ['node', 'field_long_text']],
[['node', 'field_term_reference'], ['node', 'field_term_reference']],
[['node', 'field_text'], ['node', 'field_text']],
[['node', 'field_integer'], ['node', 'field_integer']],
[['user', 'field_file'], ['user', 'field_file']],
],
// We don't actually need any ID lookups from the d7_field_instance
// migration -- it's merely a sensible dependency.
'd7_field_instance' => [],
];
$this->prepareMigrations($id_mappings);
$this->executeMigration('d7_field_instance_widget_settings');
$this->executeMigrations([
'd7_node_type',
'd7_comment_type',
'd7_field',
'd7_field_instance',
'd7_field_instance_widget_settings',
]);
}
/**
@ -143,7 +102,7 @@ class MigrateFieldInstanceWidgetSettingsTest extends MigrateDrupal7TestBase {
$this->assertEntity('node.article.default', 'node', 'article');
$this->assertComponent('node.article.default', 'body', 'text_textarea_with_summary', -4);
$this->assertComponent('node.article.default', 'field_tags', 'taxonomy_autocomplete', -4);
$this->assertComponent('node.article.default', 'field_tags', 'entity_reference_autocomplete', -4);
$this->assertComponent('node.article.default', 'field_image', 'image_image', -1);
$this->assertEntity('node.blog.default', 'node', 'blog');
@ -169,7 +128,7 @@ class MigrateFieldInstanceWidgetSettingsTest extends MigrateDrupal7TestBase {
$this->assertComponent('node.test_content_type.default', 'field_integer_list', 'options_buttons', 12);
$this->assertComponent('node.test_content_type.default', 'field_long_text', 'text_textarea_with_summary', 13);
$this->assertComponent('node.test_content_type.default', 'field_phone', 'telephone_default', 6);
$this->assertComponent('node.test_content_type.default', 'field_term_reference', 'taxonomy_autocomplete', 14);
$this->assertComponent('node.test_content_type.default', 'field_term_reference', 'entity_reference_autocomplete', 14);
$this->assertComponent('node.test_content_type.default', 'field_text', 'text_textfield', 15);
$this->assertComponent('node.test_content_type.default', 'field_text_list', 'options_select', 11);
}

View file

@ -9,6 +9,7 @@ namespace Drupal\field\Tests\Migrate\d7;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase;
/**
@ -26,7 +27,6 @@ class MigrateFieldTest extends MigrateDrupal7TestBase {
static $modules = array(
'comment',
'datetime',
'entity_reference',
'file',
'image',
'link',
@ -106,6 +106,18 @@ class MigrateFieldTest extends MigrateDrupal7TestBase {
$this->assertEntity('node.field_phone', 'telephone', FALSE, 1);
$this->assertEntity('node.field_date', 'datetime', FALSE, 1);
$this->assertEntity('node.field_date_with_end_time', 'datetime', FALSE, 1);
// Assert that the taxonomy term reference fields are referencing the
// correct entity type.
$field = FieldStorageConfig::load('node.field_term_reference');
$this->assertIdentical('taxonomy_term', $field->getSetting('target_type'));
$field = FieldStorageConfig::load('node.taxonomy_forums');
$this->assertIdentical('taxonomy_term', $field->getSetting('target_type'));
// Validate that the source count and processed count match up.
/** @var \Drupal\migrate\Entity\MigrationInterface $migration */
$migration = Migration::load('d7_field');
$this->assertIdentical($migration->getSourcePlugin()->count(), $migration->getIdMap()->processedCount());
}
}

View file

@ -145,7 +145,7 @@ class NumberFieldTest extends WebTestBase {
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'settings' => array(
'min' => $minimum, 'max' => $maximum,
'min' => $minimum, 'max' => $maximum, 'prefix' => 'ThePrefix',
)
))->save();
@ -160,6 +160,9 @@ class NumberFieldTest extends WebTestBase {
entity_get_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, array(
'type' => 'number_integer',
'settings' => array(
'prefix_suffix' => FALSE,
),
))
->save();
@ -217,6 +220,14 @@ class NumberFieldTest extends WebTestBase {
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be lower than or equal to %maximum.', array('%name' => $field_name, '%maximum' => $maximum)), 'Correctly failed to save integer value greater than maximum allowed value.');
// Try to set a wrong integer value.
$this->drupalGet('entity_test/add');
$edit = array(
"{$field_name}[0][value]" => '20-40',
);
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', array('%name' => $field_name)), 'Correctly failed to save wrong integer value.');
// Test with valid entries.
$valid_entries = array(
'-1234',
@ -234,7 +245,29 @@ class NumberFieldTest extends WebTestBase {
$id = $match[1];
$this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
$this->assertRaw($valid_entry, 'Value is displayed.');
$this->assertNoFieldByXpath('//div[@content="' . $valid_entry . '"]', NULL, 'The "content" attribute is not present since the Prefix is not being displayed');
}
// Test for the content attribute when a Prefix is displayed. Presumably this also tests for the attribute when a Suffix is displayed.
entity_get_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, array(
'type' => 'number_integer',
'settings' => array(
'prefix_suffix' => TRUE,
),
))
->save();
$integer_value = '123';
$this->drupalGet('entity_test/add');
$edit = array(
"{$field_name}[0][value]" => $integer_value,
);
$this->drupalPostForm(NULL, $edit, t('Save'));
preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
$id = $match[1];
$this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
$this->drupalGet('entity_test/' . $id);
$this->assertFieldByXPath('//div[@content="' . $integer_value . '"]', 'ThePrefix' . $integer_value, 'The "content" attribute has been set to the value of the field, and the prefix is being displayed.');
}
/**

View file

@ -53,6 +53,9 @@ class NumberItemTest extends FieldUnitTestBase {
$entity->field_integer = $integer;
$float = 3.14;
$entity->field_float = $float;
$entity->field_decimal = '20-40';
$violations = $entity->validate();
$this->assertIdentical(1, count($violations), 'Wrong decimal value causes validation error');
$decimal = '31.3';
$entity->field_decimal = $decimal;
$entity->name->value = $this->randomMachineName();

View file

@ -22,7 +22,7 @@ class StringFieldTest extends WebTestBase {
*
* @var array
*/
public static $modules = array('entity_test');
public static $modules = array('entity_test', 'file');
/**
* A user without any special permissions.
@ -81,7 +81,7 @@ class StringFieldTest extends WebTestBase {
$this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
$this->assertNoFieldByName("{$field_name}[0][format]", '1', 'Format selector is not displayed');
$this->assertRaw(format_string('placeholder="A placeholder on !widget_type"', array('!widget_type' => $widget_type)));
$this->assertRaw(format_string('placeholder="A placeholder on @widget_type"', array('@widget_type' => $widget_type)));
// Submit with some value.
$value = $this->randomMachineName();

View file

@ -46,13 +46,19 @@ class UuidFormatterTest extends KernelTestBase {
$uuid_field = $entity->get('uuid');
// Verify default render.
$render_array = $uuid_field->view([]);
$this->assertIdentical($render_array[0]['#markup'], $entity->uuid(), 'The rendered UUID matches the entity UUID.');
$this->assertIdentical($render_array[0]['#context']['value'], $entity->uuid(), 'The rendered UUID matches the entity UUID.');
$this->assertTrue(strpos($this->render($render_array), $entity->uuid()), 'The rendered UUID found.');
// Verify customized render.
$render_array = $uuid_field->view(['settings' => ['link_to_entity' => TRUE]]);
$this->assertIdentical($render_array[0]['#type'], 'link');
$this->assertIdentical($render_array[0]['#title']['#markup'], $entity->uuid());
$this->assertIdentical($render_array[0]['#title']['#context']['value'], $entity->uuid());
$this->assertIdentical($render_array[0]['#url']->toString(), $entity->url());
$rendered = $this->render($render_array);
$this->assertTrue(strpos($rendered, $entity->uuid()), 'The rendered UUID found.');
$this->assertTrue(strpos($rendered, $entity->url()), 'The rendered entity URL found.');
}
}

View file

@ -124,7 +124,8 @@ class TranslationTest extends FieldUnitTestBase {
$entity->langcode->value = reset($available_langcodes);
foreach ($available_langcodes as $langcode) {
$field_translations[$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality());
$entity->getTranslation($langcode)->{$this->fieldName}->setValue($field_translations[$langcode]);
$translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode);
$translation->{$this->fieldName}->setValue($field_translations[$langcode]);
}
// Save and reload the field translations.
@ -160,7 +161,8 @@ class TranslationTest extends FieldUnitTestBase {
$entity = entity_create($entity_type_id, $values);
foreach ($translation_langcodes as $langcode) {
$values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality());
$entity->getTranslation($langcode, FALSE)->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]);
$translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode);
$translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]);
}
$field_langcodes = array_keys($entity->getTranslationLanguages());
@ -170,7 +172,7 @@ class TranslationTest extends FieldUnitTestBase {
// @todo Test every translation once the Entity Translation API allows for
// multilingual defaults.
$langcode = $entity->language()->getId();
$this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->default_value, format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
$this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->getDefaultValueLiteral(), format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
// Check that explicit empty values are not overridden with default values.
foreach (array(NULL, array()) as $empty_items) {
@ -178,8 +180,9 @@ class TranslationTest extends FieldUnitTestBase {
$entity = entity_create($entity_type_id, $values);
foreach ($translation_langcodes as $langcode) {
$values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality());
$entity->getTranslation($langcode)->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]);
$entity->getTranslation($langcode)->{$field_name_default}->setValue($empty_items);
$translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode);
$translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]);
$translation->{$field_name_default}->setValue($empty_items);
$values[$field_name_default][$langcode] = $empty_items;
}

View file

@ -104,7 +104,8 @@ class TranslationWebTest extends FieldTestBase {
ksort($available_langcodes);
$entity->langcode->value = key($available_langcodes);
foreach ($available_langcodes as $langcode => $value) {
$entity->getTranslation($langcode)->{$field_name}->value = $value + 1;
$translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode);
$translation->{$field_name}->value = $value + 1;
}
$entity->save();

View file

@ -0,0 +1,52 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\Update\EntityReferenceHandlerSettingUpdateTest.
*/
namespace Drupal\field\Tests\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
/**
* Tests the update for the entity reference 'handler' setting.
*
* @group field
*/
class EntityReferenceHandlerSettingUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
];
}
/**
* Tests field_post_update_entity_reference_handler_setting().
*
* @see field_post_update_entity_reference_handler_setting()
*/
public function testFieldPostUpdateERHandlerSetting() {
$configFactory = $this->container->get('config.factory');
// Load the 'node.article.field_image' field config, and check that its
// 'handler' setting is wrong.
/** @var \Drupal\Core\Config\Config */
$config = $configFactory->get('field.field.node.article.field_image');
$settings = $config->get('settings');
$this->assertEqual($settings['handler'], 'default:node');
// Run updates.
$this->runUpdates();
// Reload the config, and check that the 'handler' setting has been fixed.
$config = $configFactory->get('field.field.node.article.field_image');
$settings = $config->get('settings');
$this->assertEqual($settings['handler'], 'default:file');
}
}

View file

@ -0,0 +1,128 @@
<?php
/**
* @file
* Contains \Drupal\field\Tests\Update\FieldUpdateTest.
*/
namespace Drupal\field\Tests\Update;
use Drupal\Core\Config\Config;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
use Drupal\system\Tests\Update\UpdatePathTestBase;
/**
* Tests that field settings are properly updated during database updates.
*
* @group field
*/
class FieldUpdateTest extends UpdatePathTestBase {
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->configFactory = $this->container->get('config.factory');
}
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
__DIR__ . '/../../../tests/fixtures/update/drupal-8.views_entity_reference_plugins-2429191.php',
];
}
/**
* Tests field_update_8001().
*
* @see field_update_8001()
*/
public function testFieldUpdate8001() {
// Load the 'node.field_image' field storage config, and check that is has
// a 'target_bundle' setting.
$config = $this->configFactory->get('field.storage.node.field_image');
$settings = $config->get('settings');
$this->assertTrue(array_key_exists('target_bundle', $settings));
// Run updates.
$this->runUpdates();
// Reload the config, and check that the 'target_bundle' setting has been
// removed.
$config = $this->configFactory->get('field.storage.node.field_image');
$settings = $config->get('settings');
$this->assertFalse(array_key_exists('target_bundle', $settings));
}
/**
* Tests field_update_8002().
*
* @see field_update_8002()
*/
public function testFieldUpdate8002() {
// Check that 'entity_reference' is the provider and a dependency of the
// test field storage .
$field_storage = $this->configFactory->get('field.storage.node.field_ref_views_select_2429191');
$this->assertIdentical($field_storage->get('module'), 'entity_reference');
$this->assertEntityRefDependency($field_storage, TRUE);
// Check that 'entity_reference' is a dependency of the test field.
$field = $this->configFactory->get('field.field.node.article.field_ref_views_select_2429191');
$this->assertEntityRefDependency($field, TRUE);
// Check that 'entity_reference' is a dependency of the test view.
$view = $this->configFactory->get('views.view.entity_reference_plugins_2429191');
$this->assertEntityRefDependency($view, TRUE);
// Run updates.
$this->runUpdates();
// Check that 'entity_reference' is no longer a dependency of the test field
// and view.
$field_storage = $this->configFactory->get('field.storage.node.field_ref_views_select_2429191');
$this->assertIdentical($field_storage->get('module'), 'core');
$this->assertEntityRefDependency($field_storage, FALSE);
$field = $this->configFactory->get('field.field.node.article.field_ref_views_select_2429191');
$this->assertEntityRefDependency($field, FALSE);
$view = $this->configFactory->get('views.view.entity_reference_plugins_2429191');
$this->assertEntityRefDependency($view, FALSE);
// Check that field selection, based on the view, still works. It only
// selects nodes whose title contains 'foo'.
$node_1 = Node::create(['type' => 'article', 'title' => 'foobar']);
$node_1->save();
$node_2 = Node::create(['type' => 'article', 'title' => 'barbaz']);
$node_2->save();
$field = FieldConfig::load('node.article.field_ref_views_select_2429191');
$selection = \Drupal::service('plugin.manager.entity_reference_selection')->getSelectionHandler($field);
$referencable = $selection->getReferenceableEntities();
$this->assertEqual(array_keys($referencable['article']), [$node_1->id()]);
}
/**
* Asserts that a config depends on 'entity_reference' or not
*
* @param \Drupal\Core\Config\Config $config
* The config to test.
* @param bool $present
* TRUE to test that entity_reference is present, FALSE to test that it is
* absent.
*/
protected function assertEntityRefDependency(Config $config, $present) {
$dependencies = $config->get('dependencies');
$dependencies += ['module' => []];
$this->assertEqual(in_array('entity_reference', $dependencies['module']), $present);
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of https://www.drupal.org/node/2429191.
*/
use Drupal\Core\Database\Database;
use Drupal\Component\Serialization\Yaml;
$connection = Database::getConnection();
// Configuration for a View with an "entity_reference selection" display.
$config = Yaml::decode(file_get_contents(__DIR__ . '/views.view.entity_reference_plugins_2429191.yml'));
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'views.view.' . $config['id'],
'data' => serialize($config),
])
->execute();
// Configuration for an entity_reference field storage.
$config = Yaml::decode(file_get_contents(__DIR__ . '/field.storage.node.field_ref_views_select_2429191.yml'));
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'field.storage.' . $config['id'],
'data' => serialize($config),
])
->execute();
// We need to Update the registry of "last installed" field definitions.
$installed = $connection->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.definitions.installed')
->condition('name', 'node.field_storage_definitions')
->execute()
->fetchField();
$installed = unserialize($installed);
$installed['field_ref_views_select_2429191'] = new \Drupal\field\Entity\FieldStorageConfig($config);
$connection->update('key_value')
->condition('collection', 'entity.definitions.installed')
->condition('name', 'node.field_storage_definitions')
->fields([
'value' => serialize($installed)
])
->execute();
// Configuration for an entity_reference field using the View for selection.
$config = Yaml::decode(file_get_contents(__DIR__ . '/field.field.node.article.field_ref_views_select_2429191.yml'));
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'field.field.' . $config['id'],
'data' => serialize($config),
])
->execute();

View file

@ -0,0 +1,27 @@
uuid: ac77b88d-dfa0-4b07-b700-ba50cb51f72a
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_ref_views_select_2429191
- node.type.article
module:
- entity_reference
id: node.article.field_ref_views_select_2429191
field_name: field_ref_views_select_2429191
entity_type: node
bundle: article
label: reference_views_select
description: ''
required: false
translatable: false
default_value: { }
default_value_callback: ''
settings:
handler: views
handler_settings:
view:
view_name: entity_reference_plugins_2429191
display_name: entity_reference_1
arguments: { }
field_type: entity_reference

View file

@ -0,0 +1,19 @@
uuid: 7f5e9177-56b3-4b84-a936-54bfd4d4c078
langcode: en
status: true
dependencies:
module:
- entity_reference
- node
id: node.field_ref_views_select_2429191
field_name: field_ref_views_select_2429191
entity_type: node
type: entity_reference
settings:
target_type: node
module: entity_reference
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false

View file

@ -0,0 +1,214 @@
uuid: 8b3d9ae1-c8f9-4219-af35-53f687e6081b
langcode: en
status: true
dependencies:
module:
- entity_reference
- node
- user
id: entity_reference_plugins_2429191
label: test
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' previous'
next: 'next '
first: '« first'
last: 'last »'
quantity: 9
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
entity_field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
type: string
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
filters:
status:
value: true
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: contains
value: foo
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
multiple: false
remember: false
entity_type: node
entity_field: title
plugin_id: string
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
entity_reference_1:
display_plugin: entity_reference
id: entity_reference_1
display_title: 'Entity Reference'
position: 1
display_options:
display_extenders: { }
style:
type: entity_reference
options:
search_fields:
title: title
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- 'user.node_grants:view'
- user.permissions
tags: { }

View file

@ -40,6 +40,12 @@ field.widget.settings.test_field_widget:
test_widget_setting:
type: string
label: 'Test setting'
role:
type: string
label: 'A referenced role'
role2:
type: string
label: 'A 2nd referenced role'
field.widget.settings.test_field_widget_multiple:
type: mapping
@ -49,6 +55,14 @@ field.widget.settings.test_field_widget_multiple:
type: string
label: 'Test setting'
field.widget.third_party.color:
type: mapping
label: 'Field test entity display color module third party settings'
mapping:
foo:
type: string
label: 'Foo setting'
field.storage_settings.test_field:
type: mapping
label: 'Test field storage settings'

View file

@ -38,7 +38,7 @@ class TestFieldApplicableFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
return array('#markup' => 'Nothing to see here');
}
}

View file

@ -62,7 +62,7 @@ class TestFieldDefaultFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
foreach ($items as $delta => $item) {

View file

@ -35,7 +35,7 @@ class TestFieldEmptyFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
if ($items->isEmpty()) {

View file

@ -63,7 +63,7 @@ class TestFieldEmptySettingFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
if (!empty($items)) {

View file

@ -63,7 +63,7 @@ class TestFieldMultipleFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
if (!empty($items)) {

View file

@ -27,7 +27,7 @@ class TestFieldNoSettingsFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
foreach ($items as $delta => $item) {

View file

@ -75,7 +75,7 @@ class TestFieldPrepareViewFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = array();
foreach ($items as $delta => $item) {

View file

@ -34,6 +34,8 @@ class TestFieldWidget extends WidgetBase {
public static function defaultSettings() {
return array(
'test_widget_setting' => 'dummy test string',
'role' => 'anonymous',
'role2' => 'anonymous',
) + parent::defaultSettings();
}
@ -78,4 +80,42 @@ class TestFieldWidget extends WidgetBase {
return $element['value'];
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
foreach (['role', 'role2'] as $setting) {
if (!empty($role_id = $this->getSetting($setting))) {
// Create a dependency on the role config entity referenced in settings.
$dependencies['config'][] = "user.role.$role_id";
}
}
return $dependencies;
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
$changed = parent::onDependencyRemoval($dependencies);
// Only the setting 'role' is resolved here. When the dependency related to
// this setting is removed, is expected that the widget component will be
// update accordingly in the display entity. The 'role2' setting is
// deliberately left out from being updated. When the dependency
// corresponding to this setting is removed, is expected that the widget
// component will be disabled in the display entity.
if (!empty($role_id = $this->getSetting('role'))) {
if (!empty($dependencies['config']["user.role.$role_id"])) {
$this->setSetting('role', 'anonymous');
$changed = TRUE;
}
}
return $changed;
}
}

View file

@ -99,7 +99,7 @@ class TestFieldWidgetMultiple extends WidgetBase {
/**
* {@inheritdoc}
* Used in \Drupal\entity_reference\Tests\EntityReferenceAdminTest::testAvailableFormatters().
* Used in \Drupal\field\Tests\EntityReference\EntityReferenceAdminTest::testAvailableFormatters().
*/
public static function isApplicable(FieldDefinitionInterface $field_definition) {
// Returns FALSE if machine name of the field equals field_onewidgetfield.

View file

@ -17,3 +17,4 @@ dependencies:
- entity_test
- text
persist_with_no_fields: false
custom_storage: false

View file

@ -17,3 +17,4 @@ dependencies:
- entity_test
- text
persist_with_no_fields: false
custom_storage: false

View file

@ -1,10 +1,10 @@
id: entity_test.entity_test.field_test_import_staging
id: entity_test.entity_test.field_test_import_sync
uuid: ea711065-6940-47cd-813d-618f64095481
langcode: en
field_name: field_test_import_staging
field_name: field_test_import_sync
entity_type: entity_test
bundle: entity_test
label: 'Import from staging'
label: 'Import from sync'
description: ''
required: '0'
default_value: { }
@ -13,4 +13,4 @@ settings: { }
field_type: text
dependencies:
config:
- field.storage.entity_test.field_test_import_staging
- field.storage.entity_test.field_test_import_sync

View file

@ -1,7 +1,7 @@
id: entity_test.test_bundle.field_test_import_staging_2
id: entity_test.test_bundle.field_test_import_sync_2
uuid: f07794a2-d7cc-45b6-b40d-13cf021b5552
langcode: en
field_name: field_test_import_staging_2
field_name: field_test_import_sync_2
entity_type: entity_test
bundle: test_bundle
label: 'Test import field 2 on test bundle'
@ -13,4 +13,4 @@ settings: { }
field_type: text
dependencies:
config:
- field.storage.entity_test.field_test_import_staging_2
- field.storage.entity_test.field_test_import_sync_2

View file

@ -1,7 +1,7 @@
id: entity_test.test_bundle_2.field_test_import_staging_2
id: entity_test.test_bundle_2.field_test_import_sync_2
uuid: 49d6dd19-5097-443d-8f00-fc79525bebce
langcode: en
field_name: field_test_import_staging_2
field_name: field_test_import_sync_2
entity_type: entity_test
bundle: test_bundle_2
label: 'Test import field 2 on test bundle 2'
@ -13,4 +13,4 @@ settings: { }
field_type: text
dependencies:
config:
- field.storage.entity_test.field_test_import_staging_2
- field.storage.entity_test.field_test_import_sync_2

View file

@ -1,7 +1,7 @@
id: entity_test.field_test_import_staging
id: entity_test.field_test_import_sync
uuid: 0bf654cc-f14a-4881-b94c-76959e47466b
langcode: en
field_name: field_test_import_staging
field_name: field_test_import_sync
entity_type: entity_test
type: text
settings:
@ -18,3 +18,4 @@ dependencies:
- entity_test
- text
persist_with_no_fields: false
custom_storage: false

View file

@ -1,7 +1,7 @@
id: entity_test.field_test_import_staging_2
id: entity_test.field_test_import_sync_2
uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00
langcode: en
field_name: field_test_import_staging_2
field_name: field_test_import_sync_2
entity_type: entity_test
type: text
settings:
@ -18,3 +18,4 @@ dependencies:
- entity_test
- text
persist_with_no_fields: false
custom_storage: false

View file

@ -1,6 +1,6 @@
name: 'User test views'
name: 'Field test views'
type: module
description: 'Provides default views for views user tests.'
description: 'Provides default views for views field tests.'
package: Testing
version: VERSION
core: 8.x

View file

@ -0,0 +1,52 @@
langcode: en
status: true
dependencies:
module:
- node
- user
config:
- field.storage.node.field_test
id: test_view_field_delete
label: test_view_field_delete
module: views
description: ''
tag: default
base_table: node
base_field: nid
core: '8'
display:
default:
display_options:
access:
type: perm
fields:
nid:
field: nid
id: nid
table: node
plugin_id: field
entity_type: node
entity_field: nid
field_test:
id: field_test
table: node__field_test
field: field_test
plugin_id: field
entity_type: node
entity_field: field_test
cache:
type: tag
exposed_form:
type: basic
pager:
type: full
query:
type: views_query
style:
type: default
row:
type: fields
display_plugin: default
display_title: Master
id: default
position: 0

View file

@ -153,7 +153,7 @@ class FieldConfigEntityUnitTest extends UnitTestCase {
'bundle' => 'test_bundle',
'field_type' => 'test_field',
), $this->entityTypeId);
$dependencies = $field->calculateDependencies();
$dependencies = $field->calculateDependencies()->getDependencies();
$this->assertContains('field.storage.test_entity_type.test_field', $dependencies['config']);
$this->assertContains('test.test_entity_type.id', $dependencies['config']);
$this->assertEquals(['test_module', 'test_module2', 'test_module3'], $dependencies['module']);

View file

@ -8,6 +8,9 @@
namespace Drupal\Tests\field\Unit;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\UnitTestCase;
@ -39,16 +42,25 @@ class FieldStorageConfigEntityUnitTest extends UnitTestCase {
*/
protected $uuid;
/**
* The field type manager.
*
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $fieldTypeManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
$this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
$this->fieldTypeManager = $this->getMock(FieldTypePluginManagerInterface::class);
$container = new ContainerBuilder();
$container->set('entity.manager', $this->entityManager);
$container->set('uuid', $this->uuid);
$container->set('plugin.manager.field.field_type', $this->fieldTypeManager);
\Drupal::setContainer($container);
}
@ -73,29 +85,50 @@ class FieldStorageConfigEntityUnitTest extends UnitTestCase {
// ConfigEntityBase::addDependency() to get the provider of the field config
// entity type and once in FieldStorageConfig::calculateDependencies() to
// get the provider of the entity type that field is attached to.
$this->entityManager->expects($this->at(0))
$this->entityManager->expects($this->any())
->method('getDefinition')
->with('field_storage_config')
->will($this->returnValue($fieldStorageConfigentityType));
$this->entityManager->expects($this->at(1))
->method('getDefinition')
->with($attached_entity_type_id)
->will($this->returnValue($attached_entity_type));
$this->entityManager->expects($this->at(2))
->method('getDefinition')
->with('field_storage_config')
->will($this->returnValue($fieldStorageConfigentityType));
->willReturnMap([
['field_storage_config', TRUE, $fieldStorageConfigentityType],
[$attached_entity_type_id, TRUE, $attached_entity_type],
]);
$field_storage = new FieldStorageConfig(array(
$this->fieldTypeManager->expects($this->atLeastOnce())
->method('getDefinition')
->with('test_field_type', FALSE)
->willReturn([
'class' => TestFieldType::class,
]);
$field_storage = new FieldStorageConfig([
'entity_type' => $attached_entity_type_id,
'field_name' => 'test_field',
'type' => 'test_field_type',
'module' => 'test_module',
));
]);
$dependencies = $field_storage->calculateDependencies();
$this->assertContains('test_module', $dependencies['module']);
$this->assertContains('entity_provider_module', $dependencies['module']);
$dependencies = $field_storage->calculateDependencies()->getDependencies();
$this->assertEquals(['entity_provider_module', 'entity_test', 'test_module'], $dependencies['module']);
$this->assertEquals(['stark'], $dependencies['theme']);
}
}
/**
* A test class to test field storage dependencies.
*
* @see \Drupal\Core\Field\FieldItemInterface::calculateStorageDependencies()
*/
class TestFieldType {
/**
* {@inheritdoc}
*/
public static function calculateStorageDependencies(FieldStorageDefinitionInterface $field_definition) {
$dependencies = [];
$dependencies['module'] = ['entity_test'];
$dependencies['theme'] = ['stark'];
return $dependencies;
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\field\Unit;
use Drupal\simpletest\AssertHelperTrait;
use Drupal\Tests\UnitTestCase;
/**
@ -15,6 +16,8 @@ use Drupal\Tests\UnitTestCase;
*/
class FieldUninstallValidatorTest extends UnitTestCase {
use AssertHelperTrait;
/**
* @var \Drupal\field\FieldUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
*/
@ -43,7 +46,7 @@ class FieldUninstallValidatorTest extends UnitTestCase {
$module = $this->randomMachineName();
$expected = [];
$reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons);
$this->assertSame($expected, $this->castSafeStrings($reasons));
}
/**
@ -63,7 +66,7 @@ class FieldUninstallValidatorTest extends UnitTestCase {
$module = $this->randomMachineName();
$expected = ['Fields pending deletion'];
$reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons);
$this->assertSame($expected, $this->castSafeStrings($reasons));
}
/**
@ -83,7 +86,7 @@ class FieldUninstallValidatorTest extends UnitTestCase {
$module = $this->randomMachineName();
$expected = ['Fields type(s) in use'];
$reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons);
$this->assertSame($expected, $this->castSafeStrings($reasons));
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* @file
* Contains \Drupal\Tests\field\Unit\Plugin\migrate\source\d6\FieldInstancePerViewModeTest.
*/
namespace Drupal\Tests\field\Unit\Plugin\migrate\source\d6;
use Drupal\field\Plugin\migrate\source\d6\FieldInstancePerFormDisplay;
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
/**
* Tests d6_field_instance_per_form_display source plugin.
*
* @group field
*/
class FieldInstancePerFormDisplayTest extends MigrateSqlSourceTestCase {
const PLUGIN_CLASS = FieldInstancePerFormDisplay::class;
protected $migrationConfiguration = array(
'id' => 'view_mode_test',
'source' => array(
'plugin' => 'd6_field_instance_per_form_display',
),
);
protected $expectedResults = array(
array(
'display_settings' => array(),
'widget_settings' => array(),
'type_name' => 'story',
'widget_active' => TRUE,
'field_name' => 'field_test_filefield',
'type' => 'filefield',
'module' => 'filefield',
'weight' => '8',
'widget_type' => 'filefield_widget',
),
);
/**
* {@inheritdoc}
*/
protected function setUp() {
$empty_array = serialize([]);
$this->databaseContents['content_node_field'] = array(
array(
'field_name' => 'field_test_filefield',
'type' => 'filefield',
'global_settings' => $empty_array,
'required' => '0',
'multiple' => '0',
'db_storage' => '1',
'module' => 'filefield',
'db_columns' => $empty_array,
'active' => '1',
'locked' => '0',
)
);
$this->databaseContents['content_node_field_instance'] = array(
array(
'field_name' => 'field_test_filefield',
'type_name' => 'story',
'weight' => '8',
'label' => 'File Field',
'widget_type' => 'filefield_widget',
'widget_settings' => $empty_array,
'display_settings' => $empty_array,
'description' => 'An example image field.',
'widget_module' => 'filefield',
'widget_active' => '1',
),
);
parent::setUp();
}
}

View file

@ -16,13 +16,9 @@ use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
*/
class FieldInstancePerViewModeTest extends MigrateSqlSourceTestCase {
// The plugin system is not working during unit testing so the source plugin
// class needs to be manually specified.
const PLUGIN_CLASS = 'Drupal\field\Plugin\migrate\source\d6\FieldInstancePerViewMode';
// The fake Migration configuration entity.
protected $migrationConfiguration = array(
// The ID of the entity, can be any string.
'id' => 'view_mode_test',
'source' => array(
'plugin' => 'd6_field_instance_per_view_mode',
@ -76,7 +72,6 @@ class FieldInstancePerViewModeTest extends MigrateSqlSourceTestCase {
),
);
/**
* {@inheritdoc}
*/

View file

@ -69,7 +69,6 @@ class FieldTest extends MigrateSqlSourceTestCase {
$this->databaseContents['content_node_field'][0]['global_settings'] = serialize($this->databaseContents['content_node_field'][0]['global_settings']);
$this->databaseContents['content_node_field'][0]['db_columns'] = serialize($this->databaseContents['content_node_field'][0]['db_columns']);
$this->databaseContents['content_node_field_instance'][0]['widget_settings'] = serialize(array());
$this->databaseContents['content_node_field_instance'][0]['widget_type'] = 'text_textarea';
$this->databaseContents['content_node_field_instance'][0]['field_name'] = 'field_body';
parent::setUp();