updated core to 8.6.1 via composer

This commit is contained in:
2018-09-12 13:58:26 +02:00
parent a9a219f2ed
commit ea56b9fba3
4443 changed files with 112098 additions and 40708 deletions
@@ -15,6 +15,13 @@ use Drupal\field\FieldConfigInterface;
* @ConfigEntityType(
* id = "field_config",
* label = @Translation("Field"),
* label_collection = @Translation("Fields"),
* label_singular = @Translation("field"),
* label_plural = @Translation("fields"),
* label_count = @PluralTranslation(
* singular = "@count field",
* plural = "@count fields",
* ),
* handlers = {
* "access" = "Drupal\field\FieldConfigAccessControlHandler",
* "storage" = "Drupal\field\FieldConfigStorage"
@@ -2,7 +2,6 @@
namespace Drupal\field\Entity;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
@@ -18,6 +17,13 @@ use Drupal\field\FieldStorageConfigInterface;
* @ConfigEntityType(
* id = "field_storage_config",
* label = @Translation("Field storage"),
* label_collection = @Translation("Field storages"),
* label_singular = @Translation("field storage"),
* label_plural = @Translation("field storages"),
* label_count = @PluralTranslation(
* singular = "@count field storage",
* plural = "@count field storages",
* ),
* handlers = {
* "access" = "Drupal\field\FieldStorageConfigAccessControlHandler",
* "storage" = "Drupal\field\FieldStorageConfigStorage"
@@ -310,10 +316,10 @@ class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigI
// Assign the ID.
$this->id = $this->id();
// Field name cannot be longer than FieldStorageConfig::NAME_MAX_LENGTH characters.
// We use Unicode::strlen() because the DB layer assumes that column widths
// are given in characters rather than bytes.
if (Unicode::strlen($this->getName()) > static::NAME_MAX_LENGTH) {
// Field name cannot be longer than FieldStorageConfig::NAME_MAX_LENGTH
// characters. We use mb_strlen() because the DB layer assumes that column
// widths are given in characters rather than bytes.
if (mb_strlen($this->getName()) > static::NAME_MAX_LENGTH) {
throw new FieldException('Attempt to create a field storage with an name longer than ' . static::NAME_MAX_LENGTH . ' characters: ' . $this->getName());
}
@@ -2,6 +2,7 @@
namespace Drupal\field;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\Config\Config;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
@@ -56,9 +57,11 @@ class FieldConfigStorage extends FieldConfigStorageBase {
* The field type plugin manager.
* @param \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository
* The deleted fields repository.
* @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
* The memory cache.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository, MemoryCacheInterface $memory_cache) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $memory_cache);
$this->entityManager = $entity_manager;
$this->fieldTypeManager = $field_type_manager;
$this->deletedFieldsRepository = $deleted_fields_repository;
@@ -75,7 +78,8 @@ class FieldConfigStorage extends FieldConfigStorageBase {
$container->get('language_manager'),
$container->get('entity.manager'),
$container->get('plugin.manager.field.field_type'),
$container->get('entity_field.deleted_fields_repository')
$container->get('entity_field.deleted_fields_repository'),
$container->get('entity.memory_cache')
);
}
@@ -3,6 +3,7 @@
namespace Drupal\field;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
@@ -66,9 +67,11 @@ class FieldStorageConfigStorage extends ConfigEntityStorage {
* The field type plugin manager.
* @param \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository
* The deleted fields repository.
* @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
* The memory cache.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository, MemoryCacheInterface $memory_cache) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $memory_cache);
$this->entityManager = $entity_manager;
$this->moduleHandler = $module_handler;
$this->fieldTypeManager = $field_type_manager;
@@ -87,7 +90,8 @@ class FieldStorageConfigStorage extends ConfigEntityStorage {
$container->get('entity.manager'),
$container->get('module_handler'),
$container->get('plugin.manager.field.field_type'),
$container->get('entity_field.deleted_fields_repository')
$container->get('entity_field.deleted_fields_repository'),
$container->get('entity.memory_cache')
);
}
@@ -85,7 +85,6 @@ class FieldUninstallValidator implements ModuleUninstallValidatorInterface {
return $this->fieldStorageConfigStorage->loadByProperties(['module' => $module, 'include_deleted' => TRUE]);
}
/**
* Returns the label for a specified field type.
*
@@ -147,7 +147,7 @@ class ProcessField extends ProcessPluginBase implements ContainerFactoryPluginIn
$plugin_id = $field_plugin_manager->getPluginIdFromFieldType($field_type, [], $this->migration);
$plugin_instance = $field_plugin_manager->createInstance($plugin_id, [], $this->migration);
if (!is_callable([$plugin_instance, $method])) {
throw new MigrateException('The specified method does not exists or is not callable.');
throw new MigrateException('The specified method does not exist or is not callable.');
}
return call_user_func_array([$plugin_instance, $method], [$row]);
}
@@ -28,17 +28,7 @@ class FieldInstanceDefaults extends ProcessPluginBase {
unset($default_value[0]['email']);
}
$default = [];
foreach ($default_value as $item) {
switch ($widget_type) {
// Add special processing here if needed.
default:
$default[] = $item;
}
}
return $default;
return $default_value;
}
}
@@ -34,6 +34,19 @@ class Field extends DrupalSqlBase {
->condition('fci.deleted', 0);
$query->join('field_config_instance', 'fci', 'fc.id = fci.field_id');
// If the Drupal 7 Title module is enabled, we don't want to migrate the
// fields it provides. The values of those fields will be migrated to the
// base fields they were replacing.
if ($this->moduleExists('title')) {
$title_fields = [
'title_field',
'name_field',
'description_field',
'subject_field',
];
$query->condition('fc.field_name', $title_fields, 'NOT IN');
}
return $query;
}
@@ -26,7 +26,7 @@ class FieldInstance extends DrupalSqlBase {
public function query() {
$query = $this->select('field_config_instance', 'fci')
->fields('fci')
->fields('fc', ['type'])
->fields('fc', ['type', 'translatable'])
->condition('fc.active', 1)
->condition('fc.storage_active', 1)
->condition('fc.deleted', 0)
@@ -42,6 +42,19 @@ class FieldInstance extends DrupalSqlBase {
}
}
// If the Drupal 7 Title module is enabled, we don't want to migrate the
// fields it provides. The values of those fields will be migrated to the
// base fields they were replacing.
if ($this->moduleExists('title')) {
$title_fields = [
'title_field',
'name_field',
'description_field',
'subject_field',
];
$query->condition('fc.field_name', $title_fields, 'NOT IN');
}
return $query;
}
@@ -102,12 +115,13 @@ class FieldInstance extends DrupalSqlBase {
$translatable = FALSE;
if ($row->getSourceProperty('entity_type') == 'node') {
$language_content_type_bundle = (int) $this->variableGet('language_content_type_' . $row->getSourceProperty('bundle'), 0);
// language_content_type_[bundle] may be
// - 0: no language support
// - 1: language assignment support
// - 2: node translation support
// - 4: entity translation support
if ($this->variableGet('language_content_type_' . $row->getSourceProperty('bundle'), 0) == 2) {
if ($language_content_type_bundle === 2 || ($language_content_type_bundle === 4 && $row->getSourceProperty('translatable'))) {
$translatable = TRUE;
}
}
@@ -1,131 +0,0 @@
<?php
namespace Drupal\field\Tests\Boolean;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
/**
* Tests the Boolean field formatter settings.
*
* @group field
*/
class BooleanFormatterSettingsTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field', 'field_ui', 'text', 'node', 'user'];
/**
* The name of the entity bundle that is created in the test.
*
* @var string
*/
protected $bundle;
/**
* The name of the Boolean field to use for testing.
*
* @var string
*/
protected $fieldName;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create a content type. Use Node because it has Field UI pages that work.
$type_name = Unicode::strtolower($this->randomMachineName(8)) . '_test';
$type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]);
$this->bundle = $type->id();
$admin_user = $this->drupalCreateUser(['access content', 'administer content types', 'administer node fields', 'administer node display', 'bypass node access', 'administer nodes']);
$this->drupalLogin($admin_user);
$this->fieldName = Unicode::strtolower($this->randomMachineName(8));
$field_storage = FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'boolean',
]);
$field_storage->save();
$instance = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $this->bundle,
'label' => $this->randomMachineName(),
]);
$instance->save();
$display = entity_get_display('node', $this->bundle, 'default')
->setComponent($this->fieldName, [
'type' => 'boolean',
'settings' => [],
]);
$display->save();
}
/**
* Tests the formatter settings page for the Boolean formatter.
*/
public function testBooleanFormatterSettings() {
// List the options we expect to see on the settings form. Omit the one
// with the Unicode check/x characters, which does not appear to work
// well in WebTestBase.
$options = [
'Yes / No',
'True / False',
'On / Off',
'Enabled / Disabled',
'1 / 0',
'Custom',
];
// Define what the "default" option should look like, depending on the
// field settings.
$default = 'Field settings (@on / @off)';
// For several different values of the field settings, test that the
// options, including default, are shown correctly.
$settings = [
['Yes', 'No'],
['On', 'Off'],
['TRUE', 'FALSE'],
];
foreach ($settings as $values) {
// Set up the field settings.
$this->drupalGet('admin/structure/types/manage/' . $this->bundle . '/fields/node.' . $this->bundle . '.' . $this->fieldName);
$this->drupalPostForm(NULL, [
'settings[on_label]' => $values[0],
'settings[off_label]' => $values[1],
], 'Save settings');
// Open the Manage Display page and trigger the field settings form.
$this->drupalGet('admin/structure/types/manage/' . $this->bundle . '/display');
$this->drupalPostAjaxForm(NULL, [], $this->fieldName . '_settings_edit');
// Test that the settings options are present in the correct format.
foreach ($options as $string) {
$this->assertText($string);
}
$this->assertText(SafeMarkup::format($default, ['@on' => $values[0], '@off' => $values[1]]));
}
foreach ($settings as $values) {
$this->drupalGet('admin/structure/types/manage/' . $this->bundle . '/display');
$result = $this->xpath('//div[contains(@class, :class) and contains(text(), :text)]', [':class' => 'field-plugin-summary', ':text' => 'Display: TRUE / FALSE']);
$this->assertEqual(count($result), 1, "Boolean formatter settings summary exist.");
}
}
}
@@ -1,107 +0,0 @@
<?php
namespace Drupal\field\Tests\Email;
use Drupal\Component\Utility\Unicode;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\simpletest\WebTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests email field functionality.
*
* @group field
*/
class EmailFieldTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'entity_test', 'field_ui'];
/**
* A field storage to use in this test class.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field used in this test class.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser([
'view test entity',
'administer entity_test content',
'administer content types',
]));
}
/**
* Tests email field.
*/
public function testEmailField() {
// Create a field with settings to validate.
$field_name = Unicode::strtolower($this->randomMachineName());
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'email',
]);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'entity_test',
]);
$this->field->save();
// Create a form display for the default form mode.
entity_get_form_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'email_default',
'settings' => [
'placeholder' => 'example@example.com',
],
])
->save();
// Create a display for the full view mode.
entity_get_display('entity_test', 'entity_test', 'full')
->setComponent($field_name, [
'type' => 'email_mailto',
])
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget found.');
$this->assertRaw('placeholder="example@example.com"');
// Submit a valid email address and ensure it is accepted.
$value = 'test@example.com';
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]));
$this->assertRaw($value);
// Verify that a mailto link is displayed.
$entity = EntityTest::load($id);
$display = entity_get_display($entity->getEntityTypeId(), $entity->bundle(), 'full');
$content = $display->build($entity);
$this->setRawContent(\Drupal::service('renderer')->renderRoot($content));
$this->assertLinkByHref('mailto:test@example.com');
}
}
@@ -2,7 +2,6 @@
namespace Drupal\field\Tests\EntityReference;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field_ui\Tests\FieldUiTestTrait;
@@ -294,7 +293,7 @@ class EntityReferenceAdminTest extends WebTestBase {
$edit = [
'title[0][value]' => 'Example',
'field_test_entity_ref_field[0][target_id]' => 'Test'
'field_test_entity_ref_field[0][target_id]' => 'Test',
];
$this->drupalPostForm('node/add/' . $this->type, $edit, t('Save'));
@@ -303,7 +302,7 @@ class EntityReferenceAdminTest extends WebTestBase {
$edit = [
'title[0][value]' => 'Test',
'field_test_entity_ref_field[0][target_id]' => $node1->getTitle()
'field_test_entity_ref_field[0][target_id]' => $node1->getTitle(),
];
$this->drupalPostForm('node/add/' . $this->type, $edit, t('Save'));
@@ -316,7 +315,7 @@ class EntityReferenceAdminTest extends WebTestBase {
$edit = [
'title[0][value]' => 'Test',
'field_test_entity_ref_field[0][target_id]' => $node1->getTitle() . ' (' . $node1->id() . ')'
'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());
@@ -424,7 +423,7 @@ class EntityReferenceAdminTest extends WebTestBase {
/** @var \Drupal\taxonomy\Entity\Vocabulary[] $vocabularies */
$vocabularies = [];
for ($i = 0; $i < 2; $i++) {
$vid = Unicode::strtolower($this->randomMachineName());
$vid = mb_strtolower($this->randomMachineName());
$vocabularies[$i] = Vocabulary::create([
'name' => $this->randomString(),
'vid' => $vid,
@@ -1,128 +0,0 @@
<?php
namespace Drupal\field\Tests\EntityReference;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\simpletest\WebTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests an autocomplete widget with file upload.
*
* @group entity_reference
*/
class EntityReferenceFileUploadTest extends WebTestBase {
public static $modules = ['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 int
*/
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(['type' => $referenced->id()])->id();
FieldStorageConfig::create([
'field_name' => 'test_field',
'entity_type' => 'node',
'translatable' => FALSE,
'entity_types' => [],
'settings' => [
'target_type' => 'node',
],
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
])->save();
FieldConfig::create([
'label' => 'Entity reference field',
'field_name' => 'test_field',
'entity_type' => 'node',
'required' => TRUE,
'bundle' => $referencing->id(),
'settings' => [
'handler' => 'default',
'handler_settings' => [
// Reference a single vocabulary.
'target_bundles' => [
$referenced->id(),
],
],
],
])->save();
// Create a file field.
$file_field_name = 'file_field';
$field_storage = FieldStorageConfig::create([
'field_name' => $file_field_name,
'entity_type' => 'node',
'type' => 'file'
]);
$field_storage->save();
FieldConfig::create([
'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', [
'type' => 'entity_reference_autocomplete',
])
->setComponent($file_field_name, [
'type' => 'file_generic',
])
->save();
}
/**
* Tests that the autocomplete input element does not cause ajax fatal.
*/
public function testFileUpload() {
$user1 = $this->drupalCreateUser(['access content', "create $this->referencingType content"]);
$this->drupalLogin($user1);
$test_file = current($this->drupalGetTestFiles('text'));
$edit['files[file_field_0]'] = \Drupal::service('file_system')->realpath($test_file->uri);
$this->drupalPostForm('node/add/' . $this->referencingType, $edit, 'Upload');
$this->assertResponse(200);
$edit = [
'title[0][value]' => $this->randomMachineName(),
'test_field[0][target_id]' => $this->nodeId,
];
$this->drupalPostForm(NULL, $edit, 'Save');
$this->assertResponse(200);
}
}
@@ -1,17 +0,0 @@
<?php
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']];
}
}
@@ -1,89 +0,0 @@
<?php
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 = ['node', 'field_test', 'field_ui'];
/**
* The field name.
*
* @var string
*/
private $fieldName;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->fieldName = 'field_test';
// Create Article node types.
if ($this->profile != 'standard') {
$this->drupalCreateContentType([
'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.');
}
}
@@ -1,117 +0,0 @@
<?php
namespace Drupal\field\Tests;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Delete field storages and fields during config synchronization and uninstall
* module that provides the field type through the UI.
*
* @group field
* @see \Drupal\field\ConfigImporterFieldPurger
* @see field_config_import_steps_alter()
* @see field_form_config_admin_import_form_alter()
*/
class FieldImportDeleteUninstallUiTest extends FieldTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'telephone', 'config', 'filter', 'datetime'];
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser(['synchronize configuration']));
}
/**
* Tests deleting field storages and fields as part of config import.
*/
public function testImportDeleteUninstall() {
// Create a telephone field.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_tel',
'entity_type' => 'entity_test',
'type' => 'telephone',
]);
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'entity_test',
])->save();
// Create a text field.
$date_field_storage = FieldStorageConfig::create([
'field_name' => 'field_date',
'entity_type' => 'entity_test',
'type' => 'datetime',
]);
$date_field_storage->save();
FieldConfig::create([
'field_storage' => $date_field_storage,
'bundle' => 'entity_test',
])->save();
// Create an entity which has values for the telephone and text field.
$entity = EntityTest::create();
$value = '+0123456789';
$entity->field_tel = $value;
$entity->field_date = time();
$entity->name->value = $this->randomMachineName();
$entity->save();
// Delete the text field before exporting configuration so that we can test
// that deleted fields that are provided by modules that will be uninstalled
// are also purged and that the UI message includes such fields.
$date_field_storage->delete();
// Verify entity has been created properly.
$id = $entity->id();
$entity = EntityTest::load($id);
$this->assertEqual($entity->field_tel->value, $value);
$this->assertEqual($entity->field_tel[0]->value, $value);
$active = $this->container->get('config.storage');
$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']);
$sync->write('core.extension', $core_extension);
// Stage the field deletion
$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.
$this->assertText('This synchronization will delete data from the field entity_test.field_tel.');
// Stage an uninstall of the datetime module to test the message for
// multiple fields.
unset($core_extension['module']['datetime']);
$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.');
// This will purge all the data, delete the field and uninstall the
// Telephone and Text modules.
$this->drupalPostForm(NULL, [], t('Import all'));
$this->assertNoText('Field data will be deleted by this synchronization.');
$this->rebuildContainer();
$this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone'));
$this->assertFalse(\Drupal::entityManager()->loadEntityByUuid('field_storage_config', $field_storage->uuid()), 'The telephone field has been deleted by the configuration synchronization');
$deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: [];
$this->assertFalse(isset($deleted_storages[$field_storage->uuid()]), 'Telephone field has been completed removed from the system.');
$this->assertFalse(isset($deleted_storages[$field_storage->uuid()]), 'Text field has been completed removed from the system.');
}
}
-700
View File
@@ -1,700 +0,0 @@
<?php
namespace Drupal\field\Tests;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormState;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestBaseFieldDisplay;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests field form handling.
*
* @group field
*/
class FormTest extends FieldTestBase {
/**
* Modules to enable.
*
* Locale is installed so that TranslatableMarkup actually does something.
*
* @var array
*/
public static $modules = ['node', 'field_test', 'options', 'entity_test', 'locale'];
/**
* An array of values defining a field single.
*
* @var array
*/
protected $fieldStorageSingle;
/**
* An array of values defining a field multiple.
*
* @var array
*/
protected $fieldStorageMultiple;
/**
* An array of values defining a field with unlimited cardinality.
*
* @var array
*/
protected $fieldStorageUnlimited;
/**
* An array of values defining a field.
*
* @var array
*/
protected $field;
protected function setUp() {
parent::setUp();
$web_user = $this->drupalCreateUser(['view test entity', 'administer entity_test content']);
$this->drupalLogin($web_user);
$this->fieldStorageSingle = [
'field_name' => 'field_single',
'entity_type' => 'entity_test',
'type' => 'test_field',
];
$this->fieldStorageMultiple = [
'field_name' => 'field_multiple',
'entity_type' => 'entity_test',
'type' => 'test_field',
'cardinality' => 4,
];
$this->fieldStorageUnlimited = [
'field_name' => 'field_unlimited',
'entity_type' => 'entity_test',
'type' => 'test_field',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
];
$this->field = [
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'label' => $this->randomMachineName() . '_label',
'description' => '[site:name]_description',
'weight' => mt_rand(0, 127),
'settings' => [
'test_field_setting' => $this->randomMachineName(),
],
];
}
public function testFieldFormSingle() {
$field_storage = $this->fieldStorageSingle;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
// Create token value expected for description.
$token_description = Html::escape($this->config('system.site')->get('name')) . '_description';
$this->assertText($token_description, 'Token replacement for description is displayed');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
$this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
// Check that hook_field_widget_form_alter() does not believe this is the
// default value form.
$this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
// Check that hook_field_widget_form_alter() does not believe this is the
// default value form.
$this->assertNoText('From hook_field_widget_multivalue_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
// Submit with invalid value (field-level validation).
$edit = [
"{$field_name}[0][value]" => -1
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name does not accept the value -1.', ['%name' => $this->field['label']]), 'Field validation fails with invalid input.');
// TODO : check that the correct field is flagged for error.
// Create an entity
$value = mt_rand(1, 127);
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
$entity = EntityTest::load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
// Display edit form.
$this->drupalGet('entity_test/manage/' . $id . '/edit');
$this->assertFieldByName("{$field_name}[0][value]", $value, 'Widget is displayed with the correct default value');
$this->assertNoField("{$field_name}[1][value]", 'No extraneous widget is displayed');
// Update the entity.
$value = mt_rand(1, 127);
$edit = [
"{$field_name}[0][value]" => $value,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
$this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]);
$entity = EntityTest::load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
// Empty the field.
$value = '';
$edit = [
"{$field_name}[0][value]" => $value
];
$this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
$this->assertText(t('entity_test @id has been updated.', ['@id' => $id]), 'Entity was updated');
$this->container->get('entity.manager')->getStorage('entity_test')->resetCache([$id]);
$entity = EntityTest::load($id);
$this->assertTrue($entity->{$field_name}->isEmpty(), 'Field was emptied');
}
/**
* Tests field widget default values on entity forms.
*/
public function testFieldFormDefaultValue() {
$field_storage = $this->fieldStorageSingle;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
$default = rand(1, 127);
$this->field['default_value'] = [['value' => $default]];
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
// Test that the default value is displayed correctly.
$this->assertFieldByXpath("//input[@name='{$field_name}[0][value]' and @value='$default']");
// Try to submit an empty value.
$edit = [
"{$field_name}[0][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.', ['@id' => $id]), 'Entity was created.');
$entity = EntityTest::load($id);
$this->assertTrue($entity->{$field_name}->isEmpty(), 'Field is now empty.');
}
public function testFieldFormSingleRequired() {
$field_storage = $this->fieldStorageSingle;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
$this->field['required'] = TRUE;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Submit with missing required value.
$edit = [];
$this->drupalPostForm('entity_test/add', $edit, t('Save'));
$this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]), 'Required field with no value fails validation');
// Create an entity
$value = mt_rand(1, 127);
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
$entity = EntityTest::load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
// Edit with missing required value.
$value = '';
$edit = [
"{$field_name}[0][value]" => $value,
];
$this->drupalPostForm('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
$this->assertRaw(t('@name field is required.', ['@name' => $this->field['label']]), 'Required field with no value fails validation');
}
public function testFieldFormUnlimited() {
$field_storage = $this->fieldStorageUnlimited;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Display creation form -> 1 widget.
$this->drupalGet('entity_test/add');
$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, [], t('Add another item'));
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
$this->assertFieldByName("{$field_name}[1][value]", '', 'New widget is displayed');
$this->assertNoField("{$field_name}[2][value]", 'No extraneous widget is displayed');
// TODO : check that non-field inputs are preserved ('title'), etc.
// Yet another time so that we can play with more values -> 3 widgets.
$this->drupalPostForm(NULL, [], t('Add another item'));
// Prepare values and weights.
$count = 3;
$delta_range = $count - 1;
$values = $weights = $pattern = $expected_values = [];
$edit = [];
for ($delta = 0; $delta <= $delta_range; $delta++) {
// Assign unique random values and weights.
do {
$value = mt_rand(1, 127);
} while (in_array($value, $values));
do {
$weight = mt_rand(-$delta_range, $delta_range);
} while (in_array($weight, $weights));
$edit["{$field_name}[$delta][value]"] = $value;
$edit["{$field_name}[$delta][_weight]"] = $weight;
// We'll need three slightly different formats to check the values.
$values[$delta] = $value;
$weights[$delta] = $weight;
$field_values[$weight]['value'] = (string) $value;
$pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
}
// Press 'add more' button -> 4 widgets
$this->drupalPostForm(NULL, $edit, t('Add another item'));
for ($delta = 0; $delta <= $delta_range; $delta++) {
$this->assertFieldByName("{$field_name}[$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value");
$this->assertFieldByName("{$field_name}[$delta][_weight]", $weights[$delta], "Widget $delta has the right weight");
}
ksort($pattern);
$pattern = implode('.*', array_values($pattern));
$this->assertPattern("|$pattern|s", 'Widgets are displayed in the correct order');
$this->assertFieldByName("{$field_name}[$delta][value]", '', "New widget is displayed");
$this->assertFieldByName("{$field_name}[$delta][_weight]", $delta, "New widget has the right weight");
$this->assertNoField("{$field_name}[" . ($delta + 1) . '][value]', 'No extraneous widget is displayed');
// Submit the form and create the entity.
$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.', ['@id' => $id]), 'Entity was created');
$entity = EntityTest::load($id);
ksort($field_values);
$field_values = array_values($field_values);
$this->assertIdentical($entity->{$field_name}->getValue(), $field_values, 'Field values were saved in the correct order');
// Display edit form: check that the expected number of widgets is
// displayed, with correct values change values, reorder, leave an empty
// value in the middle.
// Submit: check that the entity is updated with correct values
// Re-submit: check that the field can be emptied.
// Test with several multiple fields in a form
}
/**
* Tests the position of the required label.
*/
public function testFieldFormUnlimitedRequired() {
$field_name = $this->fieldStorageUnlimited['field_name'];
$this->field['field_name'] = $field_name;
$this->field['required'] = TRUE;
FieldStorageConfig::create($this->fieldStorageUnlimited)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Display creation form -> 1 widget.
$this->drupalGet('entity_test/add');
// Check that the Required symbol is present for the multifield label.
$element = $this->xpath('//h4[contains(@class, "label") and contains(@class, "js-form-required") and contains(text(), :value)]', [':value' => $this->field['label']]);
$this->assertTrue(isset($element[0]), 'Required symbol added field label.');
// Check that the label of the field input is visually hidden and contains
// the field title and an indication of the delta for a11y.
$element = $this->xpath('//label[@for=:for and contains(@class, "visually-hidden") and contains(text(), :value)]', [':for' => 'edit-field-unlimited-0-value', ':value' => $this->field['label'] . ' (value 1)']);
$this->assertTrue(isset($element[0]), 'Required symbol not added for field input.');
}
/**
* Tests widget handling of multiple required radios.
*/
public function testFieldFormMultivalueWithRequiredRadio() {
// Create a multivalue test field.
$field_storage = $this->fieldStorageUnlimited;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name)
->save();
// Add a required radio field.
FieldStorageConfig::create([
'field_name' => 'required_radio_test',
'entity_type' => 'entity_test',
'type' => 'list_string',
'settings' => [
'allowed_values' => ['yes' => 'yes', 'no' => 'no'],
],
])->save();
$field = [
'field_name' => 'required_radio_test',
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'required' => TRUE,
];
FieldConfig::create($field)->save();
entity_get_form_display($field['entity_type'], $field['bundle'], 'default')
->setComponent($field['field_name'], [
'type' => 'options_buttons',
])
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
// Press the 'Add more' button.
$this->drupalPostForm(NULL, [], t('Add another item'));
// Verify that no error is thrown by the radio element.
$this->assertNoFieldByXpath('//div[contains(@class, "error")]', FALSE, 'No error message is displayed.');
// Verify that the widget is added.
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget 1 is displayed');
$this->assertFieldByName("{$field_name}[1][value]", '', 'New widget is displayed');
$this->assertNoField("{$field_name}[2][value]", 'No extraneous widget is displayed');
}
/**
* Tests widgets handling multiple values.
*/
public function testFieldFormMultipleWidget() {
// Create a field with fixed cardinality, configure the form to use a
// "multiple" widget.
$field_storage = $this->fieldStorageMultiple;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name, [
'type' => 'test_field_widget_multiple',
])
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertFieldByName($field_name, '', 'Widget is displayed.');
// Create entity with three values.
$edit = [
$field_name => '1, 2, 3',
];
$this->drupalPostForm(NULL, $edit, t('Save'));
preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
$id = $match[1];
// Check that the values were saved.
$entity_init = EntityTest::load($id);
$this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
// Display the form, check that the values are correctly filled in.
$this->drupalGet('entity_test/manage/' . $id . '/edit');
$this->assertFieldByName($field_name, '1, 2, 3', 'Widget is displayed.');
// Submit the form with more values than the field accepts.
$edit = [$field_name => '1, 2, 3, 4, 5'];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw('this field cannot hold more than 4 values', 'Form validation failed.');
// Check that the field values were not submitted.
$this->assertFieldValues($entity_init, $field_name, [1, 2, 3]);
}
/**
* Tests fields with no 'edit' access.
*/
public function testFieldFormAccess() {
$entity_type = 'entity_test_rev';
// Create a "regular" field.
$field_storage = $this->fieldStorageSingle;
$field_storage['entity_type'] = $entity_type;
$field_name = $field_storage['field_name'];
$field = $this->field;
$field['field_name'] = $field_name;
$field['entity_type'] = $entity_type;
$field['bundle'] = $entity_type;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($field)->save();
entity_get_form_display($entity_type, $entity_type, 'default')
->setComponent($field_name)
->save();
// Create a field with no edit access. See
// field_test_entity_field_access().
$field_storage_no_access = [
'field_name' => 'field_no_edit_access',
'entity_type' => $entity_type,
'type' => 'test_field',
];
$field_name_no_access = $field_storage_no_access['field_name'];
$field_no_access = [
'field_name' => $field_name_no_access,
'entity_type' => $entity_type,
'bundle' => $entity_type,
'default_value' => [0 => ['value' => 99]],
];
FieldStorageConfig::create($field_storage_no_access)->save();
FieldConfig::create($field_no_access)->save();
entity_get_form_display($field_no_access['entity_type'], $field_no_access['bundle'], 'default')
->setComponent($field_name_no_access)
->save();
// Test that the form structure includes full information for each delta
// apart from #access.
$entity = $this->container->get('entity_type.manager')
->getStorage($entity_type)
->create(['id' => 0, 'revision_id' => 0]);
$display = entity_get_form_display($entity_type, $entity_type, 'default');
$form = [];
$form_state = new FormState();
$display->buildForm($entity, $form, $form_state);
$this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');
// Display creation form.
$this->drupalGet($entity_type . '/add');
$this->assertNoFieldByName("{$field_name_no_access}[0][value]", '', 'Widget is not displayed if field access is denied.');
// Create entity.
$edit = [
"{$field_name}[0][value]" => 1,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
preg_match("|$entity_type/manage/(\d+)|", $this->url, $match);
$id = $match[1];
// Check that the default value was saved.
$storage = $this->container->get('entity_type.manager')
->getStorage($entity_type);
$entity = $storage->load($id);
$this->assertEqual($entity->$field_name_no_access->value, 99, 'Default value was saved for the field with no edit access.');
$this->assertEqual($entity->$field_name->value, 1, 'Entered value vas saved for the field with edit access.');
// Create a new revision.
$edit = [
"{$field_name}[0][value]" => 2,
'revision' => TRUE,
];
$this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
// Check that the new revision has the expected values.
$storage->resetCache([$id]);
$entity = $storage->load($id);
$this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
$this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
// Check that the revision is also saved in the revisions table.
$entity = $this->container->get('entity_type.manager')
->getStorage($entity_type)
->loadRevision($entity->getRevisionId());
$this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
$this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
}
/**
* Tests hiding a field in a form.
*/
public function testHiddenField() {
$entity_type = 'entity_test_rev';
$field_storage = $this->fieldStorageSingle;
$field_storage['entity_type'] = $entity_type;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
$this->field['default_value'] = [0 => ['value' => 99]];
$this->field['entity_type'] = $entity_type;
$this->field['bundle'] = $entity_type;
FieldStorageConfig::create($field_storage)->save();
$this->field = FieldConfig::create($this->field);
$this->field->save();
// We explicitly do not assign a widget in a form display, so the field
// stays hidden in forms.
// Display the entity creation form.
$this->drupalGet($entity_type . '/add');
// Create an entity and test that the default value is assigned correctly to
// the field that uses the hidden widget.
$this->assertNoField("{$field_name}[0][value]", 'The field does not appear in the form');
$this->drupalPostForm(NULL, [], t('Save'));
preg_match('|' . $entity_type . '/manage/(\d+)|', $this->url, $match);
$id = $match[1];
$this->assertText(t('entity_test_rev @id has been created.', ['@id' => $id]), 'Entity was created');
$storage = $this->container->get('entity_type.manager')
->getStorage($entity_type);
$entity = $storage->load($id);
$this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
// Update the field to remove the default value, and switch to the default
// widget.
$this->field->setDefaultValue([]);
$this->field->save();
entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
->setComponent($this->field->getName(), [
'type' => 'test_field_widget',
])
->save();
// Display edit form.
$this->drupalGet($entity_type . '/manage/' . $id . '/edit');
$this->assertFieldByName("{$field_name}[0][value]", 99, 'Widget is displayed with the correct default value');
// Update the entity.
$value = mt_rand(1, 127);
$edit = ["{$field_name}[0][value]" => $value];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertText(t('entity_test_rev @id has been updated.', ['@id' => $id]), 'Entity was updated');
$storage->resetCache([$id]);
$entity = $storage->load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
// Set the field back to hidden.
entity_get_form_display($entity_type, $this->field->getTargetBundle(), 'default')
->removeComponent($this->field->getName())
->save();
// Create a new revision.
$edit = ['revision' => TRUE];
$this->drupalPostForm($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
// Check that the expected value has been carried over to the new revision.
$storage->resetCache([$id]);
$entity = $storage->load($id);
$this->assertEqual($entity->{$field_name}->value, $value, 'New revision has the expected value for the field with the Hidden widget');
}
/**
* Tests the form display of the label for multi-value fields.
*/
public function testLabelOnMultiValueFields() {
$user = $this->drupalCreateUser(['administer entity_test content']);
$this->drupalLogin($user);
FieldStorageConfig::create([
'entity_type' => 'entity_test_base_field_display',
'field_name' => 'foo',
'type' => 'text',
'cardinality' => FieldStorageConfig::CARDINALITY_UNLIMITED,
])->save();
FieldConfig::create([
'entity_type' => 'entity_test_base_field_display',
'bundle' => 'bar',
'field_name' => 'foo',
// Set a dangerous label to test XSS filtering.
'label' => "<script>alert('a configurable field');</script>",
])->save();
EntityFormDisplay::create([
'targetEntityType' => 'entity_test_base_field_display',
'bundle' => 'bar',
'mode' => 'default',
])->setComponent('foo', ['type' => 'text_textfield'])->enable()->save();
$entity = EntityTestBaseFieldDisplay::create(['type' => 'bar']);
$entity->save();
$this->drupalGet('entity_test_base_field_display/manage/' . $entity->id());
$this->assertResponse(200);
$this->assertText('A field with multiple values');
// Test if labels were XSS filtered.
$this->assertEscaped("<script>alert('a configurable field');</script>");
}
/**
* Tests hook_field_widget_multivalue_form_alter().
*/
public function testFieldFormMultipleWidgetAlter() {
$this->widgetAlterTest('hook_field_widget_multivalue_form_alter', 'test_field_widget_multiple');
}
/**
* Tests hook_field_widget_multivalue_form_alter() with single value elements.
*/
public function testFieldFormMultipleWidgetAlterSingleValues() {
$this->widgetAlterTest('hook_field_widget_multivalue_form_alter', 'test_field_widget_multiple_single_value');
}
/**
* Tests hook_field_widget_multivalue_WIDGET_TYPE_form_alter().
*/
public function testFieldFormMultipleWidgetTypeAlter() {
$this->widgetAlterTest('hook_field_widget_multivalue_WIDGET_TYPE_form_alter', 'test_field_widget_multiple');
}
/**
* Tests hook_field_widget_multivalue_WIDGET_TYPE_form_alter() with single value elements.
*/
public function testFieldFormMultipleWidgetTypeAlterSingleValues() {
$this->widgetAlterTest('hook_field_widget_multivalue_WIDGET_TYPE_form_alter', 'test_field_widget_multiple_single_value');
}
/**
* Tests widget alter hooks for a given hook name.
*/
protected function widgetAlterTest($hook, $widget) {
// Create a field with fixed cardinality, configure the form to use a
// "multiple" widget.
$field_storage = $this->fieldStorageMultiple;
$field_name = $field_storage['field_name'];
$this->field['field_name'] = $field_name;
FieldStorageConfig::create($field_storage)->save();
FieldConfig::create($this->field)->save();
// Set a flag in state so that the hook implementations will run.
\Drupal::state()->set("field_test.widget_alter_test", [
'hook' => $hook,
'field_name' => $field_name,
'widget' => $widget,
]);
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($field_name, [
'type' => $widget,
])
->save();
$this->drupalGet('entity_test/add');
$this->assertUniqueText("From $hook(): prefix on $field_name parent element.");
if ($widget === 'test_field_widget_multiple_single_value') {
$suffix_text = "From $hook(): suffix on $field_name child element.";
$this->assertEqual($field_storage['cardinality'], substr_count($this->getTextContent(), $suffix_text), "'$suffix_text' was found {$field_storage['cardinality']} times using widget $widget");
}
}
}
@@ -1,195 +0,0 @@
<?php
namespace Drupal\field\Tests;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests field elements in nested forms.
*
* @group field
*/
class NestedFormTest extends FieldTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field_test', 'entity_test'];
protected function setUp() {
parent::setUp();
$web_user = $this->drupalCreateUser(['view test entity', 'administer entity_test content']);
$this->drupalLogin($web_user);
$this->fieldStorageSingle = [
'field_name' => 'field_single',
'entity_type' => 'entity_test',
'type' => 'test_field',
];
$this->fieldStorageUnlimited = [
'field_name' => 'field_unlimited',
'entity_type' => 'entity_test',
'type' => 'test_field',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
];
$this->field = [
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'label' => $this->randomMachineName() . '_label',
'description' => '[site:name]_description',
'weight' => mt_rand(0, 127),
'settings' => [
'test_field_setting' => $this->randomMachineName(),
],
];
}
/**
* Tests Field API form integration within a subform.
*/
public function testNestedFieldForm() {
// Add two fields on the 'entity_test'
FieldStorageConfig::create($this->fieldStorageSingle)->save();
FieldStorageConfig::create($this->fieldStorageUnlimited)->save();
$this->field['field_name'] = 'field_single';
$this->field['label'] = 'Single field';
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($this->field['field_name'])
->save();
$this->field['field_name'] = 'field_unlimited';
$this->field['label'] = 'Unlimited field';
FieldConfig::create($this->field)->save();
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
->setComponent($this->field['field_name'])
->save();
// Create two entities.
$entity_type = 'entity_test';
$storage = $this->container->get('entity_type.manager')
->getStorage($entity_type);
$entity_1 = $storage->create(['id' => 1]);
$entity_1->enforceIsNew();
$entity_1->field_single->value = 0;
$entity_1->field_unlimited->value = 1;
$entity_1->save();
$entity_2 = $storage->create(['id' => 2]);
$entity_2->enforceIsNew();
$entity_2->field_single->value = 10;
$entity_2->field_unlimited->value = 11;
$entity_2->save();
// Display the 'combined form'.
$this->drupalGet('test-entity/nested/1/2');
$this->assertFieldByName('field_single[0][value]', 0, 'Entity 1: field_single value appears correctly is the form.');
$this->assertFieldByName('field_unlimited[0][value]', 1, 'Entity 1: field_unlimited value 0 appears correctly is the form.');
$this->assertFieldByName('entity_2[field_single][0][value]', 10, 'Entity 2: field_single value appears correctly is the form.');
$this->assertFieldByName('entity_2[field_unlimited][0][value]', 11, 'Entity 2: field_unlimited value 0 appears correctly is the form.');
// Submit the form and check that the entities are updated accordingly.
$edit = [
'field_single[0][value]' => 1,
'field_unlimited[0][value]' => 2,
'field_unlimited[1][value]' => 3,
'entity_2[field_single][0][value]' => 11,
'entity_2[field_unlimited][0][value]' => 12,
'entity_2[field_unlimited][1][value]' => 13,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$entity_1 = $storage->load(1);
$entity_2 = $storage->load(2);
$this->assertFieldValues($entity_1, 'field_single', [1]);
$this->assertFieldValues($entity_1, 'field_unlimited', [2, 3]);
$this->assertFieldValues($entity_2, 'field_single', [11]);
$this->assertFieldValues($entity_2, 'field_unlimited', [12, 13]);
// Submit invalid values and check that errors are reported on the
// correct widgets.
$edit = [
'field_unlimited[1][value]' => -1,
];
$this->drupalPostForm('test-entity/nested/1/2', $edit, t('Save'));
$this->assertRaw(t('%label does not accept the value -1', ['%label' => 'Unlimited field']), 'Entity 1: the field validation error was reported.');
$error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', [':id' => 'edit-field-unlimited-1-value']);
$this->assertTrue($error_field, 'Entity 1: the error was flagged on the correct element.');
$edit = [
'entity_2[field_unlimited][1][value]' => -1,
];
$this->drupalPostForm('test-entity/nested/1/2', $edit, t('Save'));
$this->assertRaw(t('%label does not accept the value -1', ['%label' => 'Unlimited field']), 'Entity 2: the field validation error was reported.');
$error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', [':id' => 'edit-entity-2-field-unlimited-1-value']);
$this->assertTrue($error_field, 'Entity 2: the error was flagged on the correct element.');
// Test that reordering works on both entities.
$edit = [
'field_unlimited[0][_weight]' => 0,
'field_unlimited[1][_weight]' => -1,
'entity_2[field_unlimited][0][_weight]' => 0,
'entity_2[field_unlimited][1][_weight]' => -1,
];
$this->drupalPostForm('test-entity/nested/1/2', $edit, t('Save'));
$this->assertFieldValues($entity_1, 'field_unlimited', [3, 2]);
$this->assertFieldValues($entity_2, 'field_unlimited', [13, 12]);
// Test the 'add more' buttons. Only Ajax submission is tested, because
// the two 'add more' buttons present in the form have the same #value,
// which confuses drupalPostForm().
// 'Add more' button in the first entity:
$this->drupalGet('test-entity/nested/1/2');
$this->drupalPostAjaxForm(NULL, [], 'field_unlimited_add_more');
$this->assertFieldByName('field_unlimited[0][value]', 3, 'Entity 1: field_unlimited value 0 appears correctly is the form.');
$this->assertFieldByName('field_unlimited[1][value]', 2, 'Entity 1: field_unlimited value 1 appears correctly is the form.');
$this->assertFieldByName('field_unlimited[2][value]', '', 'Entity 1: field_unlimited value 2 appears correctly is the form.');
$this->assertFieldByName('field_unlimited[3][value]', '', 'Entity 1: an empty widget was added for field_unlimited value 3.');
// 'Add more' button in the first entity (changing field values):
$edit = [
'entity_2[field_unlimited][0][value]' => 13,
'entity_2[field_unlimited][1][value]' => 14,
'entity_2[field_unlimited][2][value]' => 15,
];
$this->drupalPostAjaxForm(NULL, $edit, 'entity_2_field_unlimited_add_more');
$this->assertFieldByName('entity_2[field_unlimited][0][value]', 13, 'Entity 2: field_unlimited value 0 appears correctly is the form.');
$this->assertFieldByName('entity_2[field_unlimited][1][value]', 14, 'Entity 2: field_unlimited value 1 appears correctly is the form.');
$this->assertFieldByName('entity_2[field_unlimited][2][value]', 15, 'Entity 2: field_unlimited value 2 appears correctly is the form.');
$this->assertFieldByName('entity_2[field_unlimited][3][value]', '', 'Entity 2: an empty widget was added for field_unlimited value 3.');
// Save the form and check values are saved correctly.
$this->drupalPostForm(NULL, [], t('Save'));
$this->assertFieldValues($entity_1, 'field_unlimited', [3, 2]);
$this->assertFieldValues($entity_2, 'field_unlimited', [13, 14, 15]);
}
/**
* Tests entity level validation within subforms.
*/
public function testNestedEntityFormEntityLevelValidation() {
// Create two entities.
$storage = $this->container->get('entity_type.manager')
->getStorage('entity_test_constraints');
$entity_1 = $storage->create();
$entity_1->save();
$entity_2 = $storage->create();
$entity_2->save();
// Display the 'combined form'.
$this->drupalGet("test-entity-constraints/nested/{$entity_1->id()}/{$entity_2->id()}");
$this->assertFieldByName('entity_2[changed]', 0, 'Entity 2: changed value appears correctly in the form.');
// Submit the form and check that the entities are updated accordingly.
$edit = ['entity_2[changed]' => REQUEST_TIME - 86400];
$this->drupalPostForm(NULL, $edit, t('Save'));
$elements = $this->cssSelect('.entity-2.error');
$this->assertEqual(1, count($elements), 'The whole nested entity form has been correctly flagged with an error class.');
}
}
@@ -1,562 +0,0 @@
<?php
namespace Drupal\field\Tests\Number;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
use Drupal\simpletest\WebTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests the creation of numeric fields.
*
* @group field
*/
class NumberFieldTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'entity_test', 'field_ui'];
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser([
'view test entity',
'administer entity_test content',
'administer content types',
'administer node fields',
'administer node display',
'bypass node access',
'administer entity_test fields',
]));
}
/**
* Test decimal field.
*/
public function testNumberDecimalField() {
// Create a field with settings to validate.
$field_name = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'decimal',
'settings' => ['precision' => 8, 'scale' => 4],
])->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
])->save();
entity_get_form_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number',
'settings' => [
'placeholder' => '0.00'
],
])
->save();
entity_get_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number_decimal',
])
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
$this->assertRaw('placeholder="0.00"');
// Submit a signed decimal value within the allowed precision and scale.
$value = '-1234.5678';
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
$this->assertRaw($value, 'Value is displayed.');
// Try to create entries with more than one decimal separator; assert fail.
$wrong_entries = [
'3.14.159',
'0..45469',
'..4589',
'6.459.52',
'6.3..25',
];
foreach ($wrong_entries as $wrong_entry) {
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $wrong_entry,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save decimal value with more than one decimal point.');
}
// Try to create entries with minus sign not in the first position.
$wrong_entries = [
'3-3',
'4-',
'1.3-',
'1.2-4',
'-10-10',
];
foreach ($wrong_entries as $wrong_entry) {
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $wrong_entry,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save decimal value with minus sign in the wrong position.');
}
}
/**
* Test integer field.
*/
public function testNumberIntegerField() {
$minimum = rand(-4000, -2000);
$maximum = rand(2000, 4000);
// Create a field with settings to validate.
$field_name = Unicode::strtolower($this->randomMachineName());
$storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'integer',
]);
$storage->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'settings' => [
'min' => $minimum,
'max' => $maximum,
'prefix' => 'ThePrefix',
],
])->save();
entity_get_form_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number',
'settings' => [
'placeholder' => '4'
],
])
->save();
entity_get_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number_integer',
'settings' => [
'prefix_suffix' => FALSE,
],
])
->save();
// Check the storage schema.
$expected = [
'columns' => [
'value' => [
'type' => 'int',
'unsigned' => '',
'size' => 'normal'
],
],
'unique keys' => [],
'indexes' => [],
'foreign keys' => []
];
$this->assertEqual($storage->getSchema(), $expected);
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
$this->assertRaw('placeholder="4"');
// Submit a valid integer
$value = rand($minimum, $maximum);
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
// Try to set a value below the minimum value
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $minimum - 1,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be higher than or equal to %minimum.', ['%name' => $field_name, '%minimum' => $minimum]), 'Correctly failed to save integer value less than minimum allowed value.');
// Try to set a decimal value
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => 1.5,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name is not a valid number.', ['%name' => $field_name]), 'Correctly failed to save decimal value to integer field.');
// Try to set a value above the maximum value
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $maximum + 1,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be lower than or equal to %maximum.', ['%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 = [
"{$field_name}[0][value]" => '20-40',
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save wrong integer value.');
// Test with valid entries.
$valid_entries = [
'-1234',
'0',
'1234',
];
foreach ($valid_entries as $valid_entry) {
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $valid_entry,
];
$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.', ['@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, [
'type' => 'number_integer',
'settings' => [
'prefix_suffix' => TRUE,
],
])
->save();
$integer_value = '123';
$this->drupalGet('entity_test/add');
$edit = [
"{$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.', ['@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.');
}
/**
* Test float field.
*/
public function testNumberFloatField() {
// Create a field with settings to validate.
$field_name = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'float',
])->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
])->save();
entity_get_form_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number',
'settings' => [
'placeholder' => '0.00'
],
])
->save();
entity_get_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => 'number_decimal',
])
->save();
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
$this->assertRaw('placeholder="0.00"');
// Submit a signed decimal value within the allowed precision and scale.
$value = '-1234.5678';
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
// Ensure that the 'number_decimal' formatter displays the number with the
// expected rounding.
$this->drupalGet('entity_test/' . $id);
$this->assertRaw(round($value, 2));
// Try to create entries with more than one decimal separator; assert fail.
$wrong_entries = [
'3.14.159',
'0..45469',
'..4589',
'6.459.52',
'6.3..25',
];
foreach ($wrong_entries as $wrong_entry) {
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $wrong_entry,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save float value with more than one decimal point.');
}
// Try to create entries with minus sign not in the first position.
$wrong_entries = [
'3-3',
'4-',
'1.3-',
'1.2-4',
'-10-10',
];
foreach ($wrong_entries as $wrong_entry) {
$this->drupalGet('entity_test/add');
$edit = [
"{$field_name}[0][value]" => $wrong_entry,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save float value with minus sign in the wrong position.');
}
}
/**
* Test default formatter behavior
*/
public function testNumberFormatter() {
$type = Unicode::strtolower($this->randomMachineName());
$float_field = Unicode::strtolower($this->randomMachineName());
$integer_field = Unicode::strtolower($this->randomMachineName());
$thousand_separators = ['', '.', ',', ' ', chr(8201), "'"];
$decimal_separators = ['.', ','];
$prefix = $this->randomMachineName();
$suffix = $this->randomMachineName();
$random_float = rand(0, pow(10, 6));
$random_integer = rand(0, pow(10, 6));
// Create a content type containing float and integer fields.
$this->drupalCreateContentType(['type' => $type]);
FieldStorageConfig::create([
'field_name' => $float_field,
'entity_type' => 'node',
'type' => 'float',
])->save();
FieldStorageConfig::create([
'field_name' => $integer_field,
'entity_type' => 'node',
'type' => 'integer',
])->save();
FieldConfig::create([
'field_name' => $float_field,
'entity_type' => 'node',
'bundle' => $type,
'settings' => [
'prefix' => $prefix,
'suffix' => $suffix
],
])->save();
FieldConfig::create([
'field_name' => $integer_field,
'entity_type' => 'node',
'bundle' => $type,
'settings' => [
'prefix' => $prefix,
'suffix' => $suffix
],
])->save();
entity_get_form_display('node', $type, 'default')
->setComponent($float_field, [
'type' => 'number',
'settings' => [
'placeholder' => '0.00'
],
])
->setComponent($integer_field, [
'type' => 'number',
'settings' => [
'placeholder' => '0.00'
],
])
->save();
entity_get_display('node', $type, 'default')
->setComponent($float_field, [
'type' => 'number_decimal',
])
->setComponent($integer_field, [
'type' => 'number_unformatted',
])
->save();
// Create a node to test formatters.
$node = Node::create([
'type' => $type,
'title' => $this->randomMachineName(),
$float_field => ['value' => $random_float],
$integer_field => ['value' => $random_integer],
]);
$node->save();
// Go to manage display page.
$this->drupalGet("admin/structure/types/manage/$type/display");
// Configure number_decimal formatter for the 'float' field type.
$thousand_separator = $thousand_separators[array_rand($thousand_separators)];
$decimal_separator = $decimal_separators[array_rand($decimal_separators)];
$scale = rand(0, 10);
$this->drupalPostAjaxForm(NULL, [], "${float_field}_settings_edit");
$edit = [
"fields[${float_field}][settings_edit_form][settings][prefix_suffix]" => TRUE,
"fields[${float_field}][settings_edit_form][settings][scale]" => $scale,
"fields[${float_field}][settings_edit_form][settings][decimal_separator]" => $decimal_separator,
"fields[${float_field}][settings_edit_form][settings][thousand_separator]" => $thousand_separator,
];
$this->drupalPostAjaxForm(NULL, $edit, "${float_field}_plugin_settings_update");
$this->drupalPostForm(NULL, [], t('Save'));
// Check number_decimal and number_unformatted formatters behavior.
$this->drupalGet('node/' . $node->id());
$float_formatted = number_format($random_float, $scale, $decimal_separator, $thousand_separator);
$this->assertRaw("$prefix$float_formatted$suffix", 'Prefix and suffix added');
$this->assertRaw((string) $random_integer);
// Configure the number_decimal formatter.
entity_get_display('node', $type, 'default')
->setComponent($integer_field, [
'type' => 'number_integer',
])
->save();
$this->drupalGet("admin/structure/types/manage/$type/display");
$thousand_separator = $thousand_separators[array_rand($thousand_separators)];
$this->drupalPostAjaxForm(NULL, [], "${integer_field}_settings_edit");
$edit = [
"fields[${integer_field}][settings_edit_form][settings][prefix_suffix]" => FALSE,
"fields[${integer_field}][settings_edit_form][settings][thousand_separator]" => $thousand_separator,
];
$this->drupalPostAjaxForm(NULL, $edit, "${integer_field}_plugin_settings_update");
$this->drupalPostForm(NULL, [], t('Save'));
// Check number_integer formatter behavior.
$this->drupalGet('node/' . $node->id());
$integer_formatted = number_format($random_integer, 0, '', $thousand_separator);
$this->assertRaw($integer_formatted, 'Random integer formatted');
}
/**
* Tests setting the minimum value of a float field through the interface.
*/
public function testCreateNumberFloatField() {
// Create a float field.
$field_name = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'float',
])->save();
$field = FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field->save();
// Set the minimum value to a float value.
$this->assertSetMinimumValue($field, 0.0001);
// Set the minimum value to an integer value.
$this->assertSetMinimumValue($field, 1);
}
/**
* Tests setting the minimum value of a decimal field through the interface.
*/
public function testCreateNumberDecimalField() {
// Create a decimal field.
$field_name = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'decimal',
])->save();
$field = FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field->save();
// Set the minimum value to a decimal value.
$this->assertSetMinimumValue($field, 0.1);
// Set the minimum value to an integer value.
$this->assertSetMinimumValue($field, 1);
}
/**
* Helper function to set the minimum value of a field.
*/
public function assertSetMinimumValue($field, $minimum_value) {
$field_configuration_url = 'entity_test/structure/entity_test/fields/entity_test.entity_test.' . $field->getName();
// Set the minimum value.
$edit = [
'settings[min]' => $minimum_value,
];
$this->drupalPostForm($field_configuration_url, $edit, t('Save settings'));
// Check if an error message is shown.
$this->assertNoRaw(t('%name is not a valid number.', ['%name' => t('Minimum')]), 'Saved ' . gettype($minimum_value) . ' value as minimal value on a ' . $field->getType() . ' field');
// Check if a success message is shown.
$this->assertRaw(t('Saved %label configuration.', ['%label' => $field->getLabel()]));
// Check if the minimum value was actually set.
$this->drupalGet($field_configuration_url);
$this->assertFieldById('edit-settings-min', $minimum_value, 'Minimal ' . gettype($minimum_value) . ' value was set on a ' . $field->getType() . ' field.');
}
}
@@ -1,102 +0,0 @@
<?php
namespace Drupal\field\Tests\String;
use Drupal\Component\Utility\Unicode;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\simpletest\WebTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests the creation of string fields.
*
* @group text
*/
class StringFieldTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'file'];
/**
* A user without any special permissions.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
protected function setUp() {
parent::setUp();
$this->webUser = $this->drupalCreateUser(['view test entity', 'administer entity_test content', 'access content']);
$this->drupalLogin($this->webUser);
}
// Test fields.
/**
* Test widgets.
*/
public function testTextfieldWidgets() {
$this->_testTextfieldWidgets('string', 'string_textfield');
$this->_testTextfieldWidgets('string_long', 'string_textarea');
}
/**
* Helper function for testTextfieldWidgets().
*/
public function _testTextfieldWidgets($field_type, $widget_type) {
// Create a field.
$field_name = Unicode::strtolower($this->randomMachineName());
$field_storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => $field_type
]);
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'entity_test',
'label' => $this->randomMachineName() . '_label',
])->save();
entity_get_form_display('entity_test', 'entity_test', 'default')
->setComponent($field_name, [
'type' => $widget_type,
'settings' => [
'placeholder' => 'A placeholder on ' . $widget_type,
],
])
->save();
entity_get_display('entity_test', 'entity_test', 'full')
->setComponent($field_name)
->save();
// Display creation form.
$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"', ['@widget_type' => $widget_type]));
// Submit with some value.
$value = $this->randomMachineName();
$edit = [
"{$field_name}[0][value]" => $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.', ['@id' => $id]), 'Entity was created');
// Display the entity.
$entity = EntityTest::load($id);
$display = entity_get_display($entity->getEntityTypeId(), $entity->bundle(), 'full');
$content = $display->build($entity);
$this->setRawContent(\Drupal::service('renderer')->renderRoot($content));
$this->assertText($value, 'Filtered tags are not displayed');
}
}
@@ -2,6 +2,8 @@
namespace Drupal\field\Tests\Views;
@trigger_error(__NAMESPACE__ . '\FieldTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\field\Functional\Views\FieldTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\views\Tests\ViewTestBase;
@@ -17,6 +19,11 @@ use Drupal\field\Entity\FieldStorageConfig;
* - Use basic fields and make sure that the full wanted object is built.
* - Use relationships between different entity types, for example node and
* the node author(user).
*
* @deprecated in Drupal 8.6.0. Will be removed before Drupal 9.0.0. Use
* \Drupal\Tests\field\Functional\Views\FieldTestBase instead.
*
* @see https://www.drupal.org/node/2989020
*/
abstract class FieldTestBase extends ViewTestBase {
@@ -1,161 +0,0 @@
<?php
namespace Drupal\field\Tests\Views;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\views\Views;
/**
* Tests the UI of the field field handler.
*
* @group field
* @see \Drupal\field\Plugin\views\field\Field
*/
class FieldUITest extends FieldTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_fieldapi'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui'];
/**
* A user with the 'administer views' permission.
*
* @var \Drupal\user\UserInterface
*/
protected $account;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->account = $this->drupalCreateUser(['administer views']);
$this->drupalLogin($this->account);
$this->setUpFieldStorages(1, 'text');
$this->setUpFields();
}
/**
* Tests basic field handler settings in the UI.
*/
public function testHandlerUI() {
$url = "admin/structure/views/nojs/handler/test_view_fieldapi/default/field/field_name_0";
$this->drupalGet($url);
// Tests the available formatter options.
$result = $this->xpath('//select[@id=:id]/option', [':id' => 'edit-options-type']);
$options = array_map(function ($item) {
return (string) $item->attributes()->value[0];
}, $result);
// @todo Replace this sort by assertArray once it's in.
sort($options, SORT_STRING);
$this->assertEqual($options, ['text_default', 'text_trimmed'], 'The text formatters for a simple text field appear as expected.');
$this->drupalPostForm(NULL, ['options[type]' => 'text_trimmed'], t('Apply'));
$this->drupalGet($url);
$this->assertOptionSelected('edit-options-type', 'text_trimmed');
$random_number = rand(100, 400);
$this->drupalPostForm(NULL, ['options[settings][trim_length]' => $random_number], t('Apply'));
$this->drupalGet($url);
$this->assertFieldByName('options[settings][trim_length]', $random_number, 'The formatter setting got saved.');
// Save the view and test whether the settings are saved.
$this->drupalPostForm('admin/structure/views/view/test_view_fieldapi', [], t('Save'));
$view = Views::getView('test_view_fieldapi');
$view->initHandlers();
$this->assertEqual($view->field['field_name_0']->options['type'], 'text_trimmed');
$this->assertEqual($view->field['field_name_0']->options['settings']['trim_length'], $random_number);
// Now change the formatter back to 'default' which doesn't have any
// settings. We want to ensure that the settings are empty then.
$edit['options[type]'] = 'text_default';
$this->drupalPostForm('admin/structure/views/nojs/handler/test_view_fieldapi/default/field/field_name_0', $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_view_fieldapi', [], t('Save'));
$view = Views::getView('test_view_fieldapi');
$view->initHandlers();
$this->assertEqual($view->field['field_name_0']->options['type'], 'text_default');
$this->assertEqual($view->field['field_name_0']->options['settings'], []);
// Ensure that the view depends on the field storage.
$dependencies = \Drupal::service('config.manager')->findConfigEntityDependents('config', [$this->fieldStorages[0]->getConfigDependencyName()]);
$this->assertTrue(isset($dependencies['views.view.test_view_fieldapi']), 'The view is dependent on the field storage.');
}
/**
* Tests the basic field handler form when aggregation is enabled.
*/
public function testHandlerUIAggregation() {
// Enable aggregation.
$edit = ['group_by' => '1'];
$this->drupalPostForm('admin/structure/views/nojs/display/test_view_fieldapi/default/group_by', $edit, t('Apply'));
$url = "admin/structure/views/nojs/handler/test_view_fieldapi/default/field/field_name_0";
$this->drupalGet($url);
$this->assertResponse(200);
// Test the click sort column options.
// Tests the available formatter options.
$result = $this->xpath('//select[@id=:id]/option', [':id' => 'edit-options-click-sort-column']);
$options = array_map(function ($item) {
return (string) $item->attributes()->value[0];
}, $result);
sort($options, SORT_STRING);
$this->assertEqual($options, ['format', 'value'], 'The expected sort field options were found.');
}
/**
* Tests adding a boolean field filter handler.
*/
public function testBooleanFilterHandler() {
// Create a boolean field.
$field_name = 'field_boolean';
$field_storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'node',
'type' => 'boolean',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'page',
]);
$field->save();
$url = "admin/structure/views/nojs/add-handler/test_view_fieldapi/default/filter";
$this->drupalPostForm($url, ['name[node__' . $field_name . '.' . $field_name . '_value]' => TRUE], t('Add and configure @handler', ['@handler' => t('filter criteria')]));
$this->assertResponse(200);
// Verify that using a boolean field as a filter also results in using the
// boolean plugin.
$option = $this->xpath('//label[@for="edit-options-value-1"]');
$this->assertEqual(t('True'), (string) $option[0]);
$option = $this->xpath('//label[@for="edit-options-value-0"]');
$this->assertEqual(t('False'), (string) $option[0]);
// Expose the filter and see if the 'Any' option is added and if we can save
// it.
$this->drupalPostForm(NULL, [], 'Expose filter');
$option = $this->xpath('//label[@for="edit-options-value-all"]');
$this->assertEqual(t('- Any -'), (string) $option[0]);
$this->drupalPostForm(NULL, ['options[value]' => 'All', 'options[expose][required]' => FALSE], 'Apply');
$this->drupalPostForm(NULL, [], 'Save');
$this->drupalGet('/admin/structure/views/nojs/handler/test_view_fieldapi/default/filter/field_boolean_value');
$this->assertFieldChecked('edit-options-value-all');
}
}
@@ -1,310 +0,0 @@
<?php
namespace Drupal\field\Tests\Views;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests the field itself of the Field integration.
*
* @group field
* @TODO
* Check a entity-type with bundles
* Check a entity-type without bundles
* Check locale:disabled, locale:enabled and locale:enabled with another language
* Check revisions
*/
class HandlerFieldFieldTest extends FieldTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'field_test'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_fieldapi'];
/**
* Test nodes.
*
* @var \Drupal\node\NodeInterface[]
*/
public $nodes;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Setup basic fields.
$this->setUpFieldStorages(3);
// Setup a field with cardinality > 1.
$this->fieldStorages[3] = FieldStorageConfig::create([
'field_name' => 'field_name_3',
'entity_type' => 'node',
'type' => 'string',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$this->fieldStorages[3]->save();
// Setup a field that will have no value.
$this->fieldStorages[4] = FieldStorageConfig::create([
'field_name' => 'field_name_4',
'entity_type' => 'node',
'type' => 'string',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$this->fieldStorages[4]->save();
// Setup a text field.
$this->fieldStorages[5] = FieldStorageConfig::create([
'field_name' => 'field_name_5',
'entity_type' => 'node',
'type' => 'text',
]);
$this->fieldStorages[5]->save();
// Setup a text field with access control.
// @see field_test_entity_field_access()
$this->fieldStorages[6] = FieldStorageConfig::create([
'field_name' => 'field_no_view_access',
'entity_type' => 'node',
'type' => 'text',
]);
$this->fieldStorages[6]->save();
$this->setUpFields();
// Create some nodes.
$this->nodes = [];
for ($i = 0; $i < 3; $i++) {
$edit = ['type' => 'page'];
foreach ([0, 1, 2, 5] as $key) {
$field_storage = $this->fieldStorages[$key];
$edit[$field_storage->getName()][0]['value'] = $this->randomMachineName(8);
}
// Add a hidden value for the no-view field.
$edit[$this->fieldStorages[6]->getName()][0]['value'] = 'ssh secret squirrel';
for ($j = 0; $j < 5; $j++) {
$edit[$this->fieldStorages[3]->getName()][$j]['value'] = $this->randomMachineName(8);
}
// Set this field to be empty.
$edit[$this->fieldStorages[4]->getName()] = [['value' => NULL]];
$this->nodes[$i] = $this->drupalCreateNode($edit);
}
$this->container->get('views.views_data')->clear();
}
/**
* Sets up the testing view with random field data.
*
* @param \Drupal\views\ViewExecutable $view
* The view to add field data to.
*/
protected function prepareView(ViewExecutable $view) {
$view->storage->invalidateCaches();
$view->initDisplay();
foreach ($this->fieldStorages as $field_storage) {
$field_name = $field_storage->getName();
$view->display_handler->options['fields'][$field_name]['id'] = $field_name;
$view->display_handler->options['fields'][$field_name]['table'] = 'node__' . $field_name;
$view->display_handler->options['fields'][$field_name]['field'] = $field_name;
}
}
public function testFieldRender() {
$this->_testSimpleFieldRender();
$this->_testInaccessibleFieldRender();
$this->_testFormatterSimpleFieldRender();
$this->_testMultipleFieldRender();
}
public function _testSimpleFieldRender() {
$view = Views::getView('test_view_fieldapi');
$this->prepareView($view);
$this->executeView($view);
// Tests that the rendered fields match the actual value of the fields.
for ($i = 0; $i < 3; $i++) {
for ($key = 0; $key < 2; $key++) {
$field_name = $this->fieldStorages[$key]->getName();
$rendered_field = $view->style_plugin->getField($i, $field_name);
$expected_field = $this->nodes[$i]->$field_name->value;
$this->assertEqual($rendered_field, $expected_field);
}
}
}
public function _testInaccessibleFieldRender() {
$view = Views::getView('test_view_fieldapi');
$this->prepareView($view);
$this->executeView($view);
// Check that the field handler for the hidden field is correctly removed
// from the display.
// @see https://www.drupal.org/node/2382931
$this->assertFalse(array_key_exists('field_no_view_access', $view->field));
// Check that the access-denied field is not visible.
for ($i = 0; $i < 3; $i++) {
$field_name = $this->fieldStorages[6]->getName();
$rendered_field = $view->style_plugin->getField($i, $field_name);
$this->assertFalse($rendered_field, 'Hidden field not rendered');
}
}
/**
* Tests that fields with formatters runs as expected.
*/
public function _testFormatterSimpleFieldRender() {
$view = Views::getView('test_view_fieldapi');
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['type'] = 'text_trimmed';
$view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['settings'] = [
'trim_length' => 3,
];
$this->executeView($view);
// Make sure that the formatter works as expected.
// @TODO: actually there should be a specific formatter.
for ($i = 0; $i < 2; $i++) {
$rendered_field = $view->style_plugin->getField($i, $this->fieldStorages[5]->getName());
$this->assertEqual(strlen(html_entity_decode($rendered_field)), 3);
}
}
public function _testMultipleFieldRender() {
$view = Views::getView('test_view_fieldapi');
$field_name = $this->fieldStorages[3]->getName();
// Test delta limit.
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
$pure_items = array_splice($pure_items, 0, 3);
foreach ($pure_items as $j => $item) {
$items[] = $pure_items[$j]['value'];
}
$this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited.');
}
// Test that an empty field is rendered without error.
$view->style_plugin->getField(4, $this->fieldStorages[4]->getName());
$view->destroy();
// Test delta limit + offset
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 1;
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
$pure_items = array_splice($pure_items, 1, 3);
foreach ($pure_items as $j => $item) {
$items[] = $pure_items[$j]['value'];
}
$this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and the offset is correct.');
}
$view->destroy();
// Test delta limit + reverse.
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 0;
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = TRUE;
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
array_splice($pure_items, 0, -3);
$pure_items = array_reverse($pure_items);
foreach ($pure_items as $j => $item) {
$items[] = $pure_items[$j]['value'];
}
$this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and they are reversed.');
}
$view->destroy();
// Test delta first last.
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 0;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = FALSE;
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
$items[] = $pure_items[0]['value'];
$items[] = $pure_items[4]['value'];
$this->assertEqual($rendered_field, implode(', ', $items), 'Items are limited to first and last.');
}
$view->destroy();
// Test delta limit + custom separator.
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = FALSE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = ':';
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
$pure_items = array_splice($pure_items, 0, 3);
foreach ($pure_items as $j => $item) {
$items[] = $pure_items[$j]['value'];
}
$this->assertEqual($rendered_field, implode(':', $items), 'The amount of items is limited and the custom separator is correct.');
}
$view->destroy();
// Test separator with HTML, ensure it is escaped.
$this->prepareView($view);
$view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
$view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
$view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = '<h2>test</h2>';
$this->executeView($view);
for ($i = 0; $i < 3; $i++) {
$rendered_field = $view->style_plugin->getField($i, $field_name);
$items = [];
$pure_items = $this->nodes[$i]->{$field_name}->getValue();
$pure_items = array_splice($pure_items, 0, 3);
foreach ($pure_items as $j => $item) {
$items[] = $pure_items[$j]['value'];
}
$this->assertEqual($rendered_field, implode('<h2>test</h2>', $items), 'The custom separator is correctly escaped.');
}
$view->destroy();
}
}
@@ -1,124 +0,0 @@
<?php
namespace Drupal\field\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\simpletest\WebTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests the behavior of a field module after being disabled and re-enabled.
*
* @group field
*/
class reEnableModuleFieldTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'field',
'node',
// We use telephone module instead of test_field because test_field is
// hidden and does not display on the admin/modules page.
'telephone'
];
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'article']);
$this->drupalLogin($this->drupalCreateUser([
'create article content',
'edit own article content',
]));
}
/**
* Test the behavior of a field module after being disabled and re-enabled.
*
* @see field_system_info_alter()
*/
public function testReEnabledField() {
// Add a telephone field to the article content type.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_telephone',
'entity_type' => 'node',
'type' => 'telephone',
]);
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'article',
'label' => 'Telephone Number',
])->save();
entity_get_form_display('node', 'article', 'default')
->setComponent('field_telephone', [
'type' => 'telephone_default',
'settings' => [
'placeholder' => '123-456-7890',
],
])
->save();
entity_get_display('node', 'article', 'default')
->setComponent('field_telephone', [
'type' => 'telephone_link',
'weight' => 1,
])
->save();
// Display the article node form and verify the telephone widget is present.
$this->drupalGet('node/add/article');
$this->assertFieldByName("field_telephone[0][value]", '', 'Widget found.');
// Submit an article node with a telephone field so data exist for the
// field.
$edit = [
'title[0][value]' => $this->randomMachineName(),
'field_telephone[0][value]' => "123456789",
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertRaw('<a href="tel:123456789">');
// Test that the module can't be uninstalled from the UI while there is data
// for its fields.
$admin_user = $this->drupalCreateUser(['access administration pages', 'administer modules']);
$this->drupalLogin($admin_user);
$this->drupalGet('admin/modules/uninstall');
$this->assertText("The Telephone number field type is used in the following field: node.field_telephone");
// Add another telephone field to a different entity type in order to test
// the message for the case when multiple fields are blocking the
// uninstallation of a module.
$field_storage2 = entity_create('field_storage_config', [
'field_name' => 'field_telephone_2',
'entity_type' => 'user',
'type' => 'telephone',
]);
$field_storage2->save();
FieldConfig::create([
'field_storage' => $field_storage2,
'bundle' => 'user',
'label' => 'User Telephone Number',
])->save();
$this->drupalGet('admin/modules/uninstall');
$this->assertText("The Telephone number field type is used in the following fields: node.field_telephone, user.field_telephone_2");
// Delete both fields.
$field_storage->delete();
$field_storage2->delete();
$this->drupalGet('admin/modules/uninstall');
$this->assertText('Fields pending deletion');
$this->cronRun();
$this->assertNoText("The Telephone number field type is used in the following field: node.field_telephone");
$this->assertNoText('Fields pending deletion');
}
}