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

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

View file

@ -23,9 +23,9 @@
// submitted at the same time. The actual validation will happen
// server-side.
$form.find(
'.form-item-label label,' +
'.form-item-field-name label,' +
'.form-item-existing-storage-label label')
'.js-form-item-label label,' +
'.js-form-item-field-name label,' +
'.js-form-item-existing-storage-label label')
.addClass('js-form-required form-required');
var $newFieldType = $form.find('select[name="new_storage_type"]');

View file

@ -24,7 +24,7 @@ function field_ui_help($route_name, RouteMatchInterface $route_match) {
case 'help.page.field_ui':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Field UI module provides an administrative user interface (UI) for managing and displaying fields. Fields can be attached to most content entity sub-types. Different field types, widgets, and formatters are provided by the modules enabled on your site, and managed by the Field module. For background information and terminology related to fields and entities, see the <a href="!field">Field module help page</a>. For more information about the Field UI, see <a href="!field_ui_docs">the online documentation for the Field UI module</a>.', array('!field' => \Drupal::url('help.page', array('name' => 'field')), '!field_ui_docs' => 'https://www.drupal.org/documentation/modules/field-ui')) . '</p>';
$output .= '<p>' . t('The Field UI module provides an administrative user interface (UI) for managing and displaying fields. Fields can be attached to most content entity sub-types. Different field types, widgets, and formatters are provided by the modules enabled on your site, and managed by the Field module. For background information and terminology related to fields and entities, see the <a href=":field">Field module help page</a>. For more information about the Field UI, see the <a href=":field_ui_docs">online documentation for the Field UI module</a>.', array(':field' => \Drupal::url('help.page', array('name' => 'field')), ':field_ui_docs' => 'https://www.drupal.org/documentation/modules/field-ui')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating a field') . '</dt>';
@ -36,9 +36,9 @@ function field_ui_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dt>' . t('Configuring field display') . '</dt>';
$output .= '<dd>' . t('On the <em>Manage display</em> page of your entity type or sub-type, you can configure how each field is displayed by default and in each view mode. If your entity type has multiple view modes, you can toggle between the view modes at the top of the page, and you can toggle whether each view mode uses the default settings or custom settings in the <em>Custom display settings</em> section. For each field in each view mode, you can choose whether and how to display the label of the field from the <em>Label</em> drop-down list. You can also select the formatter to use for display; some formatters have configuration options, which you can edit using the Edit button (which looks like a wheel). You can also change the display order of fields. You can exclude a field from a specific view mode by choosing <em>Hidden</em> from the formatter drop-down list, or by dragging it into the <em>Disabled</em> section.') . '</dd>';
$output .= '<dt>' . t('Configuring view and form modes') . '</dt>';
$output .= '<dd>' . t('You can add, edit, and delete view modes for entities on the <a href="!view_modes">View modes page</a>, and you can add, edit, and delete form modes for entities on the <a href="!form_modes">Form modes page</a>. Once you have defined a view mode or form mode for an entity type, it will be available on the Manage display or Manage form display page for each sub-type of that entity.', array('!view_modes' => \Drupal::url('entity.entity_view_mode.collection'), '!form_modes' => \Drupal::url('entity.entity_form_mode.collection'))) . '</dd>';
$output .= '<dd>' . t('You can add, edit, and delete view modes for entities on the <a href=":view_modes">View modes page</a>, and you can add, edit, and delete form modes for entities on the <a href=":form_modes">Form modes page</a>. Once you have defined a view mode or form mode for an entity type, it will be available on the Manage display or Manage form display page for each sub-type of that entity.', array(':view_modes' => \Drupal::url('entity.entity_view_mode.collection'), ':form_modes' => \Drupal::url('entity.entity_form_mode.collection'))) . '</dd>';
$output .= '<dt>' . t('Listing fields') . '</dt>';
$output .= '<dd>' . t('There are two reports available that list the fields defined on your site. The <a href="!entity-list" title="Entities field list report">Entities</a> report lists all your fields, showing the field machine names, types, and the entity types or sub-types they are used on (each sub-type links to the Manage fields page). If the <a href="!views">Views</a> and <a href="!views-ui">Views UI</a> modules are enabled, the <a href="!views-list" title="Used in views field list report">Used in views</a> report lists each field that is used in a view, with a link to edit that view.', array('!entity-list' => \Drupal::url('entity.field_storage_config.collection'), '!views-list' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('views_ui.reports_fields') : '#', '!views' => (\Drupal::moduleHandler()->moduleExists('views')) ? \Drupal::url('help.page', array('name' => 'views')) : '#','!views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', array('name' => 'views_ui')) : '#')) . '</dd>';
$output .= '<dd>' . t('There are two reports available that list the fields defined on your site. The <a href=":entity-list" title="Entities field list report">Entities</a> report lists all your fields, showing the field machine names, types, and the entity types or sub-types they are used on (each sub-type links to the Manage fields page). If the <a href=":views">Views</a> and <a href=":views-ui">Views UI</a> modules are enabled, the <a href=":views-list" title="Used in views field list report">Used in views</a> report lists each field that is used in a view, with a link to edit that view.', array(':entity-list' => \Drupal::url('entity.field_storage_config.collection'), ':views-list' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('views_ui.reports_fields') : '#', ':views' => (\Drupal::moduleHandler()->moduleExists('views')) ? \Drupal::url('help.page', array('name' => 'views')) : '#',':views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', array('name' => 'views_ui')) : '#')) . '</dd>';
$output .= '</dl>';
return $output;
@ -107,15 +107,6 @@ function field_ui_entity_bundle_create($entity_type, $bundle) {
\Drupal::service('router.builder')->setRebuildNeeded();
}
/**
* Implements hook_entity_bundle_rename().
*/
function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
// When a bundle is renamed, the menu needs to be rebuilt to add our
// menu item tabs.
\Drupal::service('router.builder')->setRebuildNeeded();
}
/**
* Implements hook_form_FORM_ID_alter().
*
@ -306,3 +297,14 @@ function field_ui_local_tasks_alter(&$local_tasks) {
$local_task = FieldUiLocalTask::create($container, 'field_ui.fields');
$local_task->alterLocalTasks($local_tasks);
}
/**
* Implements hook_form_FORM_ID_alter() for 'field_ui_field_storage_add_form'.
*/
function field_ui_form_field_ui_field_storage_add_form_alter(array &$form) {
$optgroup = (string) t('Reference');
// Move the "Entity reference" option to the end of the list and rename it to
// "Other".
unset($form['add']['new_storage_type']['#options'][$optgroup]['entity_reference']);
$form['add']['new_storage_type']['#options'][$optgroup]['entity_reference'] = t('Other…');
}

View file

@ -153,7 +153,7 @@ abstract class EntityDisplayFormBase extends EntityForm {
);
if (empty($field_definitions) && empty($extra_fields) && $route_info = FieldUI::getOverviewRouteInfo($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle())) {
drupal_set_message($this->t('There are no fields yet added. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => $route_info->toString())), 'warning');
drupal_set_message($this->t('There are no fields yet added. You can add new fields on the <a href=":link">Manage fields</a> page.', array(':link' => $route_info->toString())), 'warning');
return $form;
}
@ -201,26 +201,23 @@ abstract class EntityDisplayFormBase extends EntityForm {
// Custom display settings.
if ($this->entity->getMode() == 'default') {
// Only show the settings if there is at least one custom display mode.
if ($display_modes = $this->getDisplayModes()) {
$display_mode_options = $this->getDisplayModeOptions();
// Unset default option.
unset($display_mode_options['default']);
if ($display_mode_options) {
$form['modes'] = array(
'#type' => 'details',
'#title' => $this->t('Custom display settings'),
);
// Collect options and default values for the 'Custom display settings'
// checkboxes.
$options = array();
// Prepare default values for the 'Custom display settings' checkboxes.
$default = array();
$display_statuses = $this->getDisplayStatuses();
foreach ($display_modes as $mode_name => $mode_info) {
$options[$mode_name] = $mode_info['label'];
if (!empty($display_statuses[$mode_name])) {
$default[] = $mode_name;
}
if ($display_statuses = array_filter($this->getDisplayStatuses())) {
$default = array_keys(array_intersect_key($display_mode_options, $display_statuses));
}
$form['modes']['display_modes_custom'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Use custom display settings for the following modes'),
'#options' => $options,
'#options' => $display_mode_options,
'#default_value' => $default,
);
}
@ -279,6 +276,12 @@ abstract class EntityDisplayFormBase extends EntityForm {
$display_options = $this->entity->getComponent($field_name);
$label = $field_definition->getLabel();
// Disable fields without any applicable plugins.
if (empty($this->getApplicablePluginOptions($field_definition))) {
$this->entity->removeComponent($field_name)->save();
$display_options = $this->entity->getComponent($field_name);
}
$regions = array_keys($this->getRegions());
$field_row = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
@ -530,7 +533,7 @@ abstract class EntityDisplayFormBase extends EntityForm {
$display_mode_label = $display_modes[$mode]['label'];
$url = $this->getOverviewUrl($mode);
drupal_set_message($this->t('The %display_mode mode now uses custom display settings. You might want to <a href="@url">configure them</a>.', ['%display_mode' => $display_mode_label, '@url' => $url->toString()]));
drupal_set_message($this->t('The %display_mode mode now uses custom display settings. You might want to <a href=":url">configure them</a>.', ['%display_mode' => $display_mode_label, ':url' => $url->toString()]));
}
$statuses[$mode] = !empty($value);
}
@ -816,6 +819,27 @@ abstract class EntityDisplayFormBase extends EntityForm {
*/
abstract protected function getEntityDisplay($entity_type_id, $bundle, $mode);
/**
* Returns an array of applicable widget or formatter options for a field.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
*
* @return array
* An array of applicable widget or formatter options.
*/
protected function getApplicablePluginOptions(FieldDefinitionInterface $field_definition) {
$options = $this->pluginManager->getOptions($field_definition->getType());
$applicable_options = array();
foreach ($options as $option => $label) {
$plugin_class = DefaultFactory::getPluginClass($option, $this->pluginManager->getDefinition($option));
if ($plugin_class::isApplicable($field_definition)) {
$applicable_options[$option] = $label;
}
}
return $applicable_options;
}
/**
* Returns an array of widget or formatter options for a field.
*
@ -826,14 +850,7 @@ abstract class EntityDisplayFormBase extends EntityForm {
* An array of widget or formatter options.
*/
protected function getPluginOptions(FieldDefinitionInterface $field_definition) {
$options = $this->pluginManager->getOptions($field_definition->getType());
$applicable_options = array();
foreach ($options as $option => $label) {
$plugin_class = DefaultFactory::getPluginClass($option, $this->pluginManager->getDefinition($option));
if ($plugin_class::isApplicable($field_definition)) {
$applicable_options[$option] = $label;
}
}
$applicable_options = $this->getApplicablePluginOptions($field_definition);
return $applicable_options + array('hidden' => '- ' . $this->t('Hidden') . ' -');
}
@ -856,6 +873,14 @@ abstract class EntityDisplayFormBase extends EntityForm {
*/
abstract protected function getDisplayModes();
/**
* Returns an array of form or view mode options.
*
* @return array
* An array of form or view mode options.
*/
abstract protected function getDisplayModeOptions();
/**
* Returns the region to which a row in the display overview belongs.
*

View file

@ -73,6 +73,13 @@ class EntityFormDisplayEditForm extends EntityDisplayFormBase {
return $this->entityManager->getFormModes($this->entity->getTargetEntityTypeId());
}
/**
* {@inheritdoc}
*/
protected function getDisplayModeOptions() {
return $this->entityManager->getFormModeOptions($this->entity->getTargetEntityTypeId());
}
/**
* {@inheritdoc}
*/

View file

@ -106,6 +106,13 @@ class EntityViewDisplayEditForm extends EntityDisplayFormBase {
return $this->entityManager->getViewModes($this->entity->getTargetEntityTypeId());
}
/**
* {@inheritdoc}
*/
protected function getDisplayModeOptions() {
return $this->entityManager->getViewModeOptions($this->entity->getTargetEntityTypeId());
}
/**
* {@inheritdoc}
*/

View file

@ -7,9 +7,11 @@
namespace Drupal\field_ui\Form;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\EntityDeleteForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\field_ui\FieldUI;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -44,6 +46,44 @@ class FieldConfigDeleteForm extends EntityDeleteForm {
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// If we are adding the field storage as a dependency to delete, then that
// will list the field as a dependency. That is confusing, so remove it.
// Also remove the entity type and the whole entity deletions details
// element if nothing else is in there.
if (isset($form['entity_deletes']['field_config']['#items']) && isset($form['entity_deletes']['field_config']['#items'][$this->entity->id()])) {
unset($form['entity_deletes']['field_config']['#items'][$this->entity->id()]);
if (empty($form['entity_deletes']['field_config']['#items'])) {
unset($form['entity_deletes']['field_config']);
if (!Element::children($form['entity_deletes'])) {
$form['entity_deletes']['#access'] = FALSE;
}
}
}
return $form;
}
/**
* {@inheritdoc}
*/
protected function getConfigNamesToDelete(ConfigEntityInterface $entity) {
/** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
$field_storage = $entity->getFieldStorageDefinition();
$config_names = [$entity->getConfigDependencyName()];
// If there is only one bundle left for this field storage, it will be
// deleted too, notify the user about dependencies.
if (count($field_storage->getBundles()) <= 1) {
$config_names[] = $field_storage->getConfigDependencyName();
}
return $config_names;
}
/**
* {@inheritdoc}
*/

View file

@ -7,10 +7,9 @@
namespace Drupal\field_ui\Form;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Field\AllowedTagsXssTrait;
use Drupal\Core\Field\FieldFilteredString;
use Drupal\Core\Field\FieldFilteredMarkup;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\field\FieldConfigInterface;
@ -66,7 +65,7 @@ class FieldConfigEditForm extends EntityForm {
'#title' => $this->t('Help text'),
'#default_value' => $this->entity->getDescription(),
'#rows' => 5,
'#description' => $this->t('Instructions to present to the user below this field on the editing form.<br />Allowed HTML tags: @tags', array('@tags' => FieldFilteredString::displayAllowedTags())) . '<br />' . $this->t('This field supports tokens.'),
'#description' => $this->t('Instructions to present to the user below this field on the editing form.<br />Allowed HTML tags: @tags', array('@tags' => FieldFilteredMarkup::displayAllowedTags())) . '<br />' . $this->t('This field supports tokens.'),
'#weight' => -10,
);
@ -172,7 +171,7 @@ class FieldConfigEditForm extends EntityForm {
$items = $form['#entity']->get($this->entity->getName());
$default_value = $items->defaultValuesFormSubmit($form['default_value'], $form, $form_state);
}
$this->entity->default_value = $default_value;
$this->entity->setDefaultValue($default_value);
}
/**
@ -203,7 +202,7 @@ class FieldConfigEditForm extends EntityForm {
* The label of the field.
*/
public function getTitle(FieldConfigInterface $field_config) {
return SafeMarkup::checkPlain($field_config->label());
return $field_config->label();
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\field_ui\Plugin\Derivative;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
@ -138,6 +139,7 @@ class FieldUiLocalTask extends DeriverBase implements ContainerDeriverInterface
),
'parent_id' => "field_ui.fields:form_display_overview_$entity_type_id",
'weight' => $weight++,
'cache_tags' => $this->entityManager->getDefinition('entity_form_display')->getListCacheTags(),
);
}
@ -152,6 +154,7 @@ class FieldUiLocalTask extends DeriverBase implements ContainerDeriverInterface
),
'parent_id' => "field_ui.fields:display_overview_$entity_type_id",
'weight' => $weight++,
'cache_tags' => $this->entityManager->getDefinition('entity_view_display')->getListCacheTags(),
);
}
}
@ -189,5 +192,4 @@ class FieldUiLocalTask extends DeriverBase implements ContainerDeriverInterface
}
}
}
}

View file

@ -30,6 +30,7 @@ class EntityDisplayModeTest extends WebTestBase {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('page_title_block');
}
/**

View file

@ -7,12 +7,20 @@
namespace Drupal\field_ui\Tests;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\Display\EntityDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\Entity\EntityViewMode;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\simpletest\KernelTestBase;
use Drupal\user\Entity\Role;
/**
* Tests the entity display configuration entities.
@ -31,7 +39,8 @@ class EntityDisplayTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig(array('field', 'node'));
$this->installEntitySchema('user');
$this->installConfig(array('field', 'node', 'user'));
}
/**
@ -100,7 +109,7 @@ class EntityDisplayTest extends KernelTestBase {
$new_display = $display->createCopy('other_view_mode');
$new_display->save();
$new_display = entity_load('entity_view_display', $new_display->id());
$dependencies = $new_display->calculateDependencies();
$dependencies = $new_display->calculateDependencies()->getDependencies();
$this->assertEqual(array('config' => array('core.entity_view_mode.entity_test.other_view_mode'), 'module' => array('entity_test')), $dependencies);
$this->assertEqual($new_display->getTargetEntityTypeId(), $display->getTargetEntityTypeId());
$this->assertEqual($new_display->getTargetBundle(), $display->getTargetBundle());
@ -230,7 +239,7 @@ class EntityDisplayTest extends KernelTestBase {
// Check that the display has dependencies on the field and the module that
// provides the formatter.
$dependencies = $display->calculateDependencies();
$dependencies = $display->calculateDependencies()->getDependencies();
$this->assertEqual(array('config' => array('field.field.entity_test.entity_test.test_field'), 'module' => array('entity_test', 'field_test')), $dependencies);
}
@ -296,9 +305,9 @@ class EntityDisplayTest extends KernelTestBase {
}
/**
* Tests renaming and deleting a bundle.
* Tests deleting a bundle.
*/
public function testRenameDeleteBundle() {
public function testDeleteBundle() {
// Create a node bundle, display and form display object.
$type = NodeType::create(array('type' => 'article'));
$type->save();
@ -306,44 +315,11 @@ class EntityDisplayTest extends KernelTestBase {
entity_get_display('node', 'article', 'default')->save();
entity_get_form_display('node', 'article', 'default')->save();
// Rename the article bundle and assert the entity display is renamed.
$type->old_type = 'article';
$type->set('type', 'article_rename');
$type->save();
$old_display = entity_load('entity_view_display', 'node.article.default');
$this->assertFalse((bool) $old_display);
$old_form_display = entity_load('entity_form_display', 'node.article.default');
$this->assertFalse((bool) $old_form_display);
$new_display = entity_load('entity_view_display', 'node.article_rename.default');
$this->assertEqual('article_rename', $new_display->getTargetBundle());
$this->assertEqual('node.article_rename.default', $new_display->id());
$new_form_display = entity_load('entity_form_display', 'node.article_rename.default');
$this->assertEqual('article_rename', $new_form_display->getTargetBundle());
$this->assertEqual('node.article_rename.default', $new_form_display->id());
$expected_view_dependencies = array(
'config' => array('field.field.node.article_rename.body', 'node.type.article_rename'),
'module' => array('entity_test', 'text', 'user')
);
// Check that the display has dependencies on the bundle, fields and the
// modules that provide the formatters.
$dependencies = $new_display->calculateDependencies();
$this->assertEqual($expected_view_dependencies, $dependencies);
// Check that the form display has dependencies on the bundle, fields and
// the modules that provide the formatters.
$dependencies = $new_form_display->calculateDependencies();
$expected_form_dependencies = array(
'config' => array('field.field.node.article_rename.body', 'node.type.article_rename'),
'module' => array('text')
);
$this->assertEqual($expected_form_dependencies, $dependencies);
// Delete the bundle.
$type->delete();
$display = entity_load('entity_view_display', 'node.article_rename.default');
$display = entity_load('entity_view_display', 'node.article.default');
$this->assertFalse((bool) $display);
$form_display = entity_load('entity_form_display', 'node.article_rename.default');
$form_display = entity_load('entity_form_display', 'node.article.default');
$this->assertFalse((bool) $form_display);
}
@ -435,4 +411,245 @@ class EntityDisplayTest extends KernelTestBase {
$display = entity_get_display('entity_test', 'entity_test', 'default');
$this->assertFalse($display->getComponent($field_name));
}
/**
* Ensure that entity view display changes invalidates cache tags.
*/
public function testEntityDisplayInvalidateCacheTags() {
$cache = \Drupal::cache();
$cache->set('cid', 'kittens', Cache::PERMANENT, ['config:entity_view_display_list']);
$display = EntityViewDisplay::create([
'targetEntityType' => 'entity_test',
'bundle' => 'entity_test',
'mode' => 'default',
]);
$display->setComponent('kitten');
$display->save();
$this->assertFalse($cache->get('cid'));
}
/**
* Test getDisplayModeOptions().
*/
public function testGetDisplayModeOptions() {
NodeType::create(array('type' => 'article'))->save();
EntityViewDisplay::create(array(
'targetEntityType' => 'node',
'bundle' => 'article',
'mode' => 'default',
))->setStatus(TRUE)->save();
$display_teaser = EntityViewDisplay::create(array(
'targetEntityType' => 'node',
'bundle' => 'article',
'mode' => 'teaser',
));
$display_teaser->save();
EntityFormDisplay::create(array(
'targetEntityType' => 'user',
'bundle' => 'user',
'mode' => 'default',
))->setStatus(TRUE)->save();
$form_display_teaser = EntityFormDisplay::create(array(
'targetEntityType' => 'user',
'bundle' => 'user',
'mode' => 'register',
));
$form_display_teaser->save();
// Test getViewModeOptionsByBundle().
$view_modes = \Drupal::entityManager()->getViewModeOptionsByBundle('node', 'article');
$this->assertEqual($view_modes, array('default' => 'Default'));
$display_teaser->setStatus(TRUE)->save();
$view_modes = \Drupal::entityManager()->getViewModeOptionsByBundle('node', 'article');
$this->assertEqual($view_modes, array('default' => 'Default', 'teaser' => 'Teaser'));
// Test getFormModeOptionsByBundle().
$form_modes = \Drupal::entityManager()->getFormModeOptionsByBundle('user', 'user');
$this->assertEqual($form_modes, array('default' => 'Default'));
$form_display_teaser->setStatus(TRUE)->save();
$form_modes = \Drupal::entityManager()->getFormModeOptionsByBundle('user', 'user');
$this->assertEqual($form_modes, array('default' => 'Default', 'register' => 'Register'));
}
/**
* Tests components dependencies additions.
*/
public function testComponentDependencies() {
$this->enableModules(['dblog', 'color']);
$this->installSchema('dblog', ['watchdog']);
$this->installEntitySchema('user');
/** @var \Drupal\user\RoleInterface[] $roles */
$roles = [];
// Create two arbitrary user roles.
for ($i = 0; $i < 2; $i++) {
$roles[$i] = Role::create([
'id' => Unicode::strtolower($this->randomMachineName()),
'label' => $this->randomString(),
]);
$roles[$i]->save();
}
// Create a field of type 'test_field' attached to 'entity_test'.
$field_name = Unicode::strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'type' => 'test_field',
])->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
])->save();
// Create a new form display without components.
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$form_display = EntityFormDisplay::create([
'targetEntityType' => 'entity_test',
'bundle' => 'entity_test',
'mode' => 'default',
]);
$form_display->save();
$dependencies = ['user.role.' . $roles[0]->id(), 'user.role.' . $roles[1]->id()];
// The config object should not depend on none of the two $roles.
$this->assertNoDependency('config', $dependencies[0], $form_display);
$this->assertNoDependency('config', $dependencies[1], $form_display);
// Add a widget of type 'test_field_widget'.
$component = [
'type' => 'test_field_widget',
'settings' => [
'test_widget_setting' => $this->randomString(),
'role' => $roles[0]->id(),
'role2' => $roles[1]->id(),
],
'third_party_settings' => [
'color' => ['foo' => 'bar'],
],
];
$form_display->setComponent($field_name, $component);
$form_display->save();
// Now, the form display should depend on both user roles $roles.
$this->assertDependency('config', $dependencies[0], $form_display);
$this->assertDependency('config', $dependencies[1], $form_display);
// The form display should depend on 'color' module.
$this->assertDependency('module', 'color', $form_display);
// Delete the first user role entity.
$roles[0]->delete();
// Reload the form display.
$form_display = EntityFormDisplay::load($form_display->id());
// The display exists.
$this->assertFalse(empty($form_display));
// The form display should not depend on $role[0] anymore.
$this->assertNoDependency('config', $dependencies[0], $form_display);
// The form display should depend on 'anonymous' user role.
$this->assertDependency('config', 'user.role.anonymous', $form_display);
// The form display should depend on 'color' module.
$this->assertDependency('module', 'color', $form_display);
// Manually trigger the removal of configuration belonging to the module
// because KernelTestBase::disableModules() is not aware of this.
$this->container->get('config.manager')->uninstall('module', 'color');
// Uninstall 'color' module.
$this->disableModules(['color']);
// Reload the form display.
$form_display = EntityFormDisplay::load($form_display->id());
// The display exists.
$this->assertFalse(empty($form_display));
// The component is still enabled.
$this->assertNotNull($form_display->getComponent($field_name));
// The form display should not depend on 'color' module anymore.
$this->assertNoDependency('module', 'color', $form_display);
// Delete the 2nd user role entity.
$roles[1]->delete();
// Reload the form display.
$form_display = EntityFormDisplay::load($form_display->id());
// The display exists.
$this->assertFalse(empty($form_display));
// The component has been disabled.
$this->assertNull($form_display->getComponent($field_name));
$this->assertTrue($form_display->get('hidden')[$field_name]);
// The correct warning message has been logged.
$arguments = ['@display' => (string) t('Entity form display'), '@id' => $form_display->id(), '@name' => $field_name];
$logged = (bool) Database::getConnection()->select('watchdog', 'w')
->fields('w', ['wid'])
->condition('type', 'system')
->condition('message', "@display '@id': Component '@name' was disabled because its settings depend on removed dependencies.")
->condition('variables', serialize($arguments))
->execute()
->fetchAll();
$this->assertTrue($logged);
}
/**
* Asserts that $key is a $type type dependency of $display config entity.
*
* @param string $type
* The dependency type: 'config', 'content', 'module' or 'theme'.
* @param string $key
* The string to be checked.
* @param \Drupal\Core\Entity\Display\EntityDisplayInterface $display
* The entity display object to get dependencies from.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertDependency($type, $key, EntityDisplayInterface $display) {
return $this->assertDependencyHelper(TRUE, $type, $key, $display);
}
/**
* Asserts that $key is not a $type type dependency of $display config entity.
*
* @param string $type
* The dependency type: 'config', 'content', 'module' or 'theme'.
* @param string $key
* The string to be checked.
* @param \Drupal\Core\Entity\Display\EntityDisplayInterface $display
* The entity display object to get dependencies from.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertNoDependency($type, $key, EntityDisplayInterface $display) {
return $this->assertDependencyHelper(FALSE, $type, $key, $display);
}
/**
* Provides a helper for dependency assertions.
*
* @param bool $assertion
* Assertion: positive or negative.
* @param string $type
* The dependency type: 'config', 'content', 'module' or 'theme'.
* @param string $key
* The string to be checked.
* @param \Drupal\Core\Entity\Display\EntityDisplayInterface $display
* The entity display object to get dependencies from.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertDependencyHelper($assertion, $type, $key, EntityDisplayInterface $display) {
$all_dependencies = $display->getDependencies();
$dependencies = !empty($all_dependencies[$type]) ? $all_dependencies[$type] : [];
$context = $display instanceof EntityViewDisplayInterface ? 'View' : 'Form';
$value = $assertion ? in_array($key, $dependencies) : !in_array($key, $dependencies);
$args = ['@context' => $context, '@id' => $display->id(), '@type' => $type, '@key' => $key];
$message = $assertion ? new FormattableMarkup("@context display '@id' depends on @type '@key'.", $args) : new FormattableMarkup("@context display '@id' do not depend on @type '@key'.", $args);
return $this->assert($value, $message);
}
}

View file

@ -25,7 +25,7 @@ class EntityFormDisplayTest extends KernelTestBase {
*
* @var string[]
*/
public static $modules = array('field_ui', 'field', 'entity_test', 'field_test', 'user', 'text', 'entity_reference');
public static $modules = ['field_ui', 'field', 'entity_test', 'field_test', 'user', 'text'];
protected function setUp() {
parent::setUp();

View file

@ -0,0 +1,116 @@
<?php
/**
* @file
* Contains \Drupal\field_ui\Tests\FieldUIDeleteTest.
*/
namespace Drupal\field_ui\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Tests deletion of a field and their dependencies in the UI.
*
* @group field_ui
*/
class FieldUIDeleteTest extends WebTestBase {
use FieldUiTestTrait;
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('node', 'field_ui', 'field_test', 'block', 'field_test_views');
/**
* Test views to enable
*
* @var string[]
*/
public static $testViews = array('test_view_field_delete');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_breadcrumb_block');
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
// Create a test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'administer users', 'administer account settings', 'administer user display', 'bypass node access'));
$this->drupalLogin($admin_user);
}
/**
* Tests that deletion removes field storages and fields as expected.
*/
function testDeleteField() {
$field_label = $this->randomMachineName();
$field_name_input = 'test';
$field_name = 'field_test';
// Create an additional node type.
$type_name1 = strtolower($this->randomMachineName(8)) . '_test';
$type1 = $this->drupalCreateContentType(array('name' => $type_name1, 'type' => $type_name1));
$type_name1 = $type1->id();
// Create a new field.
$bundle_path1 = 'admin/structure/types/manage/' . $type_name1;
$this->fieldUIAddNewField($bundle_path1, $field_name_input, $field_label);
// Create an additional node type.
$type_name2 = strtolower($this->randomMachineName(8)) . '_test';
$type2 = $this->drupalCreateContentType(array('name' => $type_name2, 'type' => $type_name2));
$type_name2 = $type2->id();
// Add a field to the second node type.
$bundle_path2 = 'admin/structure/types/manage/' . $type_name2;
$this->fieldUIAddExistingField($bundle_path2, $field_name, $field_label);
\Drupal::service('module_installer')->install(['views']);
ViewTestData::createTestViews(get_class($this), array('field_test_views'));
// Check the config dependencies of the first field, the field storage must
// not be shown as being deleted yet.
$this->drupalGet("$bundle_path1/fields/node.$type_name1.$field_name/delete");
$this->assertNoText(t('The listed configuration will be deleted.'));
$this->assertNoText(t('View'));
$this->assertNoText('test_view_field_delete');
// Delete the first field.
$this->fieldUIDeleteField($bundle_path1, "node.$type_name1.$field_name", $field_label, $type_name1);
// Check that the field was deleted.
$this->assertNull(FieldConfig::loadByName('node', $type_name1, $field_name), 'Field was deleted.');
// Check that the field storage was not deleted
$this->assertNotNull(FieldStorageConfig::loadByName('node', $field_name), 'Field storage was not deleted.');
// Check the config dependencies of the first field.
$this->drupalGet("$bundle_path2/fields/node.$type_name2.$field_name/delete");
$this->assertText(t('The listed configuration will be deleted.'));
$this->assertText(t('View'));
$this->assertText('test_view_field_delete');
$xml = $this->cssSelect('#edit-entity-deletes');
// Remove the wrapping HTML.
$this->assertIdentical(FALSE, strpos($xml[0]->asXml(), $field_label), 'The currently being deleted field is not shown in the entity deletions.');
// Delete the second field.
$this->fieldUIDeleteField($bundle_path2, "node.$type_name2.$field_name", $field_label, $type_name2);
// Check that the field was deleted.
$this->assertNull(FieldConfig::loadByName('node', $type_name2, $field_name), 'Field was deleted.');
// Check that the field storage was deleted too.
$this->assertNull(FieldStorageConfig::loadByName('node', $field_name), 'Field storage was deleted.');
}
}

View file

@ -8,6 +8,7 @@
namespace Drupal\field_ui\Tests;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\node\Entity\NodeType;
@ -141,7 +142,7 @@ class ManageDisplayTest extends WebTestBase {
\Drupal::entityManager()->clearCachedFieldDefinitions();
$display = entity_load('entity_view_display', 'node.' . $this->type . '.default', TRUE);
$this->assertEqual($display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_field_formatter_third_party_settings_form'), 'foo');
$this->assertTrue(in_array('field_third_party_test', $display->calculateDependencies()['module']), 'The display has a dependency on field_third_party_test module.');
$this->assertTrue(in_array('field_third_party_test', $display->calculateDependencies()->getDependencies()['module']), 'The display has a dependency on field_third_party_test module.');
// Confirm that the third party settings are not updated on the settings form.
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
@ -168,12 +169,26 @@ class ManageDisplayTest extends WebTestBase {
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
$this->drupalPostAjaxForm(NULL, $edit, "field_test_plugin_settings_update");
// Uninstall the module providing third party settings and ensure the button
// is no longer there.
// When a module providing third-party settings to a formatter (or widget)
// is uninstalled, the formatter remains enabled but the provided settings,
// together with the corresponding form elements, are removed from the
// display component.
\Drupal::service('module_installer')->uninstall(array('field_third_party_test'));
// Ensure the button is still there after the module has been disabled.
$this->drupalGet($manage_display);
$this->assertResponse(200);
$this->assertNoFieldByName('field_test_settings_edit');
$this->assertFieldByName('field_test_settings_edit');
// Ensure that third-party form elements are not present anymore.
$this->drupalPostAjaxForm(NULL, array(), 'field_test_settings_edit');
$fieldname = 'fields[field_test][settings_edit_form][third_party_settings][field_third_party_test][field_test_field_formatter_third_party_settings_form]';
$this->assertNoField($fieldname);
// Ensure that third-party settings were removed from the formatter.
$display = EntityViewDisplay::load("node.{$this->type}.default");
$component = $display->getComponent('field_test');
$this->assertFalse(array_key_exists('field_third_party_test', $component['third_party_settings']));
}
/**
@ -253,7 +268,7 @@ class ManageDisplayTest extends WebTestBase {
\Drupal::entityManager()->clearCachedFieldDefinitions();
$display = entity_load('entity_form_display', 'node.' . $this->type . '.default', TRUE);
$this->assertEqual($display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_widget_third_party_settings_form'), 'foo');
$this->assertTrue(in_array('field_third_party_test', $display->calculateDependencies()['module']), 'Form display does not have a dependency on field_third_party_test module.');
$this->assertTrue(in_array('field_third_party_test', $display->calculateDependencies()->getDependencies()['module']), 'Form display does not have a dependency on field_third_party_test module.');
// Confirm that the third party settings are not updated on the settings form.
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
@ -388,7 +403,7 @@ class ManageDisplayTest extends WebTestBase {
))->save();
$this->drupalGet('admin/structure/types/manage/no_fields/display');
$this->assertRaw(t('There are no fields yet added. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => \Drupal::url('entity.node.field_ui_fields', array('node_type' => 'no_fields')))));
$this->assertRaw(t('There are no fields yet added. You can add new fields on the <a href=":link">Manage fields</a> page.', array(':link' => \Drupal::url('entity.node.field_ui_fields', array('node_type' => 'no_fields')))));
}
/**

View file

@ -10,7 +10,7 @@ namespace Drupal\field_ui\Tests;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
@ -70,6 +70,7 @@ class ManageFieldsTest extends WebTestBase {
$this->drupalPlaceBlock('system_breadcrumb_block');
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
// Create a test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'administer taxonomy', 'administer taxonomy_term fields', 'administer taxonomy_term display', 'administer users', 'administer account settings', 'administer user display', 'bypass node access'));
@ -80,8 +81,8 @@ class ManageFieldsTest extends WebTestBase {
$type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
$this->contentType = $type->id();
// Create random field name.
$this->fieldLabel = $this->randomMachineName(8);
// Create random field name with markup to test escaping.
$this->fieldLabel = '<em>' . $this->randomMachineName(8) . '</em>';
$this->fieldNameInput = strtolower($this->randomMachineName(8));
$this->fieldName = 'field_'. $this->fieldNameInput;
@ -194,6 +195,7 @@ class ManageFieldsTest extends WebTestBase {
$field_id = 'node.' . $this->contentType . '.' . $this->fieldName;
// Go to the field edit page.
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field_id . '/storage');
$this->assertEscaped($this->fieldLabel);
// Populate the field settings with new settings.
$string = 'updated dummy test string';
@ -402,7 +404,7 @@ class ManageFieldsTest extends WebTestBase {
$this->drupalPostForm($admin_path, $edit, t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, array(array('value' => 1)), 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), array(array('value' => 1)), 'The default value was correctly saved.');
// Check that the default value shows up in the form
$this->drupalGet($admin_path);
@ -413,7 +415,7 @@ class ManageFieldsTest extends WebTestBase {
$this->drupalPostForm(NULL, $edit, t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, NULL, 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), NULL, 'The default value was correctly saved.');
// Check that the default value can be empty when the field is marked as
// required and can store unlimited values.
@ -431,7 +433,7 @@ class ManageFieldsTest extends WebTestBase {
$this->drupalPostForm(NULL, array(), t('Save settings'));
$this->assertText("Saved $field_name configuration", 'The form was successfully submitted.');
$field = FieldConfig::loadByName('node', $this->contentType, $field_name);
$this->assertEqual($field->default_value, NULL, 'The default value was correctly saved.');
$this->assertEqual($field->getDefaultValueLiteral(), NULL, 'The default value was correctly saved.');
// Check that the default widget is used when the field is hidden.
entity_get_form_display($field->getTargetEntityTypeId(), $field->getTargetBundle(), 'default')
@ -588,19 +590,6 @@ class ManageFieldsTest extends WebTestBase {
}
}
/**
* Tests renaming a bundle.
*/
function testRenameBundle() {
$type2 = strtolower($this->randomMachineName(8)) . '_test';
$options = array(
'type' => $type2,
);
$this->drupalPostForm('admin/structure/types/manage/' . $this->contentType, $options, t('Save content type'));
$this->manageFieldsPage($type2);
}
/**
* Tests that a duplicate field name is caught by validation.
*/