Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
92
core/modules/field_ui/src/Access/FormModeAccessCheck.php
Normal file
92
core/modules/field_ui/src/Access/FormModeAccessCheck.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Access\FormModeAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Defines an access check for entity form mode routes.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Entity\EntityFormMode
|
||||
*/
|
||||
class FormModeAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Creates a new FormModeAccessCheck.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks access to the form mode.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The parametrized route.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
* @param string $form_mode_name
|
||||
* (optional) The form mode. Defaults to 'default'.
|
||||
* @param string $bundle
|
||||
* (optional) The bundle. Different entity types can have different names
|
||||
* for their bundle key, so if not specified on the route via a {bundle}
|
||||
* parameter, the access checker determines the appropriate key name, and
|
||||
* gets the value from the corresponding request attribute. For example,
|
||||
* for nodes, the bundle key is "node_type", so the value would be
|
||||
* available via the {node_type} parameter rather than a {bundle}
|
||||
* parameter.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $form_mode_name = 'default', $bundle = NULL) {
|
||||
$access = AccessResult::neutral();
|
||||
if ($entity_type_id = $route->getDefault('entity_type_id')) {
|
||||
if (empty($bundle)) {
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
$bundle = $route_match->getRawParameter($entity_type->getBundleEntityType());
|
||||
}
|
||||
|
||||
$visibility = FALSE;
|
||||
if ($form_mode_name == 'default') {
|
||||
$visibility = TRUE;
|
||||
}
|
||||
elseif ($entity_display = $this->entityManager->getStorage('entity_form_display')->load($entity_type_id . '.' . $bundle . '.' . $form_mode_name)) {
|
||||
$visibility = $entity_display->status();
|
||||
}
|
||||
|
||||
if ($form_mode_name != 'default' && $entity_display) {
|
||||
$access->cacheUntilEntityChanges($entity_display);
|
||||
}
|
||||
|
||||
if ($visibility) {
|
||||
$permission = $route->getRequirement('_field_ui_form_mode_access');
|
||||
$access = $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
|
||||
}
|
||||
}
|
||||
return $access;
|
||||
}
|
||||
|
||||
}
|
92
core/modules/field_ui/src/Access/ViewModeAccessCheck.php
Normal file
92
core/modules/field_ui/src/Access/ViewModeAccessCheck.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Access\ViewModeAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Defines an access check for entity view mode routes.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Entity\EntityViewMode
|
||||
*/
|
||||
class ViewModeAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Creates a new ViewModeAccessCheck.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks access to the view mode.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The parametrized route.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
* @param string $view_mode_name
|
||||
* (optional) The view mode. Defaults to 'default'.
|
||||
* @param string $bundle
|
||||
* (optional) The bundle. Different entity types can have different names
|
||||
* for their bundle key, so if not specified on the route via a {bundle}
|
||||
* parameter, the access checker determines the appropriate key name, and
|
||||
* gets the value from the corresponding request attribute. For example,
|
||||
* for nodes, the bundle key is "node_type", so the value would be
|
||||
* available via the {node_type} parameter rather than a {bundle}
|
||||
* parameter.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $view_mode_name = 'default', $bundle = NULL) {
|
||||
$access = AccessResult::neutral();
|
||||
if ($entity_type_id = $route->getDefault('entity_type_id')) {
|
||||
if (empty($bundle)) {
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
$bundle = $route_match->getRawParameter($entity_type->getBundleEntityType());
|
||||
}
|
||||
|
||||
$visibility = FALSE;
|
||||
if ($view_mode_name == 'default') {
|
||||
$visibility = TRUE;
|
||||
}
|
||||
elseif ($entity_display = $this->entityManager->getStorage('entity_view_display')->load($entity_type_id . '.' . $bundle . '.' . $view_mode_name)) {
|
||||
$visibility = $entity_display->status();
|
||||
}
|
||||
|
||||
if ($view_mode_name != 'default' && $entity_display) {
|
||||
$access->cacheUntilEntityChanges($entity_display);
|
||||
}
|
||||
|
||||
if ($visibility) {
|
||||
$permission = $route->getRequirement('_field_ui_view_mode_access');
|
||||
$access = $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
|
||||
}
|
||||
}
|
||||
return $access;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Controller\EntityDisplayModeController.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides methods for entity display mode routes.
|
||||
*/
|
||||
class EntityDisplayModeController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Provides a list of eligible entity types for adding view modes.
|
||||
*
|
||||
* @return array
|
||||
* A list of entity types to add a view mode for.
|
||||
*/
|
||||
public function viewModeTypeSelection() {
|
||||
$entity_types = array();
|
||||
foreach ($this->entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->get('field_ui_base_route') && $entity_type->hasViewBuilderClass()) {
|
||||
$entity_types[$entity_type_id] = array(
|
||||
'title' => $entity_type->getLabel(),
|
||||
'url' => Url::fromRoute('entity.entity_view_mode.add_form', array('entity_type_id' => $entity_type_id)),
|
||||
'localized_options' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'#theme' => 'admin_block_content',
|
||||
'#content' => $entity_types,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of eligible entity types for adding form modes.
|
||||
*
|
||||
* @return array
|
||||
* A list of entity types to add a form mode for.
|
||||
*/
|
||||
public function formModeTypeSelection() {
|
||||
$entity_types = array();
|
||||
foreach ($this->entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->get('field_ui_base_route') && $entity_type->hasFormClasses()) {
|
||||
$entity_types[$entity_type_id] = array(
|
||||
'title' => $entity_type->getLabel(),
|
||||
'url' => Url::fromRoute('entity.entity_form_mode.add_form', array('entity_type_id' => $entity_type_id)),
|
||||
'localized_options' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'#theme' => 'admin_block_content',
|
||||
'#content' => $entity_types,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Controller\FieldConfigListController.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Controller;
|
||||
|
||||
use Drupal\Core\Entity\Controller\EntityListController;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Defines a controller to list field instances.
|
||||
*/
|
||||
class FieldConfigListController extends EntityListController {
|
||||
|
||||
/**
|
||||
* Shows the 'Manage fields' page.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type.
|
||||
* @param string $bundle
|
||||
* The entity bundle.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by drupal_render().
|
||||
*/
|
||||
public function listing($entity_type_id = NULL, $bundle = NULL, RouteMatchInterface $route_match = NULL) {
|
||||
return $this->entityManager()->getListBuilder('field_config')->render($entity_type_id, $bundle);
|
||||
}
|
||||
|
||||
}
|
29
core/modules/field_ui/src/Element/FieldUiTable.php
Normal file
29
core/modules/field_ui/src/Element/FieldUiTable.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Element\FieldUiTable.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
|
||||
/**
|
||||
* Provides a field_ui table element.
|
||||
*
|
||||
* @RenderElement("field_ui_table")
|
||||
*/
|
||||
class FieldUiTable extends RenderElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return array(
|
||||
'#theme' => 'field_ui_table',
|
||||
'#regions' => array('' => array()),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
146
core/modules/field_ui/src/EntityDisplayModeListBuilder.php
Normal file
146
core/modules/field_ui/src/EntityDisplayModeListBuilder.php
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\EntityDisplayModeListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of view mode entities.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Entity\EntityViewMode
|
||||
*/
|
||||
class EntityDisplayModeListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* All entity types.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface[]
|
||||
*/
|
||||
protected $entityTypes;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityDisplayModeListBuilder object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage class.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
|
||||
* List of all entity types.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, array $entity_types) {
|
||||
parent::__construct($entity_type, $storage);
|
||||
|
||||
$this->entityTypes = $entity_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
$entity_manager = $container->get('entity.manager');
|
||||
return new static(
|
||||
$entity_type,
|
||||
$entity_manager->getStorage($entity_type->id()),
|
||||
$entity_manager->getDefinitions()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['label'] = $this->t('Name');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['label'] = $this->getLabel($entity);
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load() {
|
||||
$entities = array();
|
||||
foreach (parent::load() as $entity) {
|
||||
$entities[$entity->getTargetType()][] = $entity;
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
$build = array();
|
||||
foreach ($this->load() as $entity_type => $entities) {
|
||||
if (!isset($this->entityTypes[$entity_type])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter entities.
|
||||
if (!$this->isValidEntity($entity_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table = array(
|
||||
'#prefix' => '<h2>' . $this->entityTypes[$entity_type]->getLabel() . '</h2>',
|
||||
'#type' => 'table',
|
||||
'#header' => $this->buildHeader(),
|
||||
'#rows' => array(),
|
||||
);
|
||||
foreach ($entities as $entity) {
|
||||
if ($row = $this->buildRow($entity)) {
|
||||
$table['#rows'][$entity->id()] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Move content at the top.
|
||||
if ($entity_type == 'node') {
|
||||
$table['#weight'] = -10;
|
||||
}
|
||||
|
||||
$short_type = str_replace(array('entity_', '_mode'), '', $this->entityTypeId);
|
||||
$table['#rows']['_add_new'][] = array(
|
||||
'data' => array(
|
||||
'#type' => 'link',
|
||||
'#url' => Url::fromRoute($short_type == 'view' ? 'entity.entity_view_mode.add_form' : 'entity.entity_form_mode.add_form', ['entity_type_id' => $entity_type]),
|
||||
'#title' => $this->t('Add new %label @entity-type', array('%label' => $this->entityTypes[$entity_type]->getLabel(), '@entity-type' => $this->entityType->getLowercaseLabel())),
|
||||
),
|
||||
'colspan' => count($table['#header']),
|
||||
);
|
||||
$build[$entity_type] = $table;
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters entities based on their controllers.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type of the entity that needs to be validated.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the entity has the correct controller, FALSE if the entity
|
||||
* doesn't has the correct controller.
|
||||
*/
|
||||
protected function isValidEntity($entity_type) {
|
||||
return $this->entityTypes[$entity_type]->get('field_ui_base_route') && $this->entityTypes[$entity_type]->hasViewBuilderClass();
|
||||
}
|
||||
|
||||
}
|
30
core/modules/field_ui/src/EntityFormModeListBuilder.php
Normal file
30
core/modules/field_ui/src/EntityFormModeListBuilder.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\EntityFormModeListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of form mode entities.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Entity\EntityFormMode
|
||||
*/
|
||||
class EntityFormModeListBuilder extends EntityDisplayModeListBuilder {
|
||||
|
||||
/**
|
||||
* Filters entities based on their controllers.
|
||||
*
|
||||
* @param $entity_type
|
||||
* The entity type of the entity that needs to be validated.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the entity has any forms, FALSE otherwise.
|
||||
*/
|
||||
protected function isValidEntity($entity_type) {
|
||||
return $this->entityTypes[$entity_type]->hasFormClasses();
|
||||
}
|
||||
|
||||
}
|
194
core/modules/field_ui/src/FieldConfigListBuilder.php
Normal file
194
core/modules/field_ui/src/FieldConfigListBuilder.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\FieldConfigListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides lists of field config entities.
|
||||
*/
|
||||
class FieldConfigListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* The name of the entity type the listed fields are attached to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $targetEntityTypeId;
|
||||
|
||||
/**
|
||||
* The name of the bundle the listed fields are attached to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $targetBundle;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The field type plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type manager
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
|
||||
parent::__construct($entity_type, $entity_manager->getStorage($entity_type->id()));
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static($entity_type, $container->get('entity.manager'), $container->get('plugin.manager.field.field_type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render($target_entity_type_id = NULL, $target_bundle = NULL) {
|
||||
$this->targetEntityTypeId = $target_entity_type_id;
|
||||
$this->targetBundle = $target_bundle;
|
||||
|
||||
$build = parent::render();
|
||||
$build['table']['#attributes']['id'] = 'field-overview';
|
||||
$build['table']['#empty'] = $this->t('No fields are present yet.');
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load() {
|
||||
$entities = array_filter($this->entityManager->getFieldDefinitions($this->targetEntityTypeId, $this->targetBundle), function ($field_definition) {
|
||||
return $field_definition instanceof FieldConfigInterface;
|
||||
});
|
||||
|
||||
// Sort the entities using the entity class's sort() method.
|
||||
// See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
|
||||
uasort($entities, array($this->entityType->getClass(), 'sort'));
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header = array(
|
||||
'label' => $this->t('Label'),
|
||||
'field_name' => array(
|
||||
'data' => $this->t('Machine name'),
|
||||
'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
|
||||
),
|
||||
'field_type' => $this->t('Field type'),
|
||||
);
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $field_config) {
|
||||
/** @var \Drupal\field\FieldConfigInterface $field_config */
|
||||
$field_storage = $field_config->getFieldStorageDefinition();
|
||||
$target_bundle_entity_type_id = $this->entityManager->getDefinition($this->targetEntityTypeId)->getBundleEntityType();
|
||||
$route_parameters = array(
|
||||
$target_bundle_entity_type_id => $this->targetBundle,
|
||||
'field_config' => $field_config->id(),
|
||||
);
|
||||
|
||||
$row = array(
|
||||
'id' => Html::getClass($field_config->getName()),
|
||||
'data' => array(
|
||||
'label' => SafeMarkup::checkPlain($field_config->getLabel()),
|
||||
'field_name' => $field_config->getName(),
|
||||
'field_type' => array(
|
||||
'data' => array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->fieldTypeManager->getDefinitions()[$field_storage->getType()]['label'],
|
||||
'#url' => Url::fromRoute("entity.field_config.{$this->targetEntityTypeId}_storage_edit_form", $route_parameters),
|
||||
'#options' => array('attributes' => array('title' => $this->t('Edit field settings.'))),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Add the operations.
|
||||
$row['data'] = $row['data'] + parent::buildRow($field_config);
|
||||
|
||||
if ($field_storage->isLocked()) {
|
||||
$row['data']['operations'] = array('data' => array('#markup' => $this->t('Locked')));
|
||||
$row['class'][] = 'menu-disabled';
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOperations(EntityInterface $entity) {
|
||||
/** @var \Drupal\field\FieldConfigInterface $entity */
|
||||
$operations = parent::getDefaultOperations($entity);
|
||||
|
||||
if ($entity->access('update') && $entity->hasLinkTemplate("{$entity->getTargetEntityTypeId()}-field-edit-form")) {
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'weight' => 10,
|
||||
'url' => $entity->urlInfo("{$entity->getTargetEntityTypeId()}-field-edit-form"),
|
||||
);
|
||||
}
|
||||
if ($entity->access('delete') && $entity->hasLinkTemplate("{$entity->getTargetEntityTypeId()}-field-delete-form")) {
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'weight' => 100,
|
||||
'url' => $entity->urlInfo("{$entity->getTargetEntityTypeId()}-field-delete-form"),
|
||||
);
|
||||
}
|
||||
|
||||
$operations['storage-settings'] = array(
|
||||
'title' => $this->t('Storage settings'),
|
||||
'weight' => 20,
|
||||
'attributes' => array('title' => $this->t('Edit storage settings.')),
|
||||
'url' => $entity->urlInfo("{$entity->getTargetEntityTypeId()}-storage-edit-form"),
|
||||
);
|
||||
$operations['edit']['attributes']['title'] = $this->t('Edit field settings.');
|
||||
$operations['delete']['attributes']['title'] = $this->t('Delete field.');
|
||||
|
||||
return $operations;
|
||||
}
|
||||
|
||||
}
|
132
core/modules/field_ui/src/FieldStorageConfigListBuilder.php
Normal file
132
core/modules/field_ui/src/FieldStorageConfigListBuilder.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\FieldStorageConfigListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of fields.
|
||||
*
|
||||
* @see \Drupal\field\Entity\Field
|
||||
* @see field_ui_entity_info()
|
||||
*/
|
||||
class FieldStorageConfigListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* An array of information about field types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldTypes;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* An array of entity bundle information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bundles;
|
||||
|
||||
/**
|
||||
* The field type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new FieldStorageConfigListBuilder object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The 'field type' plugin manager.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
|
||||
parent::__construct($entity_type, $entity_manager->getStorage($entity_type->id()));
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->bundles = entity_get_bundles();
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
$this->fieldTypes = $this->fieldTypeManager->getDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('plugin.manager.field.field_type')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['id'] = $this->t('Field name');
|
||||
$header['type'] = array(
|
||||
'data' => $this->t('Field type'),
|
||||
'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
|
||||
);
|
||||
$header['usage'] = $this->t('Used in');
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $field_storage) {
|
||||
if ($field_storage->isLocked()) {
|
||||
$row['class'] = array('menu-disabled');
|
||||
$row['data']['id'] = $this->t('@field_name (Locked)', array('@field_name' => $field_storage->getName()));
|
||||
}
|
||||
else {
|
||||
$row['data']['id'] = $field_storage->getName();
|
||||
}
|
||||
|
||||
$field_type = $this->fieldTypes[$field_storage->getType()];
|
||||
$row['data']['type'] = $this->t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['provider']));
|
||||
|
||||
$usage = array();
|
||||
foreach ($field_storage->getBundles() as $bundle) {
|
||||
$entity_type_id = $field_storage->getTargetEntityTypeId();
|
||||
if ($route_info = FieldUI::getOverviewRouteInfo($entity_type_id, $bundle)) {
|
||||
$usage[] = \Drupal::l($this->bundles[$entity_type_id][$bundle]['label'], $route_info);
|
||||
}
|
||||
else {
|
||||
$usage[] = $this->bundles[$entity_type_id][$bundle]['label'];
|
||||
}
|
||||
}
|
||||
$usage_escaped = '';
|
||||
$separator = '';
|
||||
foreach ($usage as $usage_item) {
|
||||
$usage_escaped .= $separator . SafeMarkup::escape($usage_item);
|
||||
$separator = ', ';
|
||||
}
|
||||
$row['data']['usage'] = SafeMarkup::set($usage_escaped);
|
||||
return $row;
|
||||
}
|
||||
|
||||
}
|
82
core/modules/field_ui/src/FieldUI.php
Normal file
82
core/modules/field_ui/src/FieldUI.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\FieldUI.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Static service container wrapper for Field UI.
|
||||
*/
|
||||
class FieldUI {
|
||||
|
||||
/**
|
||||
* Returns the route info for the field overview of a given entity bundle.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* An entity type.
|
||||
* @param string $bundle
|
||||
* The entity bundle.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* A URL object.
|
||||
*/
|
||||
public static function getOverviewRouteInfo($entity_type_id, $bundle) {
|
||||
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
|
||||
if ($entity_type->get('field_ui_base_route')) {
|
||||
return new Url("entity.{$entity_type_id}.field_ui_fields", static::getRouteBundleParameter($entity_type, $bundle));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next redirect path in a multipage sequence.
|
||||
*
|
||||
* @param array $destinations
|
||||
* An array of destinations to redirect to.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The next destination to redirect to.
|
||||
*/
|
||||
public static function getNextDestination(array $destinations) {
|
||||
$next_destination = array_shift($destinations);
|
||||
if (is_array($next_destination)) {
|
||||
$next_destination['options']['query']['destinations'] = $destinations;
|
||||
$next_destination += array(
|
||||
'route_parameters' => array(),
|
||||
);
|
||||
$next_destination = Url::fromRoute($next_destination['route_name'], $next_destination['route_parameters'], $next_destination['options']);
|
||||
}
|
||||
else {
|
||||
$options = UrlHelper::parse($next_destination);
|
||||
if ($destinations) {
|
||||
$options['query']['destinations'] = $destinations;
|
||||
}
|
||||
// Redirect to any given path within the same domain.
|
||||
// @todo Revisit this in https://www.drupal.org/node/2418219.
|
||||
$next_destination = Url::fromUserInput('/' . $options['path']);
|
||||
}
|
||||
return $next_destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the route parameter that should be used for Field UI routes.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The actual entity type, not the bundle (e.g. the content entity type).
|
||||
* @param string $bundle
|
||||
* The bundle name.
|
||||
*
|
||||
* @return array
|
||||
* An array that can be used a route parameter.
|
||||
*/
|
||||
public static function getRouteBundleParameter(EntityTypeInterface $entity_type, $bundle) {
|
||||
return array($entity_type->getBundleEntityType() => $bundle);
|
||||
}
|
||||
|
||||
}
|
74
core/modules/field_ui/src/FieldUiPermissions.php
Normal file
74
core/modules/field_ui/src/FieldUiPermissions.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\FieldUiPermissions.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides dynamic permissions of the field_ui module.
|
||||
*/
|
||||
class FieldUiPermissions implements ContainerInjectionInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new FieldUiPermissions instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('entity.manager'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of field UI permissions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fieldPermissions() {
|
||||
$permissions = [];
|
||||
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->get('field_ui_base_route')) {
|
||||
// Create a permission for each fieldable entity to manage
|
||||
// the fields and the display.
|
||||
$permissions['administer ' . $entity_type_id . ' fields'] = [
|
||||
'title' => $this->t('%entity_label: Administer fields', ['%entity_label' => $entity_type->getLabel()]),
|
||||
'restrict access' => TRUE,
|
||||
];
|
||||
$permissions['administer ' . $entity_type_id . ' form display'] = [
|
||||
'title' => $this->t('%entity_label: Administer form display', ['%entity_label' => $entity_type->getLabel()])
|
||||
];
|
||||
$permissions['administer ' . $entity_type_id . ' display'] = [
|
||||
'title' => $this->t('%entity_label: Administer display', ['%entity_label' => $entity_type->getLabel()])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
}
|
990
core/modules/field_ui/src/Form/EntityDisplayFormBase.php
Normal file
990
core/modules/field_ui/src/Form/EntityDisplayFormBase.php
Normal file
|
@ -0,0 +1,990 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityDisplayFormBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Component\Plugin\Factory\DefaultFactory;
|
||||
use Drupal\Component\Plugin\PluginManagerBase;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Field\PluginSettingsInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
|
||||
/**
|
||||
* Base class for EntityDisplay edit forms.
|
||||
*/
|
||||
abstract class EntityDisplayFormBase extends EntityForm {
|
||||
|
||||
/**
|
||||
* The display context. Either 'view' or 'form'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $displayContext;
|
||||
|
||||
/**
|
||||
* The widget or formatter plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerBase
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
/**
|
||||
* A list of field types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldTypes;
|
||||
|
||||
/**
|
||||
* The entity being used by this form.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Display\EntityDisplayInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityDisplayFormBase.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type manager.
|
||||
* @param \Drupal\Component\Plugin\PluginManagerBase $plugin_manager
|
||||
* The widget or formatter plugin manager.
|
||||
*/
|
||||
public function __construct(FieldTypePluginManagerInterface $field_type_manager, PluginManagerBase $plugin_manager) {
|
||||
$this->fieldTypes = $field_type_manager->getDefinitions();
|
||||
$this->pluginManager = $plugin_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
|
||||
$route_parameters = $route_match->getParameters()->all();
|
||||
|
||||
return $this->getEntityDisplay($route_parameters['entity_type_id'], $route_parameters['bundle'], $route_parameters[$this->displayContext . '_mode_name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the regions needed to create the overview form.
|
||||
*
|
||||
* @return array
|
||||
* Example usage:
|
||||
* @code
|
||||
* return array(
|
||||
* 'content' => array(
|
||||
* // label for the region.
|
||||
* 'title' => $this->t('Content'),
|
||||
* // Indicates if the region is visible in the UI.
|
||||
* 'invisible' => TRUE,
|
||||
* // A message to indicate that there is nothing to be displayed in
|
||||
* // the region.
|
||||
* 'message' => $this->t('No field is displayed.'),
|
||||
* ),
|
||||
* );
|
||||
* @endcode
|
||||
*/
|
||||
public function getRegions() {
|
||||
return array(
|
||||
'content' => array(
|
||||
'title' => $this->t('Content'),
|
||||
'invisible' => TRUE,
|
||||
'message' => $this->t('No field is displayed.')
|
||||
),
|
||||
'hidden' => array(
|
||||
'title' => $this->t('Disabled', array(), array('context' => 'Plural')),
|
||||
'message' => $this->t('No field is hidden.')
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array of all regions.
|
||||
*
|
||||
* @return array
|
||||
* An array containing the region options.
|
||||
*/
|
||||
public function getRegionOptions() {
|
||||
$options = array();
|
||||
foreach ($this->getRegions() as $region => $data) {
|
||||
$options[$region] = $data['title'];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the definitions of fields whose display is configurable.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldDefinitionInterface[]
|
||||
* The array of field definitions
|
||||
*/
|
||||
protected function getFieldDefinitions() {
|
||||
$context = $this->displayContext;
|
||||
return array_filter($this->entityManager->getFieldDefinitions($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle()), function(FieldDefinitionInterface $field_definition) use ($context) {
|
||||
return $field_definition->isDisplayConfigurable($context);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
$field_definitions = $this->getFieldDefinitions();
|
||||
$extra_fields = $this->getExtraFields();
|
||||
|
||||
$form += array(
|
||||
'#entity_type' => $this->entity->getTargetEntityTypeId(),
|
||||
'#bundle' => $this->entity->getTargetBundle(),
|
||||
'#fields' => array_keys($field_definitions),
|
||||
'#extra' => array_keys($extra_fields),
|
||||
);
|
||||
|
||||
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');
|
||||
return $form;
|
||||
}
|
||||
|
||||
$table = array(
|
||||
'#type' => 'field_ui_table',
|
||||
'#pre_render' => array(array($this, 'tablePreRender')),
|
||||
'#tree' => TRUE,
|
||||
'#header' => $this->getTableHeader(),
|
||||
'#regions' => $this->getRegions(),
|
||||
'#attributes' => array(
|
||||
'class' => array('field-ui-overview'),
|
||||
'id' => 'field-display-overview',
|
||||
),
|
||||
// Add Ajax wrapper.
|
||||
'#prefix' => '<div id="field-display-overview-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
'#tabledrag' => array(
|
||||
array(
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'field-weight',
|
||||
),
|
||||
array(
|
||||
'action' => 'match',
|
||||
'relationship' => 'parent',
|
||||
'group' => 'field-parent',
|
||||
'subgroup' => 'field-parent',
|
||||
'source' => 'field-name',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Field rows.
|
||||
foreach ($field_definitions as $field_name => $field_definition) {
|
||||
$table[$field_name] = $this->buildFieldRow($field_definition, $form, $form_state);
|
||||
}
|
||||
|
||||
// Non-field elements.
|
||||
foreach ($extra_fields as $field_id => $extra_field) {
|
||||
$table[$field_id] = $this->buildExtraFieldRow($field_id, $extra_field);
|
||||
}
|
||||
|
||||
$form['fields'] = $table;
|
||||
|
||||
// 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()) {
|
||||
$form['modes'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Custom display settings'),
|
||||
);
|
||||
// Collect options and default values for the 'Custom display settings'
|
||||
// checkboxes.
|
||||
$options = array();
|
||||
$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;
|
||||
}
|
||||
}
|
||||
$form['modes']['display_modes_custom'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Use custom display settings for the following modes'),
|
||||
'#options' => $options,
|
||||
'#default_value' => $default,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// In overviews involving nested rows from contributed modules (i.e
|
||||
// field_group), the 'plugin type' selects can trigger a series of changes
|
||||
// in child rows. The #ajax behavior is therefore not attached directly to
|
||||
// the selects, but triggered by the client-side script through a hidden
|
||||
// #ajax 'Refresh' button. A hidden 'refresh_rows' input tracks the name of
|
||||
// affected rows.
|
||||
$form['refresh_rows'] = array('#type' => 'hidden');
|
||||
$form['refresh'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Refresh'),
|
||||
'#op' => 'refresh_table',
|
||||
'#submit' => array('::multistepSubmit'),
|
||||
'#ajax' => array(
|
||||
'callback' => '::multistepAjax',
|
||||
'wrapper' => 'field-display-overview-wrapper',
|
||||
'effect' => 'fade',
|
||||
// The button stays hidden, so we hide the Ajax spinner too. Ad-hoc
|
||||
// spinners will be added manually by the client-side script.
|
||||
'progress' => 'none',
|
||||
),
|
||||
'#attributes' => array('class' => array('visually-hidden'))
|
||||
);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#button_type' => 'primary',
|
||||
'#value' => $this->t('Save'),
|
||||
);
|
||||
|
||||
$form['#attached']['library'][] = 'field_ui/drupal.field_ui';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the table row structure for a single field.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* A table row array.
|
||||
*/
|
||||
protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
$field_name = $field_definition->getName();
|
||||
$display_options = $this->entity->getComponent($field_name);
|
||||
$label = $field_definition->getLabel();
|
||||
|
||||
$regions = array_keys($this->getRegions());
|
||||
$field_row = array(
|
||||
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
|
||||
'#row_type' => 'field',
|
||||
'#region_callback' => array($this, 'getRowRegion'),
|
||||
'#js_settings' => array(
|
||||
'rowHandler' => 'field',
|
||||
'defaultPlugin' => $this->getDefaultPlugin($field_definition->getType()),
|
||||
),
|
||||
'human_name' => array(
|
||||
'#markup' => SafeMarkup::checkPlain($label),
|
||||
),
|
||||
'weight' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Weight for @title', array('@title' => $label)),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $display_options ? $display_options['weight'] : '0',
|
||||
'#size' => 3,
|
||||
'#attributes' => array('class' => array('field-weight')),
|
||||
),
|
||||
'parent_wrapper' => array(
|
||||
'parent' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Label display for @title', array('@title' => $label)),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => array_combine($regions, $regions),
|
||||
'#empty_value' => '',
|
||||
'#attributes' => array('class' => array('js-field-parent', 'field-parent')),
|
||||
'#parents' => array('fields', $field_name, 'parent'),
|
||||
),
|
||||
'hidden_name' => array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $field_name,
|
||||
'#attributes' => array('class' => array('field-name')),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$field_row['plugin'] = array(
|
||||
'type' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Plugin for @title', array('@title' => $label)),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $this->getPluginOptions($field_definition),
|
||||
'#default_value' => $display_options ? $display_options['type'] : 'hidden',
|
||||
'#parents' => array('fields', $field_name, 'type'),
|
||||
'#attributes' => array('class' => array('field-plugin-type')),
|
||||
),
|
||||
'settings_edit_form' => array(),
|
||||
);
|
||||
|
||||
// Get the corresponding plugin object.
|
||||
$plugin = $this->entity->getRenderer($field_name);
|
||||
|
||||
// Base button element for the various plugin settings actions.
|
||||
$base_button = array(
|
||||
'#submit' => array('::multistepSubmit'),
|
||||
'#ajax' => array(
|
||||
'callback' => '::multistepAjax',
|
||||
'wrapper' => 'field-display-overview-wrapper',
|
||||
'effect' => 'fade',
|
||||
),
|
||||
'#field_name' => $field_name,
|
||||
);
|
||||
|
||||
if ($form_state->get('plugin_settings_edit') == $field_name) {
|
||||
// We are currently editing this field's plugin settings. Display the
|
||||
// settings form and submit buttons.
|
||||
$field_row['plugin']['settings_edit_form'] = array();
|
||||
|
||||
if ($plugin) {
|
||||
// Generate the settings form and allow other modules to alter it.
|
||||
$settings_form = $plugin->settingsForm($form, $form_state);
|
||||
$third_party_settings_form = $this->thirdPartySettingsForm($plugin, $field_definition, $form, $form_state);
|
||||
|
||||
if ($settings_form || $third_party_settings_form) {
|
||||
$field_row['plugin']['#cell_attributes'] = array('colspan' => 3);
|
||||
$field_row['plugin']['settings_edit_form'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('field-plugin-settings-edit-form')),
|
||||
'#parents' => array('fields', $field_name, 'settings_edit_form'),
|
||||
'label' => array(
|
||||
'#markup' => $this->t('Plugin settings'),
|
||||
),
|
||||
'settings' => $settings_form,
|
||||
'third_party_settings' => $third_party_settings_form,
|
||||
'actions' => array(
|
||||
'#type' => 'actions',
|
||||
'save_settings' => $base_button + array(
|
||||
'#type' => 'submit',
|
||||
'#button_type' => 'primary',
|
||||
'#name' => $field_name . '_plugin_settings_update',
|
||||
'#value' => $this->t('Update'),
|
||||
'#op' => 'update',
|
||||
),
|
||||
'cancel_settings' => $base_button + array(
|
||||
'#type' => 'submit',
|
||||
'#name' => $field_name . '_plugin_settings_cancel',
|
||||
'#value' => $this->t('Cancel'),
|
||||
'#op' => 'cancel',
|
||||
// Do not check errors for the 'Cancel' button, but make sure we
|
||||
// get the value of the 'plugin type' select.
|
||||
'#limit_validation_errors' => array(array('fields', $field_name, 'type')),
|
||||
),
|
||||
),
|
||||
);
|
||||
$field_row['#attributes']['class'][] = 'field-plugin-settings-editing';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$field_row['settings_summary'] = array();
|
||||
$field_row['settings_edit'] = array();
|
||||
|
||||
if ($plugin) {
|
||||
// Display a summary of the current plugin settings, and (if the
|
||||
// summary is not empty) a button to edit them.
|
||||
$summary = $plugin->settingsSummary();
|
||||
|
||||
// Allow other modules to alter the summary.
|
||||
$this->alterSettingsSummary($summary, $plugin, $field_definition);
|
||||
|
||||
if (!empty($summary)) {
|
||||
$field_row['settings_summary'] = array(
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '<div class="field-plugin-summary">{{ summary|safe_join("<br />") }}</div>',
|
||||
'#context' => array('summary' => $summary),
|
||||
'#cell_attributes' => array('class' => array('field-plugin-summary-cell')),
|
||||
);
|
||||
}
|
||||
|
||||
// Check selected plugin settings to display edit link or not.
|
||||
$settings_form = $plugin->settingsForm($form, $form_state);
|
||||
$third_party_settings_form = $this->thirdPartySettingsForm($plugin, $field_definition, $form, $form_state);
|
||||
if (!empty($settings_form) || !empty($third_party_settings_form)) {
|
||||
$field_row['settings_edit'] = $base_button + array(
|
||||
'#type' => 'image_button',
|
||||
'#name' => $field_name . '_settings_edit',
|
||||
'#src' => 'core/misc/icons/787878/cog.svg',
|
||||
'#attributes' => array('class' => array('field-plugin-settings-edit'), 'alt' => $this->t('Edit')),
|
||||
'#op' => 'edit',
|
||||
// Do not check errors for the 'Edit' button, but make sure we get
|
||||
// the value of the 'plugin type' select.
|
||||
'#limit_validation_errors' => array(array('fields', $field_name, 'type')),
|
||||
'#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $field_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the table row structure for a single extra field.
|
||||
*
|
||||
* @param string $field_id
|
||||
* The field ID.
|
||||
* @param array $extra_field
|
||||
* The pseudo-field element.
|
||||
*
|
||||
* @return array
|
||||
* A table row array.
|
||||
*/
|
||||
protected function buildExtraFieldRow($field_id, $extra_field) {
|
||||
$display_options = $this->entity->getComponent($field_id);
|
||||
|
||||
$regions = array_keys($this->getRegions());
|
||||
$extra_field_row = array(
|
||||
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
|
||||
'#row_type' => 'extra_field',
|
||||
'#region_callback' => array($this, 'getRowRegion'),
|
||||
'#js_settings' => array('rowHandler' => 'field'),
|
||||
'human_name' => array(
|
||||
'#markup' => $extra_field['label'],
|
||||
),
|
||||
'weight' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Weight for @title', array('@title' => $extra_field['label'])),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $display_options ? $display_options['weight'] : 0,
|
||||
'#size' => 3,
|
||||
'#attributes' => array('class' => array('field-weight')),
|
||||
),
|
||||
'parent_wrapper' => array(
|
||||
'parent' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Parents for @title', array('@title' => $extra_field['label'])),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => array_combine($regions, $regions),
|
||||
'#empty_value' => '',
|
||||
'#attributes' => array('class' => array('js-field-parent', 'field-parent')),
|
||||
'#parents' => array('fields', $field_id, 'parent'),
|
||||
),
|
||||
'hidden_name' => array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $field_id,
|
||||
'#attributes' => array('class' => array('field-name')),
|
||||
),
|
||||
),
|
||||
'plugin' => array(
|
||||
'type' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Visibility for @title', array('@title' => $extra_field['label'])),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $this->getExtraFieldVisibilityOptions(),
|
||||
'#default_value' => $display_options ? 'visible' : 'hidden',
|
||||
'#parents' => array('fields', $field_id, 'type'),
|
||||
'#attributes' => array('class' => array('field-plugin-type')),
|
||||
),
|
||||
),
|
||||
'settings_summary' => array(),
|
||||
'settings_edit' => array(),
|
||||
);
|
||||
|
||||
return $extra_field_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// If the main "Save" button was submitted while a field settings subform
|
||||
// was being edited, update the new incoming settings when rebuilding the
|
||||
// entity, just as if the subform's "Update" button had been submitted.
|
||||
if ($edit_field = $form_state->get('plugin_settings_edit')) {
|
||||
$form_state->set('plugin_settings_update', $edit_field);
|
||||
}
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
$form_values = $form_state->getValues();
|
||||
|
||||
// Handle the 'display modes' checkboxes if present.
|
||||
if ($this->entity->getMode() == 'default' && !empty($form_values['display_modes_custom'])) {
|
||||
$display_modes = $this->getDisplayModes();
|
||||
$current_statuses = $this->getDisplayStatuses();
|
||||
|
||||
$statuses = array();
|
||||
foreach ($form_values['display_modes_custom'] as $mode => $value) {
|
||||
if (!empty($value) && empty($current_statuses[$mode])) {
|
||||
// If no display exists for the newly enabled view mode, initialize
|
||||
// it with those from the 'default' view mode, which were used so
|
||||
// far.
|
||||
if (!$this->entityManager->getStorage($this->entity->getEntityTypeId())->load($this->entity->getTargetEntityTypeId() . '.' . $this->entity->getTargetBundle() . '.' . $mode)) {
|
||||
$display = $this->getEntityDisplay($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle(), 'default')->createCopy($mode);
|
||||
$display->save();
|
||||
}
|
||||
|
||||
$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()]));
|
||||
}
|
||||
$statuses[$mode] = !empty($value);
|
||||
}
|
||||
|
||||
$this->saveDisplayStatuses($statuses);
|
||||
}
|
||||
|
||||
drupal_set_message($this->t('Your settings have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
|
||||
$form_values = $form_state->getValues();
|
||||
|
||||
if ($this->entity instanceof EntityWithPluginCollectionInterface) {
|
||||
// Do not manually update values represented by plugin collections.
|
||||
$form_values = array_diff_key($form_values, $this->entity->getPluginCollections());
|
||||
}
|
||||
|
||||
// Collect data for 'regular' fields.
|
||||
foreach ($form['#fields'] as $field_name) {
|
||||
$values = $form_values['fields'][$field_name];
|
||||
|
||||
if ($values['type'] == 'hidden') {
|
||||
$entity->removeComponent($field_name);
|
||||
}
|
||||
else {
|
||||
$options = $entity->getComponent($field_name);
|
||||
|
||||
// Update field settings only if the submit handler told us to.
|
||||
if ($form_state->get('plugin_settings_update') === $field_name) {
|
||||
// Only store settings actually used by the selected plugin.
|
||||
$default_settings = $this->pluginManager->getDefaultSettings($options['type']);
|
||||
$options['settings'] = array_intersect_key($values['settings_edit_form']['settings'], $default_settings);
|
||||
$options['third_party_settings'] = isset($values['settings_edit_form']['third_party_settings']) ? $values['settings_edit_form']['third_party_settings'] : [];
|
||||
$form_state->set('plugin_settings_update', NULL);
|
||||
}
|
||||
|
||||
$options['type'] = $values['type'];
|
||||
$options['weight'] = $values['weight'];
|
||||
// Only formatters have configurable label visibility.
|
||||
if (isset($values['label'])) {
|
||||
$options['label'] = $values['label'];
|
||||
}
|
||||
$entity->setComponent($field_name, $options);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect data for 'extra' fields.
|
||||
foreach ($form['#extra'] as $name) {
|
||||
if ($form_values['fields'][$name]['type'] == 'hidden') {
|
||||
$entity->removeComponent($name);
|
||||
}
|
||||
else {
|
||||
$entity->setComponent($name, array(
|
||||
'weight' => $form_values['fields'][$name]['weight'],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for multistep buttons.
|
||||
*/
|
||||
public function multistepSubmit($form, FormStateInterface $form_state) {
|
||||
$trigger = $form_state->getTriggeringElement();
|
||||
$op = $trigger['#op'];
|
||||
|
||||
switch ($op) {
|
||||
case 'edit':
|
||||
// Store the field whose settings are currently being edited.
|
||||
$field_name = $trigger['#field_name'];
|
||||
$form_state->set('plugin_settings_edit', $field_name);
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
// Set the field back to 'non edit' mode, and update $this->entity with
|
||||
// the new settings fro the next rebuild.
|
||||
$field_name = $trigger['#field_name'];
|
||||
$form_state->set('plugin_settings_edit', NULL);
|
||||
$form_state->set('plugin_settings_update', $field_name);
|
||||
$this->entity = $this->buildEntity($form, $form_state);
|
||||
break;
|
||||
|
||||
case 'cancel':
|
||||
// Set the field back to 'non edit' mode.
|
||||
$form_state->set('plugin_settings_edit', NULL);
|
||||
break;
|
||||
|
||||
case 'refresh_table':
|
||||
// If the currently edited field is one of the rows to be refreshed, set
|
||||
// it back to 'non edit' mode.
|
||||
$updated_rows = explode(' ', $form_state->getValue('refresh_rows'));
|
||||
$plugin_settings_edit = $form_state->get('plugin_settings_edit');
|
||||
if ($plugin_settings_edit && in_array($plugin_settings_edit, $updated_rows)) {
|
||||
$form_state->set('plugin_settings_edit', NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handler for multistep buttons.
|
||||
*/
|
||||
public function multistepAjax($form, FormStateInterface $form_state) {
|
||||
$trigger = $form_state->getTriggeringElement();
|
||||
$op = $trigger['#op'];
|
||||
|
||||
// Pick the elements that need to receive the ajax-new-content effect.
|
||||
switch ($op) {
|
||||
case 'edit':
|
||||
$updated_rows = array($trigger['#field_name']);
|
||||
$updated_columns = array('plugin');
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
case 'cancel':
|
||||
$updated_rows = array($trigger['#field_name']);
|
||||
$updated_columns = array('plugin', 'settings_summary', 'settings_edit');
|
||||
break;
|
||||
|
||||
case 'refresh_table':
|
||||
$updated_rows = array_values(explode(' ', $form_state->getValue('refresh_rows')));
|
||||
$updated_columns = array('settings_summary', 'settings_edit');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($updated_rows as $name) {
|
||||
foreach ($updated_columns as $key) {
|
||||
$element = &$form['fields'][$name][$key];
|
||||
$element['#prefix'] = '<div class="ajax-new-content">' . (isset($element['#prefix']) ? $element['#prefix'] : '');
|
||||
$element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Return the whole table.
|
||||
return $form['fields'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs pre-render tasks on field_ui_table elements.
|
||||
*
|
||||
* This function is assigned as a #pre_render callback in
|
||||
* field_ui_element_info().
|
||||
*
|
||||
* @param array $elements
|
||||
* A structured array containing two sub-levels of elements. Properties
|
||||
* used:
|
||||
* - #tabledrag: The value is a list of $options arrays that are passed to
|
||||
* drupal_attach_tabledrag(). The HTML ID of the table is added to each
|
||||
* $options array.
|
||||
*
|
||||
* @see drupal_render()
|
||||
* @see \Drupal\Core\Render\Element\Table::preRenderTable()
|
||||
*/
|
||||
public function tablePreRender($elements) {
|
||||
$js_settings = array();
|
||||
|
||||
// For each region, build the tree structure from the weight and parenting
|
||||
// data contained in the flat form structure, to determine row order and
|
||||
// indentation.
|
||||
$regions = $elements['#regions'];
|
||||
$tree = array('' => array('name' => '', 'children' => array()));
|
||||
$trees = array_fill_keys(array_keys($regions), $tree);
|
||||
|
||||
$parents = array();
|
||||
$children = Element::children($elements);
|
||||
$list = array_combine($children, $children);
|
||||
|
||||
// Iterate on rows until we can build a known tree path for all of them.
|
||||
while ($list) {
|
||||
foreach ($list as $name) {
|
||||
$row = &$elements[$name];
|
||||
$parent = $row['parent_wrapper']['parent']['#value'];
|
||||
// Proceed if parent is known.
|
||||
if (empty($parent) || isset($parents[$parent])) {
|
||||
// Grab parent, and remove the row from the next iteration.
|
||||
$parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array();
|
||||
unset($list[$name]);
|
||||
|
||||
// Determine the region for the row.
|
||||
$region_name = call_user_func($row['#region_callback'], $row);
|
||||
|
||||
// Add the element in the tree.
|
||||
$target = &$trees[$region_name][''];
|
||||
foreach ($parents[$name] as $key) {
|
||||
$target = &$target['children'][$key];
|
||||
}
|
||||
$target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']);
|
||||
|
||||
// Add tabledrag indentation to the first row cell.
|
||||
if ($depth = count($parents[$name])) {
|
||||
$children = Element::children($row);
|
||||
$cell = current($children);
|
||||
$indentation = array(
|
||||
'#theme' => 'indentation',
|
||||
'#size' => $depth,
|
||||
);
|
||||
$row[$cell]['#prefix'] = drupal_render($indentation) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
|
||||
}
|
||||
|
||||
// Add row id and associate JS settings.
|
||||
$id = Html::getClass($name);
|
||||
$row['#attributes']['id'] = $id;
|
||||
if (isset($row['#js_settings'])) {
|
||||
$row['#js_settings'] += array(
|
||||
'rowHandler' => $row['#row_type'],
|
||||
'name' => $name,
|
||||
'region' => $region_name,
|
||||
);
|
||||
$js_settings[$id] = $row['#js_settings'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Determine rendering order from the tree structure.
|
||||
foreach ($regions as $region_name => $region) {
|
||||
$elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], array($this, 'reduceOrder'));
|
||||
}
|
||||
|
||||
$elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;
|
||||
|
||||
// If the custom #tabledrag is set and there is a HTML ID, add the table's
|
||||
// HTML ID to the options and attach the behavior.
|
||||
// @see \Drupal\Core\Render\Element\Table::preRenderTable()
|
||||
if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
|
||||
foreach ($elements['#tabledrag'] as $options) {
|
||||
$options['table_id'] = $elements['#attributes']['id'];
|
||||
drupal_attach_tabledrag($elements, $options);
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the rendering order of an array representing a tree.
|
||||
*
|
||||
* Callback for array_reduce() within
|
||||
* \Drupal\field_ui\Form\EntityDisplayFormBase::tablePreRender().
|
||||
*/
|
||||
public function reduceOrder($array, $a) {
|
||||
$array = !isset($array) ? array() : $array;
|
||||
if ($a['name']) {
|
||||
$array[] = $a['name'];
|
||||
}
|
||||
if (!empty($a['children'])) {
|
||||
uasort($a['children'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
|
||||
$array = array_merge($array, array_reduce($a['children'], array($this, 'reduceOrder')));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra fields of the entity type and bundle used by this form.
|
||||
*
|
||||
* @return array
|
||||
* An array of extra field info.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityManagerInterface::getExtraFields()
|
||||
*/
|
||||
protected function getExtraFields() {
|
||||
$context = $this->displayContext == 'view' ? 'display' : $this->displayContext;
|
||||
$extra_fields = $this->entityManager->getExtraFields($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle());
|
||||
return isset($extra_fields[$context]) ? $extra_fields[$context] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an entity display object to be used by this form.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The target entity type ID of the entity display.
|
||||
* @param string $bundle
|
||||
* The target bundle of the entity display.
|
||||
* @param string $mode
|
||||
* A view or form mode.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Display\EntityDisplayInterface
|
||||
* An entity display.
|
||||
*/
|
||||
abstract protected function getEntityDisplay($entity_type_id, $bundle, $mode);
|
||||
|
||||
/**
|
||||
* Returns an array of widget or formatter options for a field.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
*
|
||||
* @return array
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
return $applicable_options + array('hidden' => '- ' . $this->t('Hidden') . ' -');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the default widget or formatter plugin for a field type.
|
||||
*
|
||||
* @param string $field_type
|
||||
* The field type.
|
||||
*
|
||||
* @return string
|
||||
* The widget or formatter plugin ID.
|
||||
*/
|
||||
abstract protected function getDefaultPlugin($field_type);
|
||||
|
||||
/**
|
||||
* Returns the form or view modes used by this form.
|
||||
*
|
||||
* @return array
|
||||
* An array of form or view mode info.
|
||||
*/
|
||||
abstract protected function getDisplayModes();
|
||||
|
||||
/**
|
||||
* Returns the region to which a row in the display overview belongs.
|
||||
*
|
||||
* @param array $row
|
||||
* The row element.
|
||||
*
|
||||
* @return string|null
|
||||
* The region name this row belongs to.
|
||||
*/
|
||||
public function getRowRegion($row) {
|
||||
switch ($row['#row_type']) {
|
||||
case 'field':
|
||||
case 'extra_field':
|
||||
return ($row['plugin']['type']['#value'] == 'hidden' ? 'hidden' : 'content');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of visibility options for extra fields.
|
||||
*
|
||||
* @return array
|
||||
* An array of visibility options.
|
||||
*/
|
||||
protected function getExtraFieldVisibilityOptions() {
|
||||
return array(
|
||||
'visible' => $this->t('Visible'),
|
||||
'hidden' => '- ' . $this->t('Hidden') . ' -',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entity (form) displays for the current entity display type.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Display\EntityDisplayInterface[]
|
||||
* An array holding entity displays or entity form displays.
|
||||
*/
|
||||
protected function getDisplays() {
|
||||
$load_ids = array();
|
||||
$display_entity_type = $this->entity->getEntityTypeId();
|
||||
$entity_type = $this->entityManager->getDefinition($display_entity_type);
|
||||
$config_prefix = $entity_type->getConfigPrefix();
|
||||
$ids = $this->configFactory()->listAll($config_prefix . '.' . $this->entity->getTargetEntityTypeId() . '.' . $this->entity->getTargetBundle() . '.');
|
||||
foreach ($ids as $id) {
|
||||
$config_id = str_replace($config_prefix . '.', '', $id);
|
||||
list(,, $display_mode) = explode('.', $config_id);
|
||||
if ($display_mode != 'default') {
|
||||
$load_ids[] = $config_id;
|
||||
}
|
||||
}
|
||||
return $this->entityManager->getStorage($display_entity_type)->loadMultiple($load_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns form or view modes statuses for the bundle used by this form.
|
||||
*
|
||||
* @return array
|
||||
* An array of form or view mode statuses.
|
||||
*/
|
||||
protected function getDisplayStatuses() {
|
||||
$display_statuses = array();
|
||||
$displays = $this->getDisplays();
|
||||
foreach ($displays as $display) {
|
||||
$display_statuses[$display->get('mode')] = $display->status();
|
||||
}
|
||||
return $display_statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the updated display mode statuses.
|
||||
*
|
||||
* @param array $display_statuses
|
||||
* An array holding updated form or view mode statuses.
|
||||
*/
|
||||
protected function saveDisplayStatuses($display_statuses) {
|
||||
$displays = $this->getDisplays();
|
||||
foreach ($displays as $display) {
|
||||
$display->set('status', $display_statuses[$display->get('mode')]);
|
||||
$display->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the table headers.
|
||||
*
|
||||
* @return array
|
||||
* The table header.
|
||||
*/
|
||||
abstract protected function getTableHeader();
|
||||
|
||||
/**
|
||||
* Returns the Url object for a specific entity (form) display edit form.
|
||||
*
|
||||
* @param string $mode
|
||||
* The form or view mode.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* A Url object for the overview route.
|
||||
*/
|
||||
abstract protected function getOverviewUrl($mode);
|
||||
|
||||
/**
|
||||
* Adds the widget or formatter third party settings forms.
|
||||
*
|
||||
* @param \Drupal\Core\Field\PluginSettingsInterface $plugin
|
||||
* The widget or formatter.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $form
|
||||
* The (entire) configuration form array.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The form state.
|
||||
*
|
||||
* @return array
|
||||
* The widget or formatter third party settings form.
|
||||
*/
|
||||
abstract protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Alters the widget or formatter settings summary.
|
||||
*
|
||||
* @param array $summary
|
||||
* The widget or formatter settings summary.
|
||||
* @param \Drupal\Core\Field\PluginSettingsInterface $plugin
|
||||
* The widget or formatter.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
*/
|
||||
abstract protected function alterSettingsSummary(array &$summary, PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition);
|
||||
|
||||
}
|
59
core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php
Normal file
59
core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityDisplayModeAddForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Provides the add form for entity display modes.
|
||||
*/
|
||||
class EntityDisplayModeAddForm extends EntityDisplayModeFormBase {
|
||||
|
||||
/**
|
||||
* The entity type for which the display mode is being created.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $targetEntityTypeId;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
|
||||
$this->targetEntityTypeId = $entity_type_id;
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
// Change replace_pattern to avoid undesired dots.
|
||||
$form['id']['#machine_name']['replace_pattern'] = '[^a-z0-9_]+';
|
||||
$definition = $this->entityManager->getDefinition($this->targetEntityTypeId);
|
||||
$form['#title'] = $this->t('Add new %label @entity-type', array('%label' => $definition->getLabel(), '@entity-type' => $this->entityType->getLowercaseLabel()));
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
|
||||
$form_state->setValueForElement($form['id'], $this->targetEntityTypeId . '.' . $form_state->getValue('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEntity() {
|
||||
$definition = $this->entityManager->getDefinition($this->targetEntityTypeId);
|
||||
if (!$definition->get('field_ui_base_route') || !$definition->hasViewBuilderClass()) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$this->entity->setTargetType($this->targetEntityTypeId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityDisplayModeDeleteForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
|
||||
/**
|
||||
* Provides the delete form for entity display modes.
|
||||
*/
|
||||
class EntityDisplayModeDeleteForm extends EntityDeleteForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
$entity_type = $this->entity->getEntityType();
|
||||
return $this->t('Deleting a @entity-type will cause any output still requesting to use that @entity-type to use the default display settings.', array('@entity-type' => $entity_type->getLowercaseLabel()));
|
||||
}
|
||||
|
||||
}
|
15
core/modules/field_ui/src/Form/EntityDisplayModeEditForm.php
Normal file
15
core/modules/field_ui/src/Form/EntityDisplayModeEditForm.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityDisplayModeEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
/**
|
||||
* Provides the edit form for entity display modes.
|
||||
*/
|
||||
class EntityDisplayModeEditForm extends EntityDisplayModeFormBase {
|
||||
|
||||
}
|
131
core/modules/field_ui/src/Form/EntityDisplayModeFormBase.php
Normal file
131
core/modules/field_ui/src/Form/EntityDisplayModeFormBase.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityDisplayModeFormBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides the generic base class for entity display mode forms.
|
||||
*/
|
||||
abstract class EntityDisplayModeFormBase extends EntityForm {
|
||||
|
||||
/**
|
||||
* The entity query factory.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||
*/
|
||||
protected $queryFactory;
|
||||
|
||||
/**
|
||||
* The entity type definition.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityDisplayModeFormBase.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
|
||||
* The entity query factory.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(QueryFactory $query_factory, EntityManagerInterface $entity_manager) {
|
||||
$this->queryFactory = $query_factory;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.query'),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function init(FormStateInterface $form_state) {
|
||||
parent::init($form_state);
|
||||
$this->entityType = $this->entityManager->getDefinition($this->entity->getEntityTypeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Name'),
|
||||
'#maxlength' => 100,
|
||||
'#default_value' => $this->entity->label(),
|
||||
);
|
||||
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#description' => $this->t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
|
||||
'#disabled' => !$this->entity->isNew(),
|
||||
'#default_value' => $this->entity->id(),
|
||||
'#field_prefix' => $this->entity->isNew() ? $this->entity->getTargetType() . '.' : '',
|
||||
'#machine_name' => array(
|
||||
'exists' => array($this, 'exists'),
|
||||
'replace_pattern' => '[^a-z0-9_.]+',
|
||||
),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the display mode already exists.
|
||||
*
|
||||
* @param string|int $entity_id
|
||||
* The entity ID.
|
||||
* @param array $element
|
||||
* The form element.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the display mode exists, FALSE otherwise.
|
||||
*/
|
||||
public function exists($entity_id, array $element) {
|
||||
// Do not allow to add internal 'default' view mode.
|
||||
if ($entity_id == 'default') {
|
||||
return TRUE;
|
||||
}
|
||||
return (bool) $this->queryFactory
|
||||
->get($this->entity->getEntityTypeId())
|
||||
->condition('id', $element['#field_prefix'] . $entity_id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
drupal_set_message($this->t('Saved the %label @entity-type.', array('%label' => $this->entity->label(), '@entity-type' => $this->entityType->getLowercaseLabel())));
|
||||
$this->entity->save();
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
|
||||
}
|
129
core/modules/field_ui/src/Form/EntityFormDisplayEditForm.php
Normal file
129
core/modules/field_ui/src/Form/EntityFormDisplayEditForm.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityFormDisplayEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\PluginSettingsInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Edit form for the EntityFormDisplay entity type.
|
||||
*/
|
||||
class EntityFormDisplayEditForm extends EntityDisplayFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $displayContext = 'form';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('plugin.manager.field.widget')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
$field_row = parent::buildFieldRow($field_definition, $form, $form_state);
|
||||
|
||||
$field_name = $field_definition->getName();
|
||||
|
||||
// Update the (invisible) title of the 'plugin' column.
|
||||
$field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $field_definition->getLabel()));
|
||||
if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $this->entity->getRenderer($field_name))) {
|
||||
$plugin_type_info = $plugin->getPluginDefinition();
|
||||
$field_row['plugin']['settings_edit_form']['label']['#markup'] = $this->t('Widget settings:') . ' <span class="plugin-name">' . $plugin_type_info['label'] . '</span>';
|
||||
}
|
||||
|
||||
return $field_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityDisplay($entity_type_id, $bundle, $mode) {
|
||||
return entity_get_form_display($entity_type_id, $bundle, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultPlugin($field_type) {
|
||||
return isset($this->fieldTypes[$field_type]['default_widget']) ? $this->fieldTypes[$field_type]['default_widget'] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDisplayModes() {
|
||||
return $this->entityManager->getFormModes($this->entity->getTargetEntityTypeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTableHeader() {
|
||||
return array(
|
||||
$this->t('Field'),
|
||||
$this->t('Weight'),
|
||||
$this->t('Parent'),
|
||||
array('data' => $this->t('Widget'), 'colspan' => 3),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getOverviewUrl($mode) {
|
||||
$entity_type = $this->entityManager->getDefinition($this->entity->getTargetEntityTypeId());
|
||||
return Url::fromRoute('entity.entity_form_display.' . $this->entity->getTargetEntityTypeId() . '.form_mode', [
|
||||
'form_mode_name' => $mode,
|
||||
] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
$settings_form = array();
|
||||
// Invoke hook_field_widget_third_party_settings_form(), keying resulting
|
||||
// subforms by module name.
|
||||
foreach ($this->moduleHandler->getImplementations('field_widget_third_party_settings_form') as $module) {
|
||||
$settings_form[$module] = $this->moduleHandler->invoke($module, 'field_widget_third_party_settings_form', array(
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state,
|
||||
));
|
||||
}
|
||||
return $settings_form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterSettingsSummary(array &$summary, PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition) {
|
||||
$context = array(
|
||||
'widget' => $plugin,
|
||||
'field_definition' => $field_definition,
|
||||
'form_mode' => $this->entity->getMode(),
|
||||
);
|
||||
$this->moduleHandler->alter('field_widget_settings_summary', $summary, $context);
|
||||
}
|
||||
|
||||
}
|
29
core/modules/field_ui/src/Form/EntityFormModeAddForm.php
Normal file
29
core/modules/field_ui/src/Form/EntityFormModeAddForm.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityFormModeAddForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Provides the add form for entity display modes.
|
||||
*/
|
||||
class EntityFormModeAddForm extends EntityDisplayModeAddForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareEntity() {
|
||||
$definition = $this->entityManager->getDefinition($this->targetEntityTypeId);
|
||||
if (!$definition->get('field_ui_base_route') || !$definition->hasFormClasses()) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$this->entity->setTargetType($this->targetEntityTypeId);
|
||||
}
|
||||
|
||||
}
|
178
core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
Normal file
178
core/modules/field_ui/src/Form/EntityViewDisplayEditForm.php
Normal file
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\EntityViewDisplayEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\PluginSettingsInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Edit form for the EntityViewDisplay entity type.
|
||||
*/
|
||||
class EntityViewDisplayEditForm extends EntityDisplayFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $displayContext = 'view';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('plugin.manager.field.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
$field_row = parent::buildFieldRow($field_definition, $form, $form_state);
|
||||
|
||||
$field_name = $field_definition->getName();
|
||||
$display_options = $this->entity->getComponent($field_name);
|
||||
|
||||
// Insert the label column.
|
||||
$label = array(
|
||||
'label' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Label display for @title', array('@title' => $field_definition->getLabel())),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $this->getFieldLabelOptions(),
|
||||
'#default_value' => $display_options ? $display_options['label'] : 'above',
|
||||
),
|
||||
);
|
||||
|
||||
$label_position = array_search('plugin', array_keys($field_row));
|
||||
$field_row = array_slice($field_row, 0, $label_position, TRUE) + $label + array_slice($field_row, $label_position, count($field_row) - 1, TRUE);
|
||||
|
||||
// Update the (invisible) title of the 'plugin' column.
|
||||
$field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $field_definition->getLabel()));
|
||||
if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $this->entity->getRenderer($field_name))) {
|
||||
$plugin_type_info = $plugin->getPluginDefinition();
|
||||
$field_row['plugin']['settings_edit_form']['label']['#markup'] = $this->t('Format settings:') . ' <span class="plugin-name">' . $plugin_type_info['label'] . '</span>';
|
||||
}
|
||||
|
||||
return $field_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildExtraFieldRow($field_id, $extra_field) {
|
||||
$extra_field_row = parent::buildExtraFieldRow($field_id, $extra_field);
|
||||
|
||||
// Insert an empty placeholder for the label column.
|
||||
$label = array(
|
||||
'empty_cell' => array(
|
||||
'#markup' => ' '
|
||||
)
|
||||
);
|
||||
$label_position = array_search('plugin', array_keys($extra_field_row));
|
||||
$extra_field_row = array_slice($extra_field_row, 0, $label_position, TRUE) + $label + array_slice($extra_field_row, $label_position, count($extra_field_row) - 1, TRUE);
|
||||
|
||||
return $extra_field_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityDisplay($entity_type_id, $bundle, $mode) {
|
||||
return entity_get_display($entity_type_id, $bundle, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultPlugin($field_type) {
|
||||
return isset($this->fieldTypes[$field_type]['default_formatter']) ? $this->fieldTypes[$field_type]['default_formatter'] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDisplayModes() {
|
||||
return $this->entityManager->getViewModes($this->entity->getTargetEntityTypeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTableHeader() {
|
||||
return array(
|
||||
$this->t('Field'),
|
||||
$this->t('Weight'),
|
||||
$this->t('Parent'),
|
||||
$this->t('Label'),
|
||||
array('data' => $this->t('Format'), 'colspan' => 3),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getOverviewUrl($mode) {
|
||||
$entity_type = $this->entityManager->getDefinition($this->entity->getTargetEntityTypeId());
|
||||
return Url::fromRoute('entity.entity_view_display.' . $this->entity->getTargetEntityTypeId() . '.view_mode', [
|
||||
'view_mode_name' => $mode,
|
||||
] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of visibility options for field labels.
|
||||
*
|
||||
* @return array
|
||||
* An array of visibility options.
|
||||
*/
|
||||
protected function getFieldLabelOptions() {
|
||||
return array(
|
||||
'above' => $this->t('Above'),
|
||||
'inline' => $this->t('Inline'),
|
||||
'hidden' => '- ' . $this->t('Hidden') . ' -',
|
||||
'visually_hidden' => '- ' . $this->t('Visually Hidden') . ' -',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
|
||||
$settings_form = array();
|
||||
// Invoke hook_field_formatter_third_party_settings_form(), keying resulting
|
||||
// subforms by module name.
|
||||
foreach ($this->moduleHandler->getImplementations('field_formatter_third_party_settings_form') as $module) {
|
||||
$settings_form[$module] = $this->moduleHandler->invoke($module, 'field_formatter_third_party_settings_form', array(
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state,
|
||||
));
|
||||
}
|
||||
return $settings_form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterSettingsSummary(array &$summary, PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition) {
|
||||
$context = array(
|
||||
'formatter' => $plugin,
|
||||
'field_definition' => $field_definition,
|
||||
'view_mode' => $this->entity->getMode(),
|
||||
);
|
||||
$this->moduleHandler->alter('field_formatter_settings_summary', $summary, $context);
|
||||
}
|
||||
|
||||
}
|
81
core/modules/field_ui/src/Form/FieldConfigDeleteForm.php
Normal file
81
core/modules/field_ui/src/Form/FieldConfigDeleteForm.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\FieldConfigDeleteForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for removing a field from a bundle.
|
||||
*/
|
||||
class FieldConfigDeleteForm extends EntityDeleteForm {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new FieldConfigDeleteForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return FieldUI::getOverviewRouteInfo($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$field_storage = $this->entity->getFieldStorageDefinition();
|
||||
$bundles = $this->entityManager->getBundleInfo($this->entity->getTargetEntityTypeId());
|
||||
$bundle_label = $bundles[$this->entity->getTargetBundle()]['label'];
|
||||
|
||||
if ($field_storage && !$field_storage->isLocked()) {
|
||||
$this->entity->delete();
|
||||
drupal_set_message($this->t('The field %field has been deleted from the %type content type.', array('%field' => $this->entity->label(), '%type' => $bundle_label)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('There was a problem removing the %field from the %type content type.', array('%field' => $this->entity->label(), '%type' => $bundle_label)), 'error');
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
|
||||
// Fields are purged on cron. However field module prevents disabling modules
|
||||
// when field types they provided are used in a field until it is fully
|
||||
// purged. In the case that a field has minimal or no content, a single call
|
||||
// to field_purge_batch() will remove it from the system. Call this with a
|
||||
// low batch limit to avoid administrators having to wait for cron runs when
|
||||
// removing fields that meet this criteria.
|
||||
field_purge_batch(10);
|
||||
}
|
||||
|
||||
}
|
208
core/modules/field_ui/src/Form/FieldConfigEditForm.php
Normal file
208
core/modules/field_ui/src/Form/FieldConfigEditForm.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\FieldConfigEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Field\AllowedTagsXssTrait;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
|
||||
/**
|
||||
* Provides a form for the field settings form.
|
||||
*/
|
||||
class FieldConfigEditForm extends EntityForm {
|
||||
|
||||
use AllowedTagsXssTrait;
|
||||
|
||||
/**
|
||||
* The entity being used by this form.
|
||||
*
|
||||
* @var \Drupal\field\FieldConfigInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
$field_storage = $this->entity->getFieldStorageDefinition();
|
||||
$bundles = $this->entityManager->getBundleInfo($this->entity->getTargetEntityTypeId());
|
||||
|
||||
$form_title = $this->t('%field settings for %bundle', array(
|
||||
'%field' => $this->entity->getLabel(),
|
||||
'%bundle' => $bundles[$this->entity->getTargetBundle()]['label'],
|
||||
));
|
||||
$form['#title'] = $form_title;
|
||||
|
||||
if ($field_storage->isLocked()) {
|
||||
$form['locked'] = array(
|
||||
'#markup' => $this->t('The field %field is locked and cannot be edited.', array('%field' => $this->entity->getLabel())),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
// Build the configurable field values.
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#default_value' => $this->entity->getLabel() ?: $field_storage->getName(),
|
||||
'#required' => TRUE,
|
||||
'#weight' => -20,
|
||||
);
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#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' => $this->displayAllowedTags())) . '<br />' . $this->t('This field supports tokens.'),
|
||||
'#weight' => -10,
|
||||
);
|
||||
|
||||
$form['required'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Required field'),
|
||||
'#default_value' => $this->entity->isRequired(),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
// Create an arbitrary entity object (used by the 'default value' widget).
|
||||
$ids = (object) array(
|
||||
'entity_type' => $this->entity->getTargetEntityTypeId(),
|
||||
'bundle' => $this->entity->getTargetBundle(),
|
||||
'entity_id' => NULL
|
||||
);
|
||||
$form['#entity'] = _field_create_entity_from_ids($ids);
|
||||
$items = $form['#entity']->get($this->entity->getName());
|
||||
$item = $items->first() ?: $items->appendItem();
|
||||
|
||||
// Add field settings for the field type and a container for third party
|
||||
// settings that modules can add to via hook_form_FORM_ID_alter().
|
||||
$form['settings'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#weight' => 10,
|
||||
);
|
||||
$form['settings'] += $item->fieldSettingsForm($form, $form_state);
|
||||
$form['third_party_settings'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#weight' => 11,
|
||||
);
|
||||
|
||||
// Add handling for default value.
|
||||
if ($element = $items->defaultValuesForm($form, $form_state)) {
|
||||
$element = array_merge($element , array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Default value'),
|
||||
'#open' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
'#description' => $this->t('The default value for this field, used when creating new content.'),
|
||||
));
|
||||
|
||||
$form['default_value'] = $element;
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = $this->t('Save settings');
|
||||
|
||||
if (!$this->entity->isNew()) {
|
||||
$target_entity_type = $this->entityManager->getDefinition($this->entity->getTargetEntityTypeId());
|
||||
$route_parameters = [
|
||||
'field_config' => $this->entity->id(),
|
||||
] + FieldUI::getRouteBundleParameter($target_entity_type, $this->entity->getTargetBundle());
|
||||
$url = new Url('entity.field_config.' . $target_entity_type->id() . '_field_delete_form', $route_parameters);
|
||||
|
||||
if ($this->getRequest()->query->has('destination')) {
|
||||
$query = $url->getOption('query');
|
||||
$query['destination'] = $this->getRequest()->query->get('destination');
|
||||
$url->setOption('query', $query);
|
||||
}
|
||||
$actions['delete'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Delete'),
|
||||
'#url' => $url,
|
||||
'#access' => $this->entity->access('delete'),
|
||||
'#attributes' => array(
|
||||
'class' => array('button', 'button--danger'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
|
||||
if (isset($form['default_value'])) {
|
||||
$item = $form['#entity']->get($this->entity->getName());
|
||||
$item->defaultValuesFormValidate($form['default_value'], $form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
// Handle the default value.
|
||||
$default_value = array();
|
||||
if (isset($form['default_value'])) {
|
||||
$items = $form['#entity']->get($this->entity->getName());
|
||||
$default_value = $items->defaultValuesFormSubmit($form['default_value'], $form, $form_state);
|
||||
}
|
||||
$this->entity->default_value = $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$this->entity->save();
|
||||
|
||||
drupal_set_message($this->t('Saved %label configuration.', array('%label' => $this->entity->getLabel())));
|
||||
|
||||
$request = $this->getRequest();
|
||||
if (($destinations = $request->query->get('destinations')) && $next_destination = FieldUI::getNextDestination($destinations)) {
|
||||
$request->query->remove('destinations');
|
||||
$form_state->setRedirectUrl($next_destination);
|
||||
}
|
||||
else {
|
||||
$form_state->setRedirectUrl(FieldUI::getOverviewRouteInfo($this->entity->getTargetEntityTypeId(), $this->entity->getTargetBundle()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The _title_callback for the field settings form.
|
||||
*
|
||||
* @param \Drupal\field\FieldConfigInterface $field_config
|
||||
* The field.
|
||||
*
|
||||
* @return string
|
||||
* The label of the field.
|
||||
*/
|
||||
public function getTitle(FieldConfigInterface $field_config) {
|
||||
return SafeMarkup::checkPlain($field_config->label());
|
||||
}
|
||||
|
||||
}
|
560
core/modules/field_ui/src/Form/FieldStorageAddForm.php
Normal file
560
core/modules/field_ui/src/Form/FieldStorageAddForm.php
Normal file
|
@ -0,0 +1,560 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\FieldStorageAddForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for the "field storage" add page.
|
||||
*/
|
||||
class FieldStorageAddForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The name of the entity type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityTypeId;
|
||||
|
||||
/**
|
||||
* The entity bundle.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bundle;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManager
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The field type plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypePluginManager;
|
||||
|
||||
/**
|
||||
* The query factory to create entity queries.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||
*/
|
||||
public $queryFactory;
|
||||
|
||||
/**
|
||||
* The configuration factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Constructs a new FieldStorageAddForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_plugin_manager
|
||||
* The field type plugin manager.
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
|
||||
* The entity query factory.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The configuration factory.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, QueryFactory $query_factory, ConfigFactoryInterface $config_factory) {
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->fieldTypePluginManager = $field_type_plugin_manager;
|
||||
$this->queryFactory = $query_factory;
|
||||
$this->configFactory = $config_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'field_ui_field_storage_add_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('entity.query'),
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
|
||||
if (!$form_state->get('entity_type_id')) {
|
||||
$form_state->set('entity_type_id', $entity_type_id);
|
||||
}
|
||||
if (!$form_state->get('bundle')) {
|
||||
$form_state->set('bundle', $bundle);
|
||||
}
|
||||
|
||||
$this->entityTypeId = $form_state->get('entity_type_id');
|
||||
$this->bundle = $form_state->get('bundle');
|
||||
|
||||
// Gather valid field types.
|
||||
$field_type_options = array();
|
||||
foreach ($this->fieldTypePluginManager->getGroupedDefinitions($this->fieldTypePluginManager->getUiDefinitions()) as $category => $field_types) {
|
||||
foreach ($field_types as $name => $field_type) {
|
||||
$field_type_options[$category][$name] = $field_type['label'];
|
||||
}
|
||||
}
|
||||
|
||||
$form['add'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('form--inline', 'clearfix')),
|
||||
);
|
||||
|
||||
$form['add']['new_storage_type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Add a new field'),
|
||||
'#options' => $field_type_options,
|
||||
'#empty_option' => $this->t('- Select a field type -'),
|
||||
);
|
||||
|
||||
// Re-use existing field.
|
||||
if ($existing_field_storage_options = $this->getExistingFieldStorageOptions()) {
|
||||
$form['add']['separator'] = array(
|
||||
'#type' => 'item',
|
||||
'#markup' => $this->t('or'),
|
||||
);
|
||||
$form['add']['existing_storage_name'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Re-use an existing field'),
|
||||
'#options' => $existing_field_storage_options,
|
||||
'#empty_option' => $this->t('- Select an existing field -'),
|
||||
);
|
||||
|
||||
$form['#attached']['drupalSettings']['existingFieldLabels'] = $this->getExistingFieldLabels(array_keys($existing_field_storage_options));
|
||||
}
|
||||
else {
|
||||
// Provide a placeholder form element to simplify the validation code.
|
||||
$form['add']['existing_storage_name'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
// Field label and field_name.
|
||||
$form['new_storage_wrapper'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
'!visible' => array(
|
||||
':input[name="new_storage_type"]' => array('value' => ''),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['new_storage_wrapper']['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#size' => 15,
|
||||
);
|
||||
|
||||
$field_prefix = $this->config('field_ui.settings')->get('field_prefix');
|
||||
$form['new_storage_wrapper']['field_name'] = array(
|
||||
'#type' => 'machine_name',
|
||||
// This field should stay LTR even for RTL languages.
|
||||
'#field_prefix' => '<span dir="ltr">' . $field_prefix,
|
||||
'#field_suffix' => '</span>‎',
|
||||
'#size' => 15,
|
||||
'#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
|
||||
// Calculate characters depending on the length of the field prefix
|
||||
// setting. Maximum length is 32.
|
||||
'#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix),
|
||||
'#machine_name' => array(
|
||||
'source' => array('new_storage_wrapper', 'label'),
|
||||
'exists' => array($this, 'fieldNameExists'),
|
||||
),
|
||||
'#required' => FALSE,
|
||||
);
|
||||
|
||||
// Provide a separate label element for the "Re-use existing field" case
|
||||
// and place it outside the $form['add'] wrapper because those elements
|
||||
// are displayed inline.
|
||||
if ($existing_field_storage_options) {
|
||||
$form['existing_storage_label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#size' => 15,
|
||||
'#states' => array(
|
||||
'!visible' => array(
|
||||
':input[name="existing_storage_name"]' => array('value' => ''),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Place the 'translatable' property as an explicit value so that contrib
|
||||
// modules can form_alter() the value for newly created fields. By default
|
||||
// we create field storage as translatable so it will be possible to enable
|
||||
// translation at field level.
|
||||
$form['translatable'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => TRUE,
|
||||
);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save and continue'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
$form['#attached']['library'][] = 'field_ui/drupal.field_ui';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// Missing field type.
|
||||
if (!$form_state->getValue('new_storage_type') && !$form_state->getValue('existing_storage_name')) {
|
||||
$form_state->setErrorByName('new_storage_type', $this->t('You need to select a field type or an existing field.'));
|
||||
}
|
||||
// Both field type and existing field option selected. This is prevented in
|
||||
// the UI with JavaScript but we also need a proper server-side validation.
|
||||
elseif ($form_state->getValue('new_storage_type') && $form_state->getValue('existing_storage_name')) {
|
||||
$form_state->setErrorByName('new_storage_type', $this->t('Adding a new field and re-using an existing field at the same time is not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->validateAddNew($form, $form_state);
|
||||
$this->validateAddExisting($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the 'add new field' case.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @see \Drupal\field_ui\Form\FieldStorageAddForm::validateForm()
|
||||
*/
|
||||
protected function validateAddNew(array $form, FormStateInterface $form_state) {
|
||||
// Validate if any information was provided in the 'add new field' case.
|
||||
if ($form_state->getValue('new_storage_type')) {
|
||||
// Missing label.
|
||||
if (!$form_state->getValue('label')) {
|
||||
$form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.'));
|
||||
}
|
||||
|
||||
// Missing field name.
|
||||
if (!$form_state->getValue('field_name')) {
|
||||
$form_state->setErrorByName('field_name', $this->t('Add new field: you need to provide a machine name for the field.'));
|
||||
}
|
||||
// Field name validation.
|
||||
else {
|
||||
$field_name = $form_state->getValue('field_name');
|
||||
|
||||
// Add the field prefix.
|
||||
$field_name = $this->configFactory->get('field_ui.settings')->get('field_prefix') . $field_name;
|
||||
$form_state->setValueForElement($form['new_storage_wrapper']['field_name'], $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the 're-use existing field' case.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @see \Drupal\field_ui\Form\FieldStorageAddForm::validateForm()
|
||||
*/
|
||||
protected function validateAddExisting(array $form, FormStateInterface $form_state) {
|
||||
if ($form_state->getValue('existing_storage_name')) {
|
||||
// Missing label.
|
||||
if (!$form_state->getValue('existing_storage_label')) {
|
||||
$form_state->setErrorByName('existing_storage_label', $this->t('Re-use existing field: you need to provide a label.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$error = FALSE;
|
||||
$values = $form_state->getValues();
|
||||
$destinations = array();
|
||||
$entity_type = $this->entityManager->getDefinition($this->entityTypeId);
|
||||
|
||||
// Create new field.
|
||||
if ($values['new_storage_type']) {
|
||||
$field_storage_values = [
|
||||
'field_name' => $values['field_name'],
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'type' => $values['new_storage_type'],
|
||||
'translatable' => $values['translatable'],
|
||||
];
|
||||
$field_values = [
|
||||
'field_name' => $values['field_name'],
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'bundle' => $this->bundle,
|
||||
'label' => $values['label'],
|
||||
// Field translatability should be explicitly enabled by the users.
|
||||
'translatable' => FALSE,
|
||||
];
|
||||
$widget_id = $formatter_id = NULL;
|
||||
|
||||
// Check if we're dealing with a preconfigured field.
|
||||
if (strpos($field_storage_values['type'], 'field_ui:') !== FALSE) {
|
||||
list(, $field_type, $option_key) = explode(':', $field_storage_values['type'], 3);
|
||||
$field_storage_values['type'] = $field_type;
|
||||
|
||||
$field_type_class = $this->fieldTypePluginManager->getDefinition($field_type)['class'];
|
||||
$field_options = $field_type_class::getPreconfiguredOptions()[$option_key];
|
||||
|
||||
// Merge in preconfigured field storage options.
|
||||
if (isset($field_options['field_storage_config'])) {
|
||||
foreach (array('cardinality', 'settings') as $key) {
|
||||
if (isset($field_options['field_storage_config'][$key])) {
|
||||
$field_storage_values[$key] = $field_options['field_storage_config'][$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge in preconfigured field options.
|
||||
if (isset($field_options['field_config'])) {
|
||||
foreach (array('required', 'settings') as $key) {
|
||||
if (isset($field_options['field_config'][$key])) {
|
||||
$field_values[$key] = $field_options['field_config'][$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$widget_id = isset($field_options['entity_form_display']['type']) ? $field_options['entity_form_display']['type'] : NULL;
|
||||
$formatter_id = isset($field_options['entity_view_display']['type']) ? $field_options['entity_view_display']['type'] : NULL;
|
||||
}
|
||||
|
||||
// Create the field storage and field.
|
||||
try {
|
||||
$this->entityManager->getStorage('field_storage_config')->create($field_storage_values)->save();
|
||||
$field = $this->entityManager->getStorage('field_config')->create($field_values);
|
||||
$field->save();
|
||||
|
||||
$this->configureEntityFormDisplay($values['field_name'], $widget_id);
|
||||
$this->configureEntityViewDisplay($values['field_name'], $formatter_id);
|
||||
|
||||
// Always show the field settings step, as the cardinality needs to be
|
||||
// configured for new fields.
|
||||
$route_parameters = array(
|
||||
'field_config' => $field->id(),
|
||||
) + FieldUI::getRouteBundleParameter($entity_type, $this->bundle);
|
||||
$destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_storage_edit_form", 'route_parameters' => $route_parameters);
|
||||
$destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", 'route_parameters' => $route_parameters);
|
||||
$destinations[] = array('route_name' => "entity.{$this->entityTypeId}.field_ui_fields", 'route_parameters' => $route_parameters);
|
||||
|
||||
// Store new field information for any additional submit handlers.
|
||||
$form_state->set(['fields_added', '_add_new_field'], $values['field_name']);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$error = TRUE;
|
||||
drupal_set_message($this->t('There was a problem creating field %label: @message', array('%label' => $values['label'], '@message' => $e->getMessage())), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Re-use existing field.
|
||||
if ($values['existing_storage_name']) {
|
||||
$field_name = $values['existing_storage_name'];
|
||||
|
||||
try {
|
||||
$field = $this->entityManager->getStorage('field_config')->create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'bundle' => $this->bundle,
|
||||
'label' => $values['existing_storage_label'],
|
||||
));
|
||||
$field->save();
|
||||
|
||||
$this->configureEntityFormDisplay($field_name);
|
||||
$this->configureEntityViewDisplay($field_name);
|
||||
|
||||
$route_parameters = array(
|
||||
'field_config' => $field->id(),
|
||||
) + FieldUI::getRouteBundleParameter($entity_type, $this->bundle);
|
||||
$destinations[] = array('route_name' => "entity.field_config.{$this->entityTypeId}_field_edit_form", 'route_parameters' => $route_parameters);
|
||||
$destinations[] = array('route_name' => "entity.{$this->entityTypeId}.field_ui_fields", 'route_parameters' => $route_parameters);
|
||||
|
||||
// Store new field information for any additional submit handlers.
|
||||
$form_state->set(['fields_added', '_add_existing_field'], $field_name);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$error = TRUE;
|
||||
drupal_set_message($this->t('There was a problem creating field %label: @message', array('%label' => $values['label'], '@message' => $e->getMessage())), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
if ($destinations) {
|
||||
$destination = $this->getDestinationArray();
|
||||
$destinations[] = $destination['destination'];
|
||||
$form_state->setRedirectUrl(FieldUI::getNextDestination($destinations, $form_state));
|
||||
}
|
||||
elseif (!$error) {
|
||||
drupal_set_message($this->t('Your settings have been saved.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the newly created field for the default view and form modes.
|
||||
*
|
||||
* @param string $field_name
|
||||
* The field name.
|
||||
* @param string|null $widget_id
|
||||
* (optional) The plugin ID of the widget. Defaults to NULL.
|
||||
*/
|
||||
protected function configureEntityFormDisplay($field_name, $widget_id = NULL) {
|
||||
// Make sure the field is displayed in the 'default' form mode (using
|
||||
// default widget and settings). It stays hidden for other form modes
|
||||
// until it is explicitly configured.
|
||||
$options = $widget_id ? ['type' => $widget_id] : [];
|
||||
entity_get_form_display($this->entityTypeId, $this->bundle, 'default')
|
||||
->setComponent($field_name, $options)
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the newly created field for the default view and form modes.
|
||||
*
|
||||
* @param string $field_name
|
||||
* The field name.
|
||||
* @param string|null $formatter_id
|
||||
* (optional) The plugin ID of the formatter. Defaults to NULL.
|
||||
*/
|
||||
protected function configureEntityViewDisplay($field_name, $formatter_id = NULL) {
|
||||
// Make sure the field is displayed in the 'default' view mode (using
|
||||
// default formatter and settings). It stays hidden for other view
|
||||
// modes until it is explicitly configured.
|
||||
$options = $formatter_id ? ['type' => $formatter_id] : [];
|
||||
entity_get_display($this->entityTypeId, $this->bundle, 'default')
|
||||
->setComponent($field_name, $options)
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of existing field storages that can be added to a bundle.
|
||||
*
|
||||
* @return array
|
||||
* An array of existing field storages keyed by name.
|
||||
*/
|
||||
protected function getExistingFieldStorageOptions() {
|
||||
$options = array();
|
||||
// Load the field_storages and build the list of options.
|
||||
$field_types = $this->fieldTypePluginManager->getDefinitions();
|
||||
foreach ($this->entityManager->getFieldStorageDefinitions($this->entityTypeId) as $field_name => $field_storage) {
|
||||
// Do not show:
|
||||
// - non-configurable field storages,
|
||||
// - locked field storages,
|
||||
// - field storages that should not be added via user interface,
|
||||
// - field storages that already have a field in the bundle.
|
||||
$field_type = $field_storage->getType();
|
||||
if ($field_storage instanceof FieldStorageConfigInterface
|
||||
&& !$field_storage->isLocked()
|
||||
&& empty($field_types[$field_type]['no_ui'])
|
||||
&& !in_array($this->bundle, $field_storage->getBundles(), TRUE)) {
|
||||
$options[$field_name] = $this->t('@type: @field', array(
|
||||
'@type' => $field_types[$field_type]['label'],
|
||||
'@field' => $field_name,
|
||||
));
|
||||
}
|
||||
}
|
||||
asort($options);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the human-readable labels for the given field storage names.
|
||||
*
|
||||
* Since not all field storages are required to have a field, we can only
|
||||
* provide the field labels on a best-effort basis (e.g. the label of a field
|
||||
* storage without any field attached to a bundle will be the field name).
|
||||
*
|
||||
* @param array $field_names
|
||||
* An array of field names.
|
||||
*
|
||||
* @return array
|
||||
* An array of field labels keyed by field name.
|
||||
*/
|
||||
protected function getExistingFieldLabels(array $field_names) {
|
||||
// Get all the fields corresponding to the given field storage names and
|
||||
// this entity type.
|
||||
$field_ids = $this->queryFactory->get('field_config')
|
||||
->condition('entity_type', $this->entityTypeId)
|
||||
->condition('field_name', $field_names)
|
||||
->execute();
|
||||
$fields = $this->entityManager->getStorage('field_config')->loadMultiple($field_ids);
|
||||
|
||||
// Go through all the fields and use the label of the first encounter.
|
||||
$labels = array();
|
||||
foreach ($fields as $field) {
|
||||
if (!isset($labels[$field->getName()])) {
|
||||
$labels[$field->getName()] = $field->label();
|
||||
}
|
||||
}
|
||||
|
||||
// For field storages without any fields attached to a bundle, the default
|
||||
// label is the field name.
|
||||
$labels += array_combine($field_names, $field_names);
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a field machine name is taken.
|
||||
*
|
||||
* @param string $value
|
||||
* The machine name, not prefixed.
|
||||
* @param array $element
|
||||
* An array containing the structure of the 'field_name' element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return bool
|
||||
* Whether or not the field machine name is taken.
|
||||
*/
|
||||
public function fieldNameExists($value, $element, FormStateInterface $form_state) {
|
||||
// Don't validate the case when an existing field has been selected.
|
||||
if ($form_state->getValue('existing_storage_name')) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Add the field prefix.
|
||||
$field_name = $this->configFactory->get('field_ui.settings')->get('field_prefix') . $value;
|
||||
|
||||
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->entityTypeId);
|
||||
return isset($field_storage_definitions[$field_name]);
|
||||
}
|
||||
|
||||
}
|
192
core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php
Normal file
192
core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php
Normal file
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Form\FieldStorageConfigEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field_ui\FieldUI;
|
||||
|
||||
/**
|
||||
* Provides a form for the "field storage" edit page.
|
||||
*/
|
||||
class FieldStorageConfigEditForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* The entity being used by this form.
|
||||
*
|
||||
* @var \Drupal\field\FieldStorageConfigInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
|
||||
// The URL of this entity form contains only the ID of the field_config
|
||||
// but we are actually editing a field_storage_config entity.
|
||||
$field_config = FieldConfig::load($route_match->getRawParameter('field_config'));
|
||||
|
||||
return $field_config->getFieldStorageDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $field_config
|
||||
* The ID of the field config whose field storage config is being edited.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $field_config = NULL) {
|
||||
if ($field_config) {
|
||||
$field = FieldConfig::load($field_config);
|
||||
$form_state->set('field_config', $field);
|
||||
|
||||
$form_state->set('entity_type_id', $field->getTargetEntityTypeId());
|
||||
$form_state->set('bundle', $field->getTargetBundle());
|
||||
}
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
$field_label = $form_state->get('field_config')->label();
|
||||
$form['#title'] = $field_label;
|
||||
$form['#prefix'] = '<p>' . $this->t('These settings apply to the %field field everywhere it is used. These settings impact the way that data is stored in the database and cannot be changed once data has been created.', array('%field' => $field_label)) . '</p>';
|
||||
|
||||
// See if data already exists for this field.
|
||||
// If so, prevent changes to the field settings.
|
||||
if ($this->entity->hasData()) {
|
||||
$form['#prefix'] = '<div class="messages messages--error">' . $this->t('There is data for this field in the database. The field settings can no longer be changed.') . '</div>' . $form['#prefix'];
|
||||
}
|
||||
|
||||
// Add settings provided by the field module. The field module is
|
||||
// responsible for not returning settings that cannot be changed if
|
||||
// the field already has data.
|
||||
$form['settings'] = array(
|
||||
'#weight' => -10,
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
// Create an arbitrary entity object, so that we can have an instantiated
|
||||
// FieldItem.
|
||||
$ids = (object) array(
|
||||
'entity_type' => $form_state->get('entity_type_id'),
|
||||
'bundle' => $form_state->get('bundle'),
|
||||
'entity_id' => NULL
|
||||
);
|
||||
$entity = _field_create_entity_from_ids($ids);
|
||||
$items = $entity->get($this->entity->getName());
|
||||
$item = $items->first() ?: $items->appendItem();
|
||||
$form['settings'] += $item->storageSettingsForm($form, $form_state, $this->entity->hasData());
|
||||
|
||||
// Build the configurable field values.
|
||||
$cardinality = $this->entity->getCardinality();
|
||||
$form['cardinality_container'] = array(
|
||||
// Reset #parents so the additional container does not appear.
|
||||
'#parents' => array(),
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Allowed number of values'),
|
||||
'#attributes' => array('class' => array(
|
||||
'container-inline',
|
||||
'fieldgroup',
|
||||
'form-composite'
|
||||
)),
|
||||
);
|
||||
$form['cardinality_container']['cardinality'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Allowed number of values'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => array(
|
||||
'number' => $this->t('Limited'),
|
||||
FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED => $this->t('Unlimited'),
|
||||
),
|
||||
'#default_value' => ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) ? FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED : 'number',
|
||||
);
|
||||
$form['cardinality_container']['cardinality_number'] = array(
|
||||
'#type' => 'number',
|
||||
'#default_value' => $cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED ? $cardinality : 1,
|
||||
'#min' => 1,
|
||||
'#title' => $this->t('Limit'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 2,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="cardinality"]' => array('value' => 'number'),
|
||||
),
|
||||
'disabled' => array(
|
||||
':input[name="cardinality"]' => array('value' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$elements = parent::actions($form, $form_state);
|
||||
$elements['submit']['#value'] = $this->t('Save field settings');
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
|
||||
// Validate field cardinality.
|
||||
if ($form_state->getValue('cardinality') === 'number' && !$form_state->getValue('cardinality_number')) {
|
||||
$form_state->setErrorByName('cardinality_number', $this->t('Number of values is required.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildEntity(array $form, FormStateInterface $form_state) {
|
||||
// Save field cardinality.
|
||||
if ($form_state->getValue('cardinality') === 'number' && $form_state->getValue('cardinality_number')) {
|
||||
$form_state->setValue('cardinality', $form_state->getValue('cardinality_number'));
|
||||
}
|
||||
|
||||
return parent::buildEntity($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$field_label = $form_state->get('field_config')->label();
|
||||
try {
|
||||
$this->entity->save();
|
||||
drupal_set_message($this->t('Updated field %label field settings.', array('%label' => $field_label)));
|
||||
$request = $this->getRequest();
|
||||
if (($destinations = $request->query->get('destinations')) && $next_destination = FieldUI::getNextDestination($destinations)) {
|
||||
$request->query->remove('destinations');
|
||||
$form_state->setRedirectUrl($next_destination);
|
||||
}
|
||||
else {
|
||||
$form_state->setRedirectUrl(FieldUI::getOverviewRouteInfo($form_state->get('entity_type_id'), $form_state->get('bundle')));
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
drupal_set_message($this->t('Attempt to update field %label failed: %message.', array('%label' => $field_label, '%message' => $e->getMessage())), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Plugin\Derivative\FieldUiLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Plugin\Derivative;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides local action definitions for all entity bundles.
|
||||
*/
|
||||
class FieldUiLocalAction extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity manager
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a FieldUiLocalAction object.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider to load routes by name.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(RouteProviderInterface $route_provider, EntityManagerInterface $entity_manager) {
|
||||
$this->routeProvider = $route_provider;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$this->derivatives = array();
|
||||
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->get('field_ui_base_route')) {
|
||||
$this->derivatives["field_storage_config_add_$entity_type_id"] = array(
|
||||
'route_name' => "field_ui.field_storage_config_add_$entity_type_id",
|
||||
'title' => $this->t('Add field'),
|
||||
'appears_on' => array("entity.$entity_type_id.field_ui_fields"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->derivatives as &$entry) {
|
||||
$entry += $base_plugin_definition;
|
||||
}
|
||||
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
193
core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php
Normal file
193
core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides local task definitions for all entity bundles.
|
||||
*/
|
||||
class FieldUiLocalTask extends DeriverBase implements ContainerDeriverInterface {
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The route provider.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* The entity manager
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Creates an FieldUiLocalTask object.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The translation manager.
|
||||
*/
|
||||
public function __construct(RouteProviderInterface $route_provider, EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
|
||||
$this->routeProvider = $route_provider;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('string_translation')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$this->derivatives = array();
|
||||
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->get('field_ui_base_route')) {
|
||||
$this->derivatives["overview_$entity_type_id"] = array(
|
||||
'route_name' => "entity.$entity_type_id.field_ui_fields",
|
||||
'weight' => 1,
|
||||
'title' => $this->t('Manage fields'),
|
||||
'base_route' => "entity.$entity_type_id.field_ui_fields",
|
||||
);
|
||||
|
||||
// 'Manage form display' tab.
|
||||
$this->derivatives["form_display_overview_$entity_type_id"] = array(
|
||||
'route_name' => "entity.entity_form_display.$entity_type_id.default",
|
||||
'weight' => 2,
|
||||
'title' => $this->t('Manage form display'),
|
||||
'base_route' => "entity.$entity_type_id.field_ui_fields",
|
||||
);
|
||||
|
||||
// 'Manage display' tab.
|
||||
$this->derivatives["display_overview_$entity_type_id"] = array(
|
||||
'route_name' => "entity.entity_view_display.$entity_type_id.default",
|
||||
'weight' => 3,
|
||||
'title' => $this->t('Manage display'),
|
||||
'base_route' => "entity.$entity_type_id.field_ui_fields",
|
||||
);
|
||||
|
||||
// Field edit tab.
|
||||
$this->derivatives["field_edit_$entity_type_id"] = array(
|
||||
'route_name' => "entity.field_config.{$entity_type_id}_field_edit_form",
|
||||
'title' => $this->t('Edit'),
|
||||
'base_route' => "entity.field_config.{$entity_type_id}_field_edit_form",
|
||||
);
|
||||
|
||||
// Field settings tab.
|
||||
$this->derivatives["field_storage_$entity_type_id"] = array(
|
||||
'route_name' => "entity.field_config.{$entity_type_id}_storage_edit_form",
|
||||
'title' => $this->t('Field settings'),
|
||||
'base_route' => "entity.field_config.{$entity_type_id}_field_edit_form",
|
||||
);
|
||||
|
||||
// View and form modes secondary tabs.
|
||||
// The same base $path for the menu item (with a placeholder) can be
|
||||
// used for all bundles of a given entity type; but depending on
|
||||
// administrator settings, each bundle has a different set of view
|
||||
// modes available for customisation. So we define menu items for all
|
||||
// view modes, and use a route requirement to determine which ones are
|
||||
// actually visible for a given bundle.
|
||||
$this->derivatives['field_form_display_default_' . $entity_type_id] = array(
|
||||
'title' => 'Default',
|
||||
'route_name' => "entity.entity_form_display.$entity_type_id.default",
|
||||
'parent_id' => "field_ui.fields:form_display_overview_$entity_type_id",
|
||||
'weight' => -1,
|
||||
);
|
||||
$this->derivatives['field_display_default_' . $entity_type_id] = array(
|
||||
'title' => 'Default',
|
||||
'route_name' => "entity.entity_view_display.$entity_type_id.default",
|
||||
'parent_id' => "field_ui.fields:display_overview_$entity_type_id",
|
||||
'weight' => -1,
|
||||
);
|
||||
|
||||
// One local task for each form mode.
|
||||
$weight = 0;
|
||||
foreach ($this->entityManager->getFormModes($entity_type_id) as $form_mode => $form_mode_info) {
|
||||
$this->derivatives['field_form_display_' . $form_mode . '_' . $entity_type_id] = array(
|
||||
'title' => $form_mode_info['label'],
|
||||
'route_name' => "entity.entity_form_display.$entity_type_id.form_mode",
|
||||
'route_parameters' => array(
|
||||
'form_mode_name' => $form_mode,
|
||||
),
|
||||
'parent_id' => "field_ui.fields:form_display_overview_$entity_type_id",
|
||||
'weight' => $weight++,
|
||||
);
|
||||
}
|
||||
|
||||
// One local task for each view mode.
|
||||
$weight = 0;
|
||||
foreach ($this->entityManager->getViewModes($entity_type_id) as $view_mode => $form_mode_info) {
|
||||
$this->derivatives['field_display_' . $view_mode . '_' . $entity_type_id] = array(
|
||||
'title' => $form_mode_info['label'],
|
||||
'route_name' => "entity.entity_view_display.$entity_type_id.view_mode",
|
||||
'route_parameters' => array(
|
||||
'view_mode_name' => $view_mode,
|
||||
),
|
||||
'parent_id' => "field_ui.fields:display_overview_$entity_type_id",
|
||||
'weight' => $weight++,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->derivatives as &$entry) {
|
||||
$entry += $base_plugin_definition;
|
||||
}
|
||||
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters the base_route definition for field_ui local tasks.
|
||||
*
|
||||
* @param array $local_tasks
|
||||
* An array of local tasks plugin definitions, keyed by plugin ID.
|
||||
*/
|
||||
public function alterLocalTasks(&$local_tasks) {
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($route_name = $entity_type->get('field_ui_base_route')) {
|
||||
$local_tasks["field_ui.fields:overview_$entity_type_id"]['base_route'] = $route_name;
|
||||
$local_tasks["field_ui.fields:form_display_overview_$entity_type_id"]['base_route'] = $route_name;
|
||||
$local_tasks["field_ui.fields:display_overview_$entity_type_id"]['base_route'] = $route_name;
|
||||
$local_tasks["field_ui.fields:field_form_display_default_$entity_type_id"]['base_route'] = $route_name;
|
||||
$local_tasks["field_ui.fields:field_display_default_$entity_type_id"]['base_route'] = $route_name;
|
||||
|
||||
foreach ($this->entityManager->getFormModes($entity_type_id) as $form_mode => $form_mode_info) {
|
||||
$local_tasks['field_ui.fields:field_form_display_' . $form_mode . '_' . $entity_type_id]['base_route'] = $route_name;
|
||||
}
|
||||
|
||||
foreach ($this->entityManager->getViewModes($entity_type_id) as $view_mode => $form_mode_info) {
|
||||
$local_tasks['field_ui.fields:field_display_' . $view_mode . '_' . $entity_type_id]['base_route'] = $route_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
core/modules/field_ui/src/Routing/FieldUiRouteEnhancer.php
Normal file
58
core/modules/field_ui/src/Routing/FieldUiRouteEnhancer.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Routing\FieldUiRouteEnhancer.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Routing;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Routing\Enhancer\RouteEnhancerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Enhances Field UI routes by adding proper information about the bundle name.
|
||||
*/
|
||||
class FieldUiRouteEnhancer implements RouteEnhancerInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a FieldUiRouteEnhancer object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function enhance(array $defaults, Request $request) {
|
||||
if (($bundle = $this->entityManager->getDefinition($defaults['entity_type_id'])->getBundleEntityType()) && isset($defaults[$bundle])) {
|
||||
// Field UI forms only need the actual name of the bundle they're dealing
|
||||
// with, not an upcasted entity object, so provide a simple way for them
|
||||
// to get it.
|
||||
$defaults['bundle'] = $defaults['_raw_variables']->get($bundle);
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(Route $route) {
|
||||
return ($route->hasOption('_field_ui'));
|
||||
}
|
||||
|
||||
}
|
176
core/modules/field_ui/src/Routing/RouteSubscriber.php
Normal file
176
core/modules/field_ui/src/Routing/RouteSubscriber.php
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Routing\RouteSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Routing;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Routing\RouteSubscriberBase;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Subscriber for Field UI routes.
|
||||
*/
|
||||
class RouteSubscriber extends RouteSubscriberBase {
|
||||
|
||||
/**
|
||||
* The entity type manager
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* Constructs a RouteSubscriber object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $manager) {
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterRoutes(RouteCollection $collection) {
|
||||
foreach ($this->manager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($route_name = $entity_type->get('field_ui_base_route')) {
|
||||
// Try to get the route from the current collection.
|
||||
if (!$entity_route = $collection->get($route_name)) {
|
||||
continue;
|
||||
}
|
||||
$path = $entity_route->getPath();
|
||||
|
||||
$options = array();
|
||||
if (($bundle_entity_type = $entity_type->getBundleEntityType()) && $bundle_entity_type !== 'bundle') {
|
||||
$options['parameters'][$bundle_entity_type] = array(
|
||||
'type' => 'entity:' . $bundle_entity_type,
|
||||
);
|
||||
|
||||
// Special parameter used to easily recognize all Field UI routes.
|
||||
$options['_field_ui'] = TRUE;
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'entity_type_id' => $entity_type_id,
|
||||
);
|
||||
// If the entity type has no bundles and it doesn't use {bundle} in its
|
||||
// admin path, use the entity type.
|
||||
if (strpos($path, '{bundle}') === FALSE) {
|
||||
$defaults['bundle'] = !$entity_type->hasKey('bundle') ? $entity_type_id : '';
|
||||
}
|
||||
|
||||
$route = new Route(
|
||||
"$path/fields/{field_config}",
|
||||
array(
|
||||
'_entity_form' => 'field_config.edit',
|
||||
'_title_callback' => '\Drupal\field_ui\Form\FieldConfigEditForm::getTitle',
|
||||
) + $defaults,
|
||||
array('_entity_access' => 'field_config.update'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.field_config.{$entity_type_id}_field_edit_form", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/fields/{field_config}/storage",
|
||||
array('_entity_form' => 'field_storage_config.edit') + $defaults,
|
||||
array('_permission' => 'administer ' . $entity_type_id . ' fields'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.field_config.{$entity_type_id}_storage_edit_form", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/fields/{field_config}/delete",
|
||||
array('_entity_form' => 'field_config.delete') + $defaults,
|
||||
array('_entity_access' => 'field_config.delete'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.field_config.{$entity_type_id}_field_delete_form", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/fields",
|
||||
array(
|
||||
'_controller' => '\Drupal\field_ui\Controller\FieldConfigListController::listing',
|
||||
'_title' => 'Manage fields',
|
||||
) + $defaults,
|
||||
array('_permission' => 'administer ' . $entity_type_id . ' fields'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.{$entity_type_id}.field_ui_fields", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/fields/add-field",
|
||||
array(
|
||||
'_form' => '\Drupal\field_ui\Form\FieldStorageAddForm',
|
||||
'_title' => 'Add field',
|
||||
) + $defaults,
|
||||
array('_permission' => 'administer ' . $entity_type_id . ' fields'),
|
||||
$options
|
||||
);
|
||||
$collection->add("field_ui.field_storage_config_add_$entity_type_id", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/form-display",
|
||||
array(
|
||||
'_entity_form' => 'entity_form_display.edit',
|
||||
'_title' => 'Manage form display',
|
||||
'form_mode_name' => 'default',
|
||||
) + $defaults,
|
||||
array('_field_ui_form_mode_access' => 'administer ' . $entity_type_id . ' form display'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.entity_form_display.{$entity_type_id}.default", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/form-display/{form_mode_name}",
|
||||
array(
|
||||
'_entity_form' => 'entity_form_display.edit',
|
||||
'_title' => 'Manage form display',
|
||||
) + $defaults,
|
||||
array('_field_ui_form_mode_access' => 'administer ' . $entity_type_id . ' form display'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.entity_form_display.{$entity_type_id}.form_mode", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/display",
|
||||
array(
|
||||
'_entity_form' => 'entity_view_display.edit',
|
||||
'_title' => 'Manage display',
|
||||
'view_mode_name' => 'default',
|
||||
) + $defaults,
|
||||
array('_field_ui_view_mode_access' => 'administer ' . $entity_type_id . ' display'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.entity_view_display.{$entity_type_id}.default", $route);
|
||||
|
||||
$route = new Route(
|
||||
"$path/display/{view_mode_name}",
|
||||
array(
|
||||
'_entity_form' => 'entity_view_display.edit',
|
||||
'_title' => 'Manage display',
|
||||
) + $defaults,
|
||||
array('_field_ui_view_mode_access' => 'administer ' . $entity_type_id . ' display'),
|
||||
$options
|
||||
);
|
||||
$collection->add("entity.entity_view_display.{$entity_type_id}.view_mode", $route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events = parent::getSubscribedEvents();
|
||||
$events[RoutingEvents::ALTER] = array('onAlterRoutes', -100);
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
119
core/modules/field_ui/src/Tests/EntityDisplayModeTest.php
Normal file
119
core/modules/field_ui/src/Tests/EntityDisplayModeTest.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\EntityDisplayModeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the entity display modes UI.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class EntityDisplayModeTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('entity_test', 'field_ui');
|
||||
|
||||
/**
|
||||
* Tests the EntityViewMode user interface.
|
||||
*/
|
||||
public function testEntityViewModeUI() {
|
||||
// Test the listing page.
|
||||
$this->drupalGet('admin/structure/display-modes/view');
|
||||
$this->assertResponse(403);
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer display modes')));
|
||||
$this->drupalGet('admin/structure/display-modes/view');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('Add new view mode'));
|
||||
$this->assertLinkByHref('admin/structure/display-modes/view/add');
|
||||
$this->assertLinkByHref('admin/structure/display-modes/view/add/entity_test');
|
||||
|
||||
$this->drupalGet('admin/structure/display-modes/view/add/entity_test_mulrev');
|
||||
$this->assertResponse(404);
|
||||
|
||||
$this->drupalGet('admin/structure/display-modes/view/add');
|
||||
$this->assertNoLink(t('Test entity - revisions and data table'), 'An entity type with no view builder cannot have view modes.');
|
||||
|
||||
// Test adding a view mode including dots in machine_name.
|
||||
$this->clickLink(t('Test entity'));
|
||||
$edit = array(
|
||||
'id' => strtolower($this->randomMachineName()) . '.' . strtolower($this->randomMachineName()),
|
||||
'label' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertRaw('The machine-readable name must contain only lowercase letters, numbers, and underscores.');
|
||||
|
||||
// Test adding a view mode.
|
||||
$edit = array(
|
||||
'id' => strtolower($this->randomMachineName()),
|
||||
'label' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertRaw(t('Saved the %label view mode.', array('%label' => $edit['label'])));
|
||||
|
||||
// Test editing the view mode.
|
||||
$this->drupalGet('admin/structure/display-modes/view/manage/entity_test.' . $edit['id']);
|
||||
|
||||
// Test deleting the view mode.
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertRaw(t('Are you sure you want to delete the view mode %label?', array('%label' => $edit['label'])));
|
||||
$this->drupalPostForm(NULL, NULL, t('Delete'));
|
||||
$this->assertRaw(t('The view mode %label has been deleted.', array('%label' => $edit['label'])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the EntityFormMode user interface.
|
||||
*/
|
||||
public function testEntityFormModeUI() {
|
||||
// Test the listing page.
|
||||
$this->drupalGet('admin/structure/display-modes/form');
|
||||
$this->assertResponse(403);
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer display modes')));
|
||||
$this->drupalGet('admin/structure/display-modes/form');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('Add new form mode'));
|
||||
$this->assertLinkByHref('admin/structure/display-modes/form/add');
|
||||
|
||||
$this->drupalGet('admin/structure/display-modes/form/add/entity_test_no_label');
|
||||
$this->assertResponse(404);
|
||||
|
||||
$this->drupalGet('admin/structure/display-modes/form/add');
|
||||
$this->assertNoLink(t('Entity Test without label'), 'An entity type with no form cannot have form modes.');
|
||||
|
||||
// Test adding a view mode including dots in machine_name.
|
||||
$this->clickLink(t('Test entity'));
|
||||
$edit = array(
|
||||
'id' => strtolower($this->randomMachineName()) . '.' . strtolower($this->randomMachineName()),
|
||||
'label' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertRaw('The machine-readable name must contain only lowercase letters, numbers, and underscores.');
|
||||
|
||||
// Test adding a form mode.
|
||||
$edit = array(
|
||||
'id' => strtolower($this->randomMachineName()),
|
||||
'label' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertRaw(t('Saved the %label form mode.', array('%label' => $edit['label'])));
|
||||
|
||||
// Test editing the form mode.
|
||||
$this->drupalGet('admin/structure/display-modes/form/manage/entity_test.' . $edit['id']);
|
||||
|
||||
// Test deleting the form mode.
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertRaw(t('Are you sure you want to delete the form mode %label?', array('%label' => $edit['label'])));
|
||||
$this->drupalPostForm(NULL, NULL, t('Delete'));
|
||||
$this->assertRaw(t('The form mode %label has been deleted.', array('%label' => $edit['label'])));
|
||||
}
|
||||
|
||||
}
|
438
core/modules/field_ui/src/Tests/EntityDisplayTest.php
Normal file
438
core/modules/field_ui/src/Tests/EntityDisplayTest.php
Normal file
|
@ -0,0 +1,438 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\EntityDisplayTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests the entity display configuration entities.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class EntityDisplayTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $modules = array('field_ui', 'field', 'entity_test', 'user', 'text', 'field_test', 'node', 'system');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('node');
|
||||
$this->installConfig(array('field', 'node'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests basic CRUD operations on entity display objects.
|
||||
*/
|
||||
public function testEntityDisplayCRUD() {
|
||||
$display = EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
$expected = array();
|
||||
|
||||
// Check that providing no 'weight' results in the highest current weight
|
||||
// being assigned. The 'name' field's formatter has weight -5, therefore
|
||||
// these follow.
|
||||
$expected['component_1'] = array('weight' => -4, 'settings' => array(), 'third_party_settings' => array());
|
||||
$expected['component_2'] = array('weight' => -3, 'settings' => array(), 'third_party_settings' => array());
|
||||
$display->setComponent('component_1');
|
||||
$display->setComponent('component_2');
|
||||
$this->assertEqual($display->getComponent('component_1'), $expected['component_1']);
|
||||
$this->assertEqual($display->getComponent('component_2'), $expected['component_2']);
|
||||
|
||||
// Check that arbitrary options are correctly stored.
|
||||
$expected['component_3'] = array('weight' => 10, 'third_party_settings' => array('field_test' => array('foo' => 'bar')), 'settings' => array());
|
||||
$display->setComponent('component_3', $expected['component_3']);
|
||||
$this->assertEqual($display->getComponent('component_3'), $expected['component_3']);
|
||||
|
||||
// Check that the display can be properly saved and read back.
|
||||
$display->save();
|
||||
$display = entity_load('entity_view_display', $display->id());
|
||||
foreach (array('component_1', 'component_2', 'component_3') as $name) {
|
||||
$this->assertEqual($display->getComponent($name), $expected[$name]);
|
||||
}
|
||||
|
||||
// Ensure that third party settings were added to the config entity.
|
||||
// These are added by entity_test_entity_presave() implemented in
|
||||
// entity_test module.
|
||||
$this->assertEqual('bar', $display->getThirdPartySetting('entity_test', 'foo'), 'Third party settings were added to the entity view display.');
|
||||
|
||||
// Check that getComponents() returns options for all components.
|
||||
$expected['name'] = array(
|
||||
'label' => 'hidden',
|
||||
'type' => 'string',
|
||||
'weight' => -5,
|
||||
'settings' => array(
|
||||
'link_to_entity' => FALSE,
|
||||
),
|
||||
'third_party_settings' => array(),
|
||||
);
|
||||
$this->assertEqual($display->getComponents(), $expected);
|
||||
|
||||
// Check that a component can be removed.
|
||||
$display->removeComponent('component_3');
|
||||
$this->assertNULL($display->getComponent('component_3'));
|
||||
|
||||
// Check that the removal is correctly persisted.
|
||||
$display->save();
|
||||
$display = entity_load('entity_view_display', $display->id());
|
||||
$this->assertNULL($display->getComponent('component_3'));
|
||||
|
||||
// Check that createCopy() creates a new component that can be correctly
|
||||
// saved.
|
||||
EntityViewMode::create(array('id' => $display->getTargetEntityTypeId() . '.other_view_mode', 'targetEntityType' => $display->getTargetEntityTypeId()))->save();
|
||||
$new_display = $display->createCopy('other_view_mode');
|
||||
$new_display->save();
|
||||
$new_display = entity_load('entity_view_display', $new_display->id());
|
||||
$dependencies = $new_display->calculateDependencies();
|
||||
$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());
|
||||
$this->assertEqual($new_display->getMode(), 'other_view_mode');
|
||||
$this->assertEqual($new_display->getComponents(), $display->getComponents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test sorting of components by name on basic CRUD operations
|
||||
*/
|
||||
public function testEntityDisplayCRUDSort() {
|
||||
$display = EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
));
|
||||
$display->setComponent('component_3');
|
||||
$display->setComponent('component_1');
|
||||
$display->setComponent('component_2');
|
||||
$display->save();
|
||||
$components = array_keys($display->getComponents());
|
||||
// The name field is not configurable so will be added automatically.
|
||||
$expected = array ( 0 => 'component_1', 1 => 'component_2', 2 => 'component_3', 'name');
|
||||
$this->assertIdentical($components, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity_get_display().
|
||||
*/
|
||||
public function testEntityGetDisplay() {
|
||||
// Check that entity_get_display() returns a fresh object when no
|
||||
// configuration entry exists.
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertTrue($display->isNew());
|
||||
|
||||
// Add some components and save the display.
|
||||
$display->setComponent('component_1', array('weight' => 10, 'settings' => array()))
|
||||
->save();
|
||||
|
||||
// Check that entity_get_display() returns the correct object.
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($display->isNew());
|
||||
$this->assertEqual($display->id(), 'entity_test.entity_test.default');
|
||||
$this->assertEqual($display->getComponent('component_1'), array( 'weight' => 10, 'settings' => array(), 'third_party_settings' => array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of a field component within an entity display object.
|
||||
*/
|
||||
public function testExtraFieldComponent() {
|
||||
entity_test_create_bundle('bundle_with_extra_fields');
|
||||
$display = EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'bundle_with_extra_fields',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
// Check that the default visibility taken into account for extra fields
|
||||
// unknown in the display.
|
||||
$this->assertEqual($display->getComponent('display_extra_field'), array('weight' => 5));
|
||||
$this->assertNull($display->getComponent('display_extra_field_hidden'));
|
||||
|
||||
// Check that setting explicit options overrides the defaults.
|
||||
$display->removeComponent('display_extra_field');
|
||||
$display->setComponent('display_extra_field_hidden', array('weight' => 10));
|
||||
$this->assertNull($display->getComponent('display_extra_field'));
|
||||
$this->assertEqual($display->getComponent('display_extra_field_hidden'), array('weight' => 10, 'settings' => array(), 'third_party_settings' => array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of a field component within an entity display object.
|
||||
*/
|
||||
public function testFieldComponent() {
|
||||
$field_name = 'test_field';
|
||||
// Create a field storage and a field.
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'test_field'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
$display = EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
// Check that providing no options results in default values being used.
|
||||
$display->setComponent($field_name);
|
||||
$field_type_info = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field_storage->getType());
|
||||
$default_formatter = $field_type_info['default_formatter'];
|
||||
$formatter_settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings($default_formatter);
|
||||
$expected = array(
|
||||
'weight' => -4,
|
||||
'label' => 'above',
|
||||
'type' => $default_formatter,
|
||||
'settings' => $formatter_settings,
|
||||
'third_party_settings' => array(),
|
||||
);
|
||||
$this->assertEqual($display->getComponent($field_name), $expected);
|
||||
|
||||
// Check that the getFormatter() method returns the correct formatter plugin.
|
||||
$formatter = $display->getRenderer($field_name);
|
||||
$this->assertEqual($formatter->getPluginId(), $default_formatter);
|
||||
$this->assertEqual($formatter->getSettings(), $formatter_settings);
|
||||
|
||||
// Check that the formatter is statically persisted, by assigning an
|
||||
// arbitrary property and reading it back.
|
||||
$random_value = $this->randomString();
|
||||
$formatter->randomValue = $random_value;
|
||||
$formatter = $display->getRenderer($field_name);
|
||||
$this->assertEqual($formatter->randomValue, $random_value);
|
||||
|
||||
// Check that changing the definition creates a new formatter.
|
||||
$display->setComponent($field_name, array(
|
||||
'type' => 'field_test_multiple',
|
||||
));
|
||||
$formatter = $display->getRenderer($field_name);
|
||||
$this->assertEqual($formatter->getPluginId(), 'field_test_multiple');
|
||||
$this->assertFalse(isset($formatter->randomValue));
|
||||
|
||||
// Check that the display has dependencies on the field and the module that
|
||||
// provides the formatter.
|
||||
$dependencies = $display->calculateDependencies();
|
||||
$this->assertEqual(array('config' => array('field.field.entity_test.entity_test.test_field'), 'module' => array('entity_test', 'field_test')), $dependencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of a field component for a base field.
|
||||
*/
|
||||
public function testBaseFieldComponent() {
|
||||
$display = EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test_base_field_display',
|
||||
'bundle' => 'entity_test_base_field_display',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
// Check that default options are correctly filled in.
|
||||
$formatter_settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('text_default');
|
||||
$expected = array(
|
||||
'test_no_display' => NULL,
|
||||
'test_display_configurable' => array(
|
||||
'label' => 'above',
|
||||
'type' => 'text_default',
|
||||
'settings' => $formatter_settings,
|
||||
'third_party_settings' => array(),
|
||||
'weight' => 10,
|
||||
),
|
||||
'test_display_non_configurable' => array(
|
||||
'label' => 'above',
|
||||
'type' => 'text_default',
|
||||
'settings' => $formatter_settings,
|
||||
'third_party_settings' => array(),
|
||||
'weight' => 11,
|
||||
),
|
||||
);
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
|
||||
// Check that saving the display only writes data for fields whose display
|
||||
// is configurable.
|
||||
$display->save();
|
||||
$config = $this->config('core.entity_view_display.' . $display->id());
|
||||
$data = $config->get();
|
||||
$this->assertFalse(isset($data['content']['test_no_display']));
|
||||
$this->assertFalse(isset($data['hidden']['test_no_display']));
|
||||
$this->assertEqual($data['content']['test_display_configurable'], $expected['test_display_configurable']);
|
||||
$this->assertFalse(isset($data['content']['test_display_non_configurable']));
|
||||
$this->assertFalse(isset($data['hidden']['test_display_non_configurable']));
|
||||
|
||||
// Check that defaults are correctly filled when loading the display.
|
||||
$display = entity_load('entity_view_display', $display->id());
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
|
||||
// Check that data manually written for fields whose display is not
|
||||
// configurable is discarded when loading the display.
|
||||
$data['content']['test_display_non_configurable'] = $expected['test_display_non_configurable'];
|
||||
$data['content']['test_display_non_configurable']['weight']++;
|
||||
$config->setData($data)->save();
|
||||
$display = entity_load('entity_view_display', $display->id());
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests renaming and deleting a bundle.
|
||||
*/
|
||||
public function testRenameDeleteBundle() {
|
||||
// Create a node bundle, display and form display object.
|
||||
$type = NodeType::create(array('type' => 'article'));
|
||||
$type->save();
|
||||
node_add_body_field($type);
|
||||
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');
|
||||
$this->assertFalse((bool) $display);
|
||||
$form_display = entity_load('entity_form_display', 'node.article_rename.default');
|
||||
$this->assertFalse((bool) $form_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deleting field.
|
||||
*/
|
||||
public function testDeleteField() {
|
||||
$field_name = 'test_field';
|
||||
// Create a field storage and a field.
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'test_field'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
// Create default and teaser entity display.
|
||||
EntityViewMode::create(array('id' => 'entity_test.teaser', 'targetEntityType' => 'entity_test'))->save();
|
||||
EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
))->setComponent($field_name)->save();
|
||||
EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'teaser',
|
||||
))->setComponent($field_name)->save();
|
||||
|
||||
// Check the component exists.
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertTrue($display->getComponent($field_name));
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'teaser');
|
||||
$this->assertTrue($display->getComponent($field_name));
|
||||
|
||||
// Delete the field.
|
||||
$field->delete();
|
||||
|
||||
// Check that the component has been removed from the entity displays.
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'teaser');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests \Drupal\Core\Entity\EntityDisplayBase::onDependencyRemoval().
|
||||
*/
|
||||
public function testOnDependencyRemoval() {
|
||||
$this->enableModules(array('field_plugins_test'));
|
||||
|
||||
$field_name = 'test_field';
|
||||
// Create a field.
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'text'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
EntityViewDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
))->setComponent($field_name, array('type' => 'field_plugins_test_text_formatter'))->save();
|
||||
|
||||
// Check the component exists and is of the correct type.
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertEqual($display->getComponent($field_name)['type'], 'field_plugins_test_text_formatter');
|
||||
|
||||
// Removing the field_plugins_test module should change the component to use
|
||||
// the default formatter for test fields.
|
||||
\Drupal::service('config.manager')->uninstall('module', 'field_plugins_test');
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertEqual($display->getComponent($field_name)['type'], 'text_default');
|
||||
|
||||
// Removing the text module should remove the field from the view display.
|
||||
\Drupal::service('config.manager')->uninstall('module', 'text');
|
||||
$display = entity_get_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
}
|
||||
}
|
271
core/modules/field_ui/src/Tests/EntityFormDisplayTest.php
Normal file
271
core/modules/field_ui/src/Tests/EntityFormDisplayTest.php
Normal file
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\EntityFormDisplayTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Entity\Entity\EntityFormMode;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the entity display configuration entities.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class EntityFormDisplayTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $modules = array('field_ui', 'field', 'entity_test', 'field_test', 'user', 'text', 'entity_reference');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity_get_form_display().
|
||||
*/
|
||||
public function testEntityGetFromDisplay() {
|
||||
// Check that entity_get_form_display() returns a fresh object when no
|
||||
// configuration entry exists.
|
||||
$form_display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertTrue($form_display->isNew());
|
||||
|
||||
// Add some components and save the display.
|
||||
$form_display->setComponent('component_1', array('weight' => 10))
|
||||
->save();
|
||||
|
||||
// Check that entity_get_form_display() returns the correct object.
|
||||
$form_display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($form_display->isNew());
|
||||
$this->assertEqual($form_display->id(), 'entity_test.entity_test.default');
|
||||
$this->assertEqual($form_display->getComponent('component_1'), array('weight' => 10, 'settings' => array(), 'third_party_settings' => array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of a field component within an EntityFormDisplay object.
|
||||
*/
|
||||
public function testFieldComponent() {
|
||||
// Create a field storage and a field.
|
||||
$field_name = 'test_field';
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'test_field'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
$form_display = EntityFormDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
// Check that providing no options results in default values being used.
|
||||
$form_display->setComponent($field_name);
|
||||
$field_type_info = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field_storage->getType());
|
||||
$default_widget = $field_type_info['default_widget'];
|
||||
$widget_settings = \Drupal::service('plugin.manager.field.widget')->getDefaultSettings($default_widget);
|
||||
$expected = array(
|
||||
'weight' => 0,
|
||||
'type' => $default_widget,
|
||||
'settings' => $widget_settings,
|
||||
'third_party_settings' => array(),
|
||||
);
|
||||
$this->assertEqual($form_display->getComponent($field_name), $expected);
|
||||
|
||||
// Check that the getWidget() method returns the correct widget plugin.
|
||||
$widget = $form_display->getRenderer($field_name);
|
||||
$this->assertEqual($widget->getPluginId(), $default_widget);
|
||||
$this->assertEqual($widget->getSettings(), $widget_settings);
|
||||
|
||||
// Check that the widget is statically persisted, by assigning an
|
||||
// arbitrary property and reading it back.
|
||||
$random_value = $this->randomString();
|
||||
$widget->randomValue = $random_value;
|
||||
$widget = $form_display->getRenderer($field_name);
|
||||
$this->assertEqual($widget->randomValue, $random_value);
|
||||
|
||||
// Check that changing the definition creates a new widget.
|
||||
$form_display->setComponent($field_name, array(
|
||||
'type' => 'field_test_multiple',
|
||||
));
|
||||
$widget = $form_display->getRenderer($field_name);
|
||||
$this->assertEqual($widget->getPluginId(), 'test_field_widget');
|
||||
$this->assertFalse(isset($widget->randomValue));
|
||||
|
||||
// Check that specifying an unknown widget (e.g. case of a disabled module)
|
||||
// gets stored as is in the display, but results in the default widget being
|
||||
// used.
|
||||
$form_display->setComponent($field_name, array(
|
||||
'type' => 'unknown_widget',
|
||||
));
|
||||
$options = $form_display->getComponent($field_name);
|
||||
$this->assertEqual($options['type'], 'unknown_widget');
|
||||
$widget = $form_display->getRenderer($field_name);
|
||||
$this->assertEqual($widget->getPluginId(), $default_widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of a field component for a base field.
|
||||
*/
|
||||
public function testBaseFieldComponent() {
|
||||
$display = EntityFormDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test_base_field_display',
|
||||
'bundle' => 'entity_test_base_field_display',
|
||||
'mode' => 'default',
|
||||
));
|
||||
|
||||
// Check that default options are correctly filled in.
|
||||
$formatter_settings = \Drupal::service('plugin.manager.field.widget')->getDefaultSettings('text_textfield');
|
||||
$expected = array(
|
||||
'test_no_display' => NULL,
|
||||
'test_display_configurable' => array(
|
||||
'type' => 'text_textfield',
|
||||
'settings' => $formatter_settings,
|
||||
'third_party_settings' => array(),
|
||||
'weight' => 10,
|
||||
),
|
||||
'test_display_non_configurable' => array(
|
||||
'type' => 'text_textfield',
|
||||
'settings' => $formatter_settings,
|
||||
'third_party_settings' => array(),
|
||||
'weight' => 11,
|
||||
),
|
||||
);
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
|
||||
// Check that saving the display only writes data for fields whose display
|
||||
// is configurable.
|
||||
$display->save();
|
||||
$config = $this->config('core.entity_form_display.' . $display->id());
|
||||
$data = $config->get();
|
||||
$this->assertFalse(isset($data['content']['test_no_display']));
|
||||
$this->assertFalse(isset($data['hidden']['test_no_display']));
|
||||
$this->assertEqual($data['content']['test_display_configurable'], $expected['test_display_configurable']);
|
||||
$this->assertFalse(isset($data['content']['test_display_non_configurable']));
|
||||
$this->assertFalse(isset($data['hidden']['test_display_non_configurable']));
|
||||
|
||||
// Check that defaults are correctly filled when loading the display.
|
||||
$display = entity_load('entity_form_display', $display->id());
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
|
||||
// Check that data manually written for fields whose display is not
|
||||
// configurable is discarded when loading the display.
|
||||
$data['content']['test_display_non_configurable'] = $expected['test_display_non_configurable'];
|
||||
$data['content']['test_display_non_configurable']['weight']++;
|
||||
$config->setData($data)->save();
|
||||
$display = entity_load('entity_form_display', $display->id());
|
||||
foreach ($expected as $field_name => $options) {
|
||||
$this->assertEqual($display->getComponent($field_name), $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deleting field.
|
||||
*/
|
||||
public function testDeleteField() {
|
||||
$field_name = 'test_field';
|
||||
// Create a field storage and a field.
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'test_field'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
// Create default and compact entity display.
|
||||
EntityFormMode::create(array('id' => 'entity_test.compact', 'targetEntityType' => 'entity_test'))->save();
|
||||
EntityFormDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
))->setComponent($field_name)->save();
|
||||
EntityFormDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'compact',
|
||||
))->setComponent($field_name)->save();
|
||||
|
||||
// Check the component exists.
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertTrue($display->getComponent($field_name));
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'compact');
|
||||
$this->assertTrue($display->getComponent($field_name));
|
||||
|
||||
// Delete the field.
|
||||
$field->delete();
|
||||
|
||||
// Check that the component has been removed from the entity displays.
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'compact');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests \Drupal\Core\Entity\EntityDisplayBase::onDependencyRemoval().
|
||||
*/
|
||||
public function testOnDependencyRemoval() {
|
||||
$this->enableModules(array('field_plugins_test'));
|
||||
|
||||
$field_name = 'test_field';
|
||||
// Create a field.
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'entity_test',
|
||||
'type' => 'text'
|
||||
));
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => 'entity_test',
|
||||
));
|
||||
$field->save();
|
||||
|
||||
EntityFormDisplay::create(array(
|
||||
'targetEntityType' => 'entity_test',
|
||||
'bundle' => 'entity_test',
|
||||
'mode' => 'default',
|
||||
))->setComponent($field_name, array('type' => 'field_plugins_test_text_widget'))->save();
|
||||
|
||||
// Check the component exists and is of the correct type.
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertEqual($display->getComponent($field_name)['type'], 'field_plugins_test_text_widget');
|
||||
|
||||
// Removing the field_plugins_test module should change the component to use
|
||||
// the default widget for test fields.
|
||||
\Drupal::service('config.manager')->uninstall('module', 'field_plugins_test');
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertEqual($display->getComponent($field_name)['type'], 'text_textfield');
|
||||
|
||||
// Removing the text module should remove the field from the form display.
|
||||
\Drupal::service('config.manager')->uninstall('module', 'text');
|
||||
$display = entity_get_form_display('entity_test', 'entity_test', 'default');
|
||||
$this->assertFalse($display->getComponent($field_name));
|
||||
}
|
||||
|
||||
}
|
115
core/modules/field_ui/src/Tests/FieldUIRouteTest.php
Normal file
115
core/modules/field_ui/src/Tests/FieldUIRouteTest.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\FieldUIRouteTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormMode;
|
||||
use Drupal\Core\Entity\Entity\EntityViewMode;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the functionality of the Field UI route subscriber.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class FieldUIRouteTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $modules = array('entity_test', 'field_ui');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that entity types with bundles do not break following entity types.
|
||||
*/
|
||||
public function testFieldUIRoutes() {
|
||||
$this->drupalGet('entity_test_no_id/structure/entity_test/fields');
|
||||
$this->assertText('No fields are present yet.');
|
||||
|
||||
$this->drupalGet('admin/config/people/accounts/fields');
|
||||
$this->assertTitle('Manage fields | Drupal');
|
||||
$this->assertLocalTasks();
|
||||
|
||||
// Test manage display tabs and titles.
|
||||
$this->drupalGet('admin/config/people/accounts/display/compact');
|
||||
$this->assertResponse(403);
|
||||
|
||||
$this->drupalGet('admin/config/people/accounts/display');
|
||||
$this->assertTitle('Manage display | Drupal');
|
||||
$this->assertLocalTasks();
|
||||
|
||||
$edit = array('display_modes_custom[compact]' => TRUE);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->drupalGet('admin/config/people/accounts/display/compact');
|
||||
$this->assertTitle('Manage display | Drupal');
|
||||
$this->assertLocalTasks();
|
||||
|
||||
// Test manage form display tabs and titles.
|
||||
$this->drupalGet('admin/config/people/accounts/form-display/register');
|
||||
$this->assertResponse(403);
|
||||
|
||||
$this->drupalGet('admin/config/people/accounts/form-display');
|
||||
$this->assertTitle('Manage form display | Drupal');
|
||||
$this->assertLocalTasks();
|
||||
|
||||
$edit = array('display_modes_custom[register]' => TRUE);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet('admin/config/people/accounts/form-display/register');
|
||||
$this->assertTitle('Manage form display | Drupal');
|
||||
$this->assertLocalTasks();
|
||||
$this->assert(count($this->xpath('//ul/li[1]/a[contains(text(), :text)]', array(':text' => 'Default'))) == 1, 'Default secondary tab is in first position.');
|
||||
|
||||
// Create new view mode and verify it's available on the Manage Display
|
||||
// screen after enabling it.
|
||||
EntityViewMode::create(array(
|
||||
'id' => 'user.test',
|
||||
'label' => 'Test',
|
||||
'targetEntityType' => 'user',
|
||||
))->save();
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
|
||||
$edit = array('display_modes_custom[test]' => TRUE);
|
||||
$this->drupalPostForm('admin/config/people/accounts/display', $edit, t('Save'));
|
||||
$this->assertLink('Test');
|
||||
|
||||
// Create new form mode and verify it's available on the Manage Form
|
||||
// Display screen after enabling it.
|
||||
EntityFormMode::create(array(
|
||||
'id' => 'user.test',
|
||||
'label' => 'Test',
|
||||
'targetEntityType' => 'user',
|
||||
))->save();
|
||||
$this->container->get('router.builder')->rebuildIfNeeded();
|
||||
|
||||
$edit = array('display_modes_custom[test]' => TRUE);
|
||||
$this->drupalPostForm('admin/config/people/accounts/form-display', $edit, t('Save'));
|
||||
$this->assertLink('Test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that local tasks exists.
|
||||
*/
|
||||
public function assertLocalTasks() {
|
||||
$this->assertLink('Settings');
|
||||
$this->assertLink('Manage fields');
|
||||
$this->assertLink('Manage display');
|
||||
$this->assertLink('Manage form display');
|
||||
}
|
||||
|
||||
}
|
132
core/modules/field_ui/src/Tests/FieldUiTestTrait.php
Normal file
132
core/modules/field_ui/src/Tests/FieldUiTestTrait.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\FieldUiTestTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
/**
|
||||
* Provides common functionality for the Field UI test classes.
|
||||
*/
|
||||
trait FieldUiTestTrait {
|
||||
|
||||
/**
|
||||
* Creates a new field through the Field UI.
|
||||
*
|
||||
* @param string $bundle_path
|
||||
* Admin path of the bundle that the new field is to be attached to.
|
||||
* @param string $field_name
|
||||
* The field name of the new field storage.
|
||||
* @param string $label
|
||||
* (optional) The label of the new field. Defaults to a random string.
|
||||
* @param string $field_type
|
||||
* (optional) The field type of the new field storage. Defaults to
|
||||
* 'test_field'.
|
||||
* @param array $storage_edit
|
||||
* (optional) $edit parameter for drupalPostForm() on the second step
|
||||
* ('Storage settings' form).
|
||||
* @param array $field_edit
|
||||
* (optional) $edit parameter for drupalPostForm() on the third step ('Field
|
||||
* settings' form).
|
||||
*/
|
||||
public function fieldUIAddNewField($bundle_path, $field_name, $label = NULL, $field_type = 'test_field', array $storage_edit = array(), array $field_edit = array()) {
|
||||
$label = $label ?: $this->randomString();
|
||||
$initial_edit = array(
|
||||
'new_storage_type' => $field_type,
|
||||
'label' => $label,
|
||||
'field_name' => $field_name,
|
||||
);
|
||||
|
||||
// Allow the caller to set a NULL path in case they navigated to the right
|
||||
// page before calling this method.
|
||||
if ($bundle_path !== NULL) {
|
||||
$bundle_path = "$bundle_path/fields/add-field";
|
||||
}
|
||||
|
||||
// First step: 'Add field' page.
|
||||
$this->drupalPostForm($bundle_path, $initial_edit, t('Save and continue'));
|
||||
$this->assertRaw(t('These settings apply to the %label field everywhere it is used.', array('%label' => $label)), 'Storage settings page was displayed.');
|
||||
// Test Breadcrumbs.
|
||||
$this->assertLink($label, 0, 'Field label is correct in the breadcrumb of the storage settings page.');
|
||||
|
||||
// Second step: 'Storage settings' form.
|
||||
$this->drupalPostForm(NULL, $storage_edit, t('Save field settings'));
|
||||
$this->assertRaw(t('Updated field %label field settings.', array('%label' => $label)), 'Redirected to field settings page.');
|
||||
|
||||
// Third step: 'Field settings' form.
|
||||
$this->drupalPostForm(NULL, $field_edit, t('Save settings'));
|
||||
$this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), 'Redirected to "Manage fields" page.');
|
||||
|
||||
// Check that the field appears in the overview form.
|
||||
$this->assertFieldByXPath('//table[@id="field-overview"]//tr/td[1]', $label, 'Field was created and appears in the overview page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an existing field through the Field UI.
|
||||
*
|
||||
* @param string $bundle_path
|
||||
* Admin path of the bundle that the field is to be attached to.
|
||||
* @param string $existing_storage_name
|
||||
* The name of the existing field storage for which we want to add a new
|
||||
* field.
|
||||
* @param string $label
|
||||
* (optional) The label of the new field. Defaults to a random string.
|
||||
* @param array $field_edit
|
||||
* (optional) $edit parameter for drupalPostForm() on the second step
|
||||
* ('Field settings' form).
|
||||
*/
|
||||
public function fieldUIAddExistingField($bundle_path, $existing_storage_name, $label = NULL, array $field_edit = array()) {
|
||||
$label = $label ?: $this->randomString();
|
||||
$initial_edit = array(
|
||||
'existing_storage_name' => $existing_storage_name,
|
||||
'existing_storage_label' => $label,
|
||||
);
|
||||
|
||||
// First step: 'Re-use existing field' on the 'Add field' page.
|
||||
$this->drupalPostForm("$bundle_path/fields/add-field", $initial_edit, t('Save and continue'));
|
||||
// Set the main content to only the content region because the label can
|
||||
// contain HTML which will be auto-escaped by Twig.
|
||||
$main_content = $this->cssSelect('.region-content');
|
||||
$this->setRawContent(reset($main_content)->asXml());
|
||||
$this->assertRaw('field-config-edit-form', 'The field config edit form is present.');
|
||||
$this->assertNoRaw('&lt;', 'The page does not have double escaped HTML tags.');
|
||||
|
||||
// Second step: 'Field settings' form.
|
||||
$this->drupalPostForm(NULL, $field_edit, t('Save settings'));
|
||||
$this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), 'Redirected to "Manage fields" page.');
|
||||
|
||||
// Check that the field appears in the overview form.
|
||||
$this->assertFieldByXPath('//table[@id="field-overview"]//tr/td[1]', $label, 'Field was created and appears in the overview page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a field through the Field UI.
|
||||
*
|
||||
* @param string $bundle_path
|
||||
* Admin path of the bundle that the field is to be deleted from.
|
||||
* @param string $field_name
|
||||
* The name of the field.
|
||||
* @param string $label
|
||||
* The label of the field.
|
||||
* @param string $bundle_label
|
||||
* The label of the bundle.
|
||||
*/
|
||||
public function fieldUIDeleteField($bundle_path, $field_name, $label, $bundle_label) {
|
||||
// Display confirmation form.
|
||||
$this->drupalGet("$bundle_path/fields/$field_name/delete");
|
||||
$this->assertRaw(t('Are you sure you want to delete the field %label', array('%label' => $label)), 'Delete confirmation was found.');
|
||||
|
||||
// Test Breadcrumbs.
|
||||
$this->assertLink($label, 0, 'Field label is correct in the breadcrumb of the field delete page.');
|
||||
|
||||
// Submit confirmation form.
|
||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
||||
$this->assertRaw(t('The field %label has been deleted from the %type content type.', array('%label' => $label, '%type' => $bundle_label)), 'Delete message was found.');
|
||||
|
||||
// Check that the field does not appear in the overview form.
|
||||
$this->assertNoFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $label, 'Field does not appear in the overview page.');
|
||||
}
|
||||
|
||||
}
|
523
core/modules/field_ui/src/Tests/ManageDisplayTest.php
Normal file
523
core/modules/field_ui/src/Tests/ManageDisplayTest.php
Normal file
|
@ -0,0 +1,523 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\ManageDisplayTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\field_ui\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the Field UI "Manage display" and "Manage form display" screens.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class ManageDisplayTest extends WebTestBase {
|
||||
|
||||
use FieldUiTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'field_ui', 'taxonomy', 'search', 'field_test', 'field_third_party_test', 'block');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_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'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create content type, with underscores.
|
||||
$type_name = strtolower($this->randomMachineName(8)) . '_test';
|
||||
$type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
|
||||
$this->type = $type->id();
|
||||
|
||||
// Create a default vocabulary.
|
||||
$vocabulary = Vocabulary::create(array(
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => Unicode::strtolower($this->randomMachineName()),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'help' => '',
|
||||
'nodes' => array('article' => 'article'),
|
||||
'weight' => mt_rand(0, 10),
|
||||
));
|
||||
$vocabulary->save();
|
||||
$this->vocabulary = $vocabulary->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests formatter settings.
|
||||
*/
|
||||
function testFormatterUI() {
|
||||
$manage_fields = 'admin/structure/types/manage/' . $this->type;
|
||||
$manage_display = $manage_fields . '/display';
|
||||
|
||||
// Create a field, and a node with some data for the field.
|
||||
$this->fieldUIAddNewField($manage_fields, 'test', 'Test field');
|
||||
|
||||
// Get the display options (formatter and settings) that were automatically
|
||||
// assigned for the 'default' display.
|
||||
$display = entity_get_display('node', $this->type, 'default');
|
||||
$display_options = $display->getComponent('field_test');
|
||||
$format = $display_options['type'];
|
||||
$default_settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings($format);
|
||||
$setting_name = key($default_settings);
|
||||
$setting_value = $display_options['settings'][$setting_name];
|
||||
|
||||
// Display the "Manage display" screen and check that the expected formatter
|
||||
// is selected.
|
||||
$this->drupalGet($manage_display);
|
||||
$this->assertFieldByName('fields[field_test][type]', $format, 'The expected formatter is selected.');
|
||||
$this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
|
||||
|
||||
// Check whether formatter weights are respected.
|
||||
$result = $this->xpath('//select[@id=:id]/option', array(':id' => 'edit-fields-field-test-type'));
|
||||
$options = array_map(function($item) {
|
||||
return (string) $item->attributes()->value[0];
|
||||
}, $result);
|
||||
$expected_options = array (
|
||||
'field_no_settings',
|
||||
'field_empty_test',
|
||||
'field_empty_setting',
|
||||
'field_test_default',
|
||||
'field_test_multiple',
|
||||
'field_test_with_prepare_view',
|
||||
'field_test_applicable',
|
||||
'hidden',
|
||||
);
|
||||
$this->assertEqual($options, $expected_options, 'The expected formatter ordering is respected.');
|
||||
|
||||
// Change the formatter and check that the summary is updated.
|
||||
$edit = array('fields[field_test][type]' => 'field_test_multiple', 'refresh_rows' => 'field_test');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, array('op' => t('Refresh')));
|
||||
$format = 'field_test_multiple';
|
||||
$default_settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings($format);
|
||||
$setting_name = key($default_settings);
|
||||
$setting_value = $default_settings[$setting_name];
|
||||
$this->assertFieldByName('fields[field_test][type]', $format, 'The expected formatter is selected.');
|
||||
$this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
|
||||
|
||||
// Submit the form and check that the display is updated.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
$display = entity_get_display('node', $this->type, 'default');
|
||||
$display_options = $display->getComponent('field_test');
|
||||
$current_format = $display_options['type'];
|
||||
$current_setting_value = $display_options['settings'][$setting_name];
|
||||
$this->assertEqual($current_format, $format, 'The formatter was updated.');
|
||||
$this->assertEqual($current_setting_value, $setting_value, 'The setting was updated.');
|
||||
|
||||
// Assert that hook_field_formatter_settings_summary_alter() is called.
|
||||
$this->assertText('field_test_field_formatter_settings_summary_alter');
|
||||
|
||||
// Click on the formatter settings button to open the formatter settings
|
||||
// form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
|
||||
|
||||
// Assert that the field added in
|
||||
// field_test_field_formatter_third_party_settings_form() is present.
|
||||
$fieldname = 'fields[field_test][settings_edit_form][third_party_settings][field_third_party_test][field_test_field_formatter_third_party_settings_form]';
|
||||
$this->assertField($fieldname, 'The field added in hook_field_formatter_third_party_settings_form() is present on the settings form.');
|
||||
$edit = array($fieldname => 'foo');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, "field_test_plugin_settings_update");
|
||||
|
||||
// Save the form to save the third party settings.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
|
||||
\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.');
|
||||
|
||||
// Confirm that the third party settings are not updated on the settings form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
|
||||
$this->assertFieldByName($fieldname, '');
|
||||
|
||||
// Test the empty setting formatter.
|
||||
$edit = array('fields[field_test][type]' => 'field_empty_setting');
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertNoText('Default empty setting now has a value.');
|
||||
$this->assertFieldById('edit-fields-field-test-settings-edit');
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
|
||||
$fieldname = 'fields[field_test][settings_edit_form][settings][field_empty_setting]';
|
||||
$edit = array($fieldname => 'non empty setting');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, "field_test_plugin_settings_update");
|
||||
$this->assertText('Default empty setting now has a value.');
|
||||
|
||||
// Test the settings form behavior. An edit button should be present since
|
||||
// there are third party settings to configure.
|
||||
$edit = array('fields[field_test][type]' => 'field_no_settings', 'refresh_rows' => 'field_test');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, array('op' => t('Refresh')));
|
||||
$this->assertFieldByName('field_test_settings_edit');
|
||||
// Uninstall the module providing third party settings and ensure the button
|
||||
// is no longer there.
|
||||
\Drupal::service('module_installer')->uninstall(array('field_third_party_test'));
|
||||
$this->drupalGet($manage_display);
|
||||
$this->assertResponse(200);
|
||||
$this->assertNoFieldByName('field_test_settings_edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests widget settings.
|
||||
*/
|
||||
public function testWidgetUI() {
|
||||
// Admin Manage Fields page.
|
||||
$manage_fields = 'admin/structure/types/manage/' . $this->type;
|
||||
// Admin Manage Display page.
|
||||
$manage_display = $manage_fields . '/form-display';
|
||||
|
||||
// Creates a new field that can be used with multiple formatters.
|
||||
// Reference: Drupal\field_test\Plugin\Field\FieldWidget\TestFieldWidgetMultiple::isApplicable().
|
||||
$this->fieldUIAddNewField($manage_fields, 'test', 'Test field');
|
||||
|
||||
// Get the display options (formatter and settings) that were automatically
|
||||
// assigned for the 'default' display.
|
||||
$display = entity_get_form_display('node', $this->type, 'default');
|
||||
$display_options = $display->getComponent('field_test');
|
||||
$widget_type = $display_options['type'];
|
||||
$default_settings = \Drupal::service('plugin.manager.field.widget')->getDefaultSettings($widget_type);
|
||||
$setting_name = key($default_settings);
|
||||
$setting_value = $display_options['settings'][$setting_name];
|
||||
|
||||
// Display the "Manage form display" screen and check if the expected
|
||||
// widget is selected.
|
||||
$this->drupalGet($manage_display);
|
||||
$this->assertFieldByName('fields[field_test][type]', $widget_type, 'The expected widget is selected.');
|
||||
$this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
|
||||
|
||||
// Check whether widget weights are respected.
|
||||
$result = $this->xpath('//select[@id=:id]/option', array(':id' => 'edit-fields-field-test-type'));
|
||||
$options = array_map(function($item) {
|
||||
return (string) $item->attributes()->value[0];
|
||||
}, $result);
|
||||
$expected_options = array (
|
||||
'test_field_widget',
|
||||
'test_field_widget_multiple',
|
||||
'hidden',
|
||||
);
|
||||
$this->assertEqual($options, $expected_options, 'The expected widget ordering is respected.');
|
||||
|
||||
// Change the widget and check that the summary is updated.
|
||||
$edit = array('fields[field_test][type]' => 'test_field_widget_multiple', 'refresh_rows' => 'field_test');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, array('op' => t('Refresh')));
|
||||
$widget_type = 'test_field_widget_multiple';
|
||||
$default_settings = \Drupal::service('plugin.manager.field.widget')->getDefaultSettings($widget_type);
|
||||
$setting_name = key($default_settings);
|
||||
$setting_value = $default_settings[$setting_name];
|
||||
$this->assertFieldByName('fields[field_test][type]', $widget_type, 'The expected widget is selected.');
|
||||
$this->assertText("$setting_name: $setting_value", 'The expected summary is displayed.');
|
||||
|
||||
// Submit the form and check that the display is updated.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
$display = entity_get_form_display('node', $this->type, 'default');
|
||||
$display_options = $display->getComponent('field_test');
|
||||
$current_widget = $display_options['type'];
|
||||
$current_setting_value = $display_options['settings'][$setting_name];
|
||||
$this->assertEqual($current_widget, $widget_type, 'The widget was updated.');
|
||||
$this->assertEqual($current_setting_value, $setting_value, 'The setting was updated.');
|
||||
|
||||
// Assert that hook_field_widget_settings_summary_alter() is called.
|
||||
$this->assertText('field_test_field_widget_settings_summary_alter');
|
||||
|
||||
// Click on the widget settings button to open the widget settings form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
|
||||
|
||||
// Assert that the field added in
|
||||
// field_test_field_widget_third_party_settings_form() is present.
|
||||
$fieldname = 'fields[field_test][settings_edit_form][third_party_settings][field_third_party_test][field_test_widget_third_party_settings_form]';
|
||||
$this->assertField($fieldname, 'The field added in hook_field_widget_third_party_settings_form() is present on the settings form.');
|
||||
$edit = array($fieldname => 'foo');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, "field_test_plugin_settings_update");
|
||||
|
||||
// Save the form to save the third party settings.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
\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.');
|
||||
|
||||
// Confirm that the third party settings are not updated on the settings form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_test_settings_edit");
|
||||
$this->assertFieldByName($fieldname, '');
|
||||
|
||||
// Creates a new field that can not be used with the multiple formatter.
|
||||
// Reference: Drupal\field_test\Plugin\Field\FieldWidget\TestFieldWidgetMultiple::isApplicable().
|
||||
$this->fieldUIAddNewField($manage_fields, 'onewidgetfield', 'One Widget Field');
|
||||
|
||||
// Go to the Manage Form Display.
|
||||
$this->drupalGet($manage_display);
|
||||
|
||||
// Checks if the select elements contain the specified options.
|
||||
$this->assertFieldSelectOptions('fields[field_test][type]', array('test_field_widget', 'test_field_widget_multiple', 'hidden'));
|
||||
$this->assertFieldSelectOptions('fields[field_onewidgetfield][type]', array('test_field_widget', 'hidden'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests switching view modes to use custom or 'default' settings'.
|
||||
*/
|
||||
function testViewModeCustom() {
|
||||
// Create a field, and a node with some data for the field.
|
||||
$this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, 'test', 'Test field');
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
// For this test, use a formatter setting value that is an integer unlikely
|
||||
// to appear in a rendered node other than as part of the field being tested
|
||||
// (for example, unlikely to be part of the "Submitted by ... on ..." line).
|
||||
$value = 12345;
|
||||
$settings = array(
|
||||
'type' => $this->type,
|
||||
'field_test' => array(array('value' => $value)),
|
||||
);
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Gather expected output values with the various formatters.
|
||||
$formatter_plugin_manager = \Drupal::service('plugin.manager.field.formatter');
|
||||
$field_test_default_settings = $formatter_plugin_manager->getDefaultSettings('field_test_default');
|
||||
$field_test_with_prepare_view_settings = $formatter_plugin_manager->getDefaultSettings('field_test_with_prepare_view');
|
||||
$output = array(
|
||||
'field_test_default' => $field_test_default_settings['test_formatter_setting'] . '|' . $value,
|
||||
'field_test_with_prepare_view' => $field_test_with_prepare_view_settings['test_formatter_setting_additional'] . '|' . $value. '|' . ($value + 1),
|
||||
);
|
||||
|
||||
// Check that the field is displayed with the default formatter in 'rss'
|
||||
// mode (uses 'default'), and hidden in 'teaser' mode (uses custom settings).
|
||||
$this->assertNodeViewText($node, 'rss', $output['field_test_default'], "The field is displayed as expected in view modes that use 'default' settings.");
|
||||
$this->assertNodeViewNoText($node, 'teaser', $value, "The field is hidden in view modes that use custom settings.");
|
||||
|
||||
// Change formatter for 'default' mode, check that the field is displayed
|
||||
// accordingly in 'rss' mode.
|
||||
$edit = array(
|
||||
'fields[field_test][type]' => 'field_test_with_prepare_view',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save'));
|
||||
$this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected in view modes that use 'default' settings.");
|
||||
|
||||
// Specialize the 'rss' mode, check that the field is displayed the same.
|
||||
$edit = array(
|
||||
"display_modes_custom[rss]" => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save'));
|
||||
$this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected in newly specialized 'rss' mode.");
|
||||
|
||||
// Set the field to 'hidden' in the view mode, check that the field is
|
||||
// hidden.
|
||||
$edit = array(
|
||||
'fields[field_test][type]' => 'hidden',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/rss', $edit, t('Save'));
|
||||
$this->assertNodeViewNoText($node, 'rss', $value, "The field is hidden in 'rss' mode.");
|
||||
|
||||
// Set the view mode back to 'default', check that the field is displayed
|
||||
// accordingly.
|
||||
$edit = array(
|
||||
"display_modes_custom[rss]" => FALSE,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save'));
|
||||
$this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], "The field is displayed as expected when 'rss' mode is set back to 'default' settings.");
|
||||
|
||||
// Specialize the view mode again.
|
||||
$edit = array(
|
||||
"display_modes_custom[rss]" => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save'));
|
||||
// Check that the previous settings for the view mode have been kept.
|
||||
$this->assertNodeViewNoText($node, 'rss', $value, "The previous settings are kept when 'rss' mode is specialized again.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the local tasks are displayed correctly for view modes.
|
||||
*/
|
||||
public function testViewModeLocalTasks() {
|
||||
$manage_display = 'admin/structure/types/manage/' . $this->type . '/display';
|
||||
$this->drupalGet($manage_display);
|
||||
$this->assertNoLink('Full content');
|
||||
$this->drupalGet($manage_display . '/teaser');
|
||||
$this->assertNoLink('Full content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that fields with no explicit display settings do not break.
|
||||
*/
|
||||
function testNonInitializedFields() {
|
||||
// Create a test field.
|
||||
$this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, 'test', 'Test');
|
||||
|
||||
// Check that the field appears as 'hidden' on the 'Manage display' page
|
||||
// for the 'teaser' mode.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->type . '/display/teaser');
|
||||
$this->assertFieldByName('fields[field_test][type]', 'hidden', 'The field is displayed as \'hidden \'.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hiding the view modes fieldset when there's only one available.
|
||||
*/
|
||||
function testSingleViewMode() {
|
||||
$this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary . '/display');
|
||||
$this->assertNoText('Use custom display settings for the following view modes', 'Custom display settings fieldset found.');
|
||||
|
||||
// This may not trigger a notice when 'view_modes_custom' isn't available.
|
||||
$this->drupalPostForm('admin/structure/taxonomy/manage/' . $this->vocabulary . '/overview/display', array(), t('Save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a message is shown when there are no fields.
|
||||
*/
|
||||
function testNoFieldsDisplayOverview() {
|
||||
// Create a fresh content type without any fields.
|
||||
NodeType::create(array(
|
||||
'type' => 'no_fields',
|
||||
'name' => 'No fields',
|
||||
))->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')))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a string is found in the rendered node in a view mode.
|
||||
*
|
||||
* @param EntityInterface $node
|
||||
* The node.
|
||||
* @param $view_mode
|
||||
* The view mode in which the node should be displayed.
|
||||
* @param $text
|
||||
* Plain text to look for.
|
||||
* @param $message
|
||||
* Message to display.
|
||||
*
|
||||
* @return
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
function assertNodeViewText(EntityInterface $node, $view_mode, $text, $message) {
|
||||
return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a string is not found in the rendered node in a view mode.
|
||||
*
|
||||
* @param EntityInterface $node
|
||||
* The node.
|
||||
* @param $view_mode
|
||||
* The view mode in which the node should be displayed.
|
||||
* @param $text
|
||||
* Plain text to look for.
|
||||
* @param $message
|
||||
* Message to display.
|
||||
* @return
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
function assertNodeViewNoText(EntityInterface $node, $view_mode, $text, $message) {
|
||||
return $this->assertNodeViewTextHelper($node, $view_mode, $text, $message, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a string is (not) found in the rendered nodein a view mode.
|
||||
*
|
||||
* This helper function is used by assertNodeViewText() and
|
||||
* assertNodeViewNoText().
|
||||
*
|
||||
* @param EntityInterface $node
|
||||
* The node.
|
||||
* @param $view_mode
|
||||
* The view mode in which the node should be displayed.
|
||||
* @param $text
|
||||
* Plain text to look for.
|
||||
* @param $message
|
||||
* Message to display.
|
||||
* @param $not_exists
|
||||
* TRUE if this text should not exist, FALSE if it should.
|
||||
*
|
||||
* @return
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
function assertNodeViewTextHelper(EntityInterface $node, $view_mode, $text, $message, $not_exists) {
|
||||
// Make sure caches on the tester side are refreshed after changes
|
||||
// submitted on the tested side.
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
|
||||
// Save current content so that we can restore it when we're done.
|
||||
$old_content = $this->getRawContent();
|
||||
|
||||
// Render a cloned node, so that we do not alter the original.
|
||||
$clone = clone $node;
|
||||
$element = node_view($clone, $view_mode);
|
||||
$output = \Drupal::service('renderer')->renderRoot($element);
|
||||
$this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '<hr />'. $output);
|
||||
|
||||
// Assign content so that WebTestBase functions can be used.
|
||||
$this->setRawContent($output);
|
||||
$method = ($not_exists ? 'assertNoText' : 'assertText');
|
||||
$return = $this->{$method}((string) $text, $message);
|
||||
|
||||
// Restore previous content.
|
||||
$this->setRawContent($old_content);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a select element contains the specified options.
|
||||
*
|
||||
* @param string $name
|
||||
* The field name.
|
||||
* @param array $expected_options
|
||||
* An array of expected options.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertFieldSelectOptions($name, array $expected_options) {
|
||||
$xpath = $this->buildXPathQuery('//select[@name=:name]', array(':name' => $name));
|
||||
$fields = $this->xpath($xpath);
|
||||
if ($fields) {
|
||||
$field = $fields[0];
|
||||
$options = $this->getAllOptionsList($field);
|
||||
|
||||
sort($options);
|
||||
sort($expected_options);
|
||||
|
||||
return $this->assertIdentical($options, $expected_options);
|
||||
}
|
||||
else {
|
||||
return $this->fail('Unable to find field ' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts all options from a select element.
|
||||
*
|
||||
* @param \SimpleXMLElement $element
|
||||
* The select element field information.
|
||||
*
|
||||
* @return array
|
||||
* An array of option values as strings.
|
||||
*/
|
||||
protected function getAllOptionsList(\SimpleXMLElement $element) {
|
||||
$options = array();
|
||||
// Add all options items.
|
||||
foreach ($element->option as $option) {
|
||||
$options[] = (string) $option['value'];
|
||||
}
|
||||
|
||||
// Loops trough all the option groups
|
||||
foreach ($element->optgroup as $optgroup) {
|
||||
$options = array_merge($this->getAllOptionsList($optgroup), $options);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
715
core/modules/field_ui/src/Tests/ManageFieldsTest.php
Normal file
715
core/modules/field_ui/src/Tests/ManageFieldsTest.php
Normal file
|
@ -0,0 +1,715 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\field_ui\Tests\ManageFieldsTest.
|
||||
*/
|
||||
|
||||
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\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests the Field UI "Manage fields" screen.
|
||||
*
|
||||
* @group field_ui
|
||||
*/
|
||||
class ManageFieldsTest extends WebTestBase {
|
||||
|
||||
use FieldUiTestTrait;
|
||||
use EntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'field_ui', 'field_test', 'taxonomy', 'image', 'block');
|
||||
|
||||
/**
|
||||
* The ID of the custom content type created for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $contentType;
|
||||
|
||||
/**
|
||||
* The label for a random field to be created for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldLabel;
|
||||
|
||||
/**
|
||||
* The input name of a random field to be created for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldNameInput;
|
||||
|
||||
/**
|
||||
* The name of a random field to be created for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_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'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create content type, with underscores.
|
||||
$type_name = strtolower($this->randomMachineName(8)) . '_test';
|
||||
$type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
|
||||
$this->contentType = $type->id();
|
||||
|
||||
// Create random field name.
|
||||
$this->fieldLabel = $this->randomMachineName(8);
|
||||
$this->fieldNameInput = strtolower($this->randomMachineName(8));
|
||||
$this->fieldName = 'field_'. $this->fieldNameInput;
|
||||
|
||||
// Create Basic page and Article node types.
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
|
||||
|
||||
// Create a vocabulary named "Tags".
|
||||
$vocabulary = Vocabulary::create(array(
|
||||
'name' => 'Tags',
|
||||
'vid' => 'tags',
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
));
|
||||
$vocabulary->save();
|
||||
|
||||
$handler_settings = array(
|
||||
'target_bundles' => array(
|
||||
$vocabulary->id() => $vocabulary->id(),
|
||||
),
|
||||
);
|
||||
$this->createEntityReferenceField('node', 'article', 'field_' . $vocabulary->id(), 'Tags', 'taxonomy_term', 'default', $handler_settings);
|
||||
|
||||
entity_get_form_display('node', 'article', 'default')
|
||||
->setComponent('field_' . $vocabulary->id())
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the field CRUD tests.
|
||||
*
|
||||
* In order to act on the same fields, and not create the fields over and over
|
||||
* again the following tests create, update and delete the same fields.
|
||||
*/
|
||||
function testCRUDFields() {
|
||||
$this->manageFieldsPage();
|
||||
$this->createField();
|
||||
$this->updateField();
|
||||
$this->addExistingField();
|
||||
$this->cardinalitySettings();
|
||||
$this->fieldListAdminPage();
|
||||
$this->deleteField();
|
||||
$this->addPersistentFieldStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the manage fields page.
|
||||
*
|
||||
* @param string $type
|
||||
* (optional) The name of a content type.
|
||||
*/
|
||||
function manageFieldsPage($type = '') {
|
||||
$type = empty($type) ? $this->contentType : $type;
|
||||
$this->drupalGet('admin/structure/types/manage/' . $type . '/fields');
|
||||
// Check all table columns.
|
||||
$table_headers = array(
|
||||
t('Label'),
|
||||
t('Machine name'),
|
||||
t('Field type'),
|
||||
t('Operations'),
|
||||
);
|
||||
foreach ($table_headers as $table_header) {
|
||||
// We check that the label appear in the table headings.
|
||||
$this->assertRaw($table_header . '</th>', format_string('%table_header table header was found.', array('%table_header' => $table_header)));
|
||||
}
|
||||
|
||||
// Test the "Add field" action link.
|
||||
$this->assertLink('Add field');
|
||||
|
||||
// Assert entity operations for all fields.
|
||||
$number_of_links = 3;
|
||||
$number_of_links_found = 0;
|
||||
$operation_links = $this->xpath('//ul[@class = "dropbutton"]/li/a');
|
||||
$url = base_path() . "admin/structure/types/manage/$type/fields/node.$type.body";
|
||||
|
||||
foreach ($operation_links as $link) {
|
||||
switch ($link['title']) {
|
||||
case 'Edit field settings.':
|
||||
$this->assertIdentical($url, (string) $link['href']);
|
||||
$number_of_links_found++;
|
||||
break;
|
||||
case 'Edit storage settings.':
|
||||
$this->assertIdentical("$url/storage", (string) $link['href']);
|
||||
$number_of_links_found++;
|
||||
break;
|
||||
case 'Delete field.':
|
||||
$this->assertIdentical("$url/delete", (string) $link['href']);
|
||||
$number_of_links_found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEqual($number_of_links, $number_of_links_found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests adding a new field.
|
||||
*
|
||||
* @todo Assert properties can bet set in the form and read back in
|
||||
* $field_storage and $fields.
|
||||
*/
|
||||
function createField() {
|
||||
// Create a test field.
|
||||
$this->fieldUIAddNewField('admin/structure/types/manage/' . $this->contentType, $this->fieldNameInput, $this->fieldLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests editing an existing field.
|
||||
*/
|
||||
function updateField() {
|
||||
$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');
|
||||
|
||||
// Populate the field settings with new settings.
|
||||
$string = 'updated dummy test string';
|
||||
$edit = array(
|
||||
'settings[test_field_storage_setting]' => $string,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save field settings'));
|
||||
|
||||
// Go to the field edit page.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field_id);
|
||||
$edit = array(
|
||||
'settings[test_field_setting]' => $string,
|
||||
);
|
||||
$this->assertText(t('Default value'), 'Default value heading is shown');
|
||||
$this->drupalPostForm(NULL, $edit, t('Save settings'));
|
||||
|
||||
// Assert the field settings are correct.
|
||||
$this->assertFieldSettings($this->contentType, $this->fieldName, $string);
|
||||
|
||||
// Assert redirection back to the "manage fields" page.
|
||||
$this->assertUrl('admin/structure/types/manage/' . $this->contentType . '/fields');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests adding an existing field in another content type.
|
||||
*/
|
||||
function addExistingField() {
|
||||
// Check "Re-use existing field" appears.
|
||||
$this->drupalGet('admin/structure/types/manage/page/fields/add-field');
|
||||
$this->assertRaw(t('Re-use an existing field'), '"Re-use existing field" was found.');
|
||||
|
||||
// Check that fields of other entity types (here, the 'comment_body' field)
|
||||
// do not show up in the "Re-use existing field" list.
|
||||
$this->assertFalse($this->xpath('//select[@id="edit-existing-storage-name"]//option[@value="comment"]'), 'The list of options respects entity type restrictions.');
|
||||
// Validate the FALSE assertion above by also testing a valid one.
|
||||
$this->assertTrue($this->xpath('//select[@id="edit-existing-storage-name"]//option[@value=:field_name]', array(':field_name' => $this->fieldName)), 'The list of options shows a valid option.');
|
||||
|
||||
// Add a new field based on an existing field.
|
||||
$this->fieldUIAddExistingField("admin/structure/types/manage/page", $this->fieldName, $this->fieldLabel . '_2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the cardinality settings of a field.
|
||||
*
|
||||
* We do not test if the number can be submitted with anything else than a
|
||||
* numeric value. That is tested already in FormTest::testNumber().
|
||||
*/
|
||||
function cardinalitySettings() {
|
||||
$field_edit_path = 'admin/structure/types/manage/article/fields/node.article.body/storage';
|
||||
|
||||
// Assert the cardinality other field cannot be empty when cardinality is
|
||||
// set to 'number'.
|
||||
$edit = array(
|
||||
'cardinality' => 'number',
|
||||
'cardinality_number' => '',
|
||||
);
|
||||
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
|
||||
$this->assertText('Number of values is required.');
|
||||
|
||||
// Submit a custom number.
|
||||
$edit = array(
|
||||
'cardinality' => 'number',
|
||||
'cardinality_number' => 6,
|
||||
);
|
||||
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
|
||||
$this->assertText('Updated field Body field settings.');
|
||||
$this->drupalGet($field_edit_path);
|
||||
$this->assertFieldByXPath("//select[@name='cardinality']", 'number');
|
||||
$this->assertFieldByXPath("//input[@name='cardinality_number']", 6);
|
||||
|
||||
// Check that tabs displayed.
|
||||
$this->assertLink(t('Edit'));
|
||||
$this->assertLinkByHref('admin/structure/types/manage/article/fields/node.article.body');
|
||||
$this->assertLink(t('Field settings'));
|
||||
$this->assertLinkByHref($field_edit_path);
|
||||
|
||||
// Set to unlimited.
|
||||
$edit = array(
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
);
|
||||
$this->drupalPostForm($field_edit_path, $edit, t('Save field settings'));
|
||||
$this->assertText('Updated field Body field settings.');
|
||||
$this->drupalGet($field_edit_path);
|
||||
$this->assertFieldByXPath("//select[@name='cardinality']", FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$this->assertFieldByXPath("//input[@name='cardinality_number']", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deleting a field from the field edit form.
|
||||
*/
|
||||
protected function deleteField() {
|
||||
// Delete the field.
|
||||
$field_id = 'node.' . $this->contentType . '.' . $this->fieldName;
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field_id);
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that persistent field storage appears in the field UI.
|
||||
*/
|
||||
protected function addPersistentFieldStorage() {
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $this->fieldName);
|
||||
// Persist the field storage even if there are no fields.
|
||||
$field_storage->set('persist_with_no_fields', TRUE)->save();
|
||||
// Delete all instances of the field.
|
||||
foreach ($field_storage->getBundles() as $node_type) {
|
||||
// Delete all the body field instances.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $node_type . '/fields/node.' . $node_type . '.' . $this->fieldName);
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
||||
}
|
||||
// Check "Re-use existing field" appears.
|
||||
$this->drupalGet('admin/structure/types/manage/page/fields/add-field');
|
||||
$this->assertRaw(t('Re-use an existing field'), '"Re-use existing field" was found.');
|
||||
|
||||
// Ensure that we test with a label that contains HTML.
|
||||
$label = $this->randomString(4) . '<br/>' . $this->randomString(4);
|
||||
// Add a new field for the orphaned storage.
|
||||
$this->fieldUIAddExistingField("admin/structure/types/manage/page", $this->fieldName, $label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts field settings are as expected.
|
||||
*
|
||||
* @param $bundle
|
||||
* The bundle name for the field.
|
||||
* @param $field_name
|
||||
* The field name for the field.
|
||||
* @param $string
|
||||
* The settings text.
|
||||
* @param $entity_type
|
||||
* The entity type for the field.
|
||||
*/
|
||||
function assertFieldSettings($bundle, $field_name, $string = 'dummy test string', $entity_type = 'node') {
|
||||
// Assert field storage settings.
|
||||
$field_storage = FieldStorageConfig::loadByName($entity_type, $field_name);
|
||||
$this->assertTrue($field_storage->getSetting('test_field_storage_setting') == $string, 'Field storage settings were found.');
|
||||
|
||||
// Assert field settings.
|
||||
$field = FieldConfig::loadByName($entity_type, $bundle, $field_name);
|
||||
$this->assertTrue($field->getSetting('test_field_setting') == $string, 'Field settings were found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the 'field_prefix' setting works on Field UI.
|
||||
*/
|
||||
function testFieldPrefix() {
|
||||
// Change default field prefix.
|
||||
$field_prefix = strtolower($this->randomMachineName(10));
|
||||
$this->config('field_ui.settings')->set('field_prefix', $field_prefix)->save();
|
||||
|
||||
// Create a field input and label exceeding the new maxlength, which is 22.
|
||||
$field_exceed_max_length_label = $this->randomString(23);
|
||||
$field_exceed_max_length_input = $this->randomMachineName(23);
|
||||
|
||||
// Try to create the field.
|
||||
$edit = array(
|
||||
'label' => $field_exceed_max_length_label,
|
||||
'field_name' => $field_exceed_max_length_input,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/' . $this->contentType . '/fields/add-field', $edit, t('Save and continue'));
|
||||
$this->assertText('Machine-readable name cannot be longer than 22 characters but is currently 23 characters long.');
|
||||
|
||||
// Create a valid field.
|
||||
$this->fieldUIAddNewField('admin/structure/types/manage/' . $this->contentType, $this->fieldNameInput, $this->fieldLabel);
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/node.' . $this->contentType . '.' . $field_prefix . $this->fieldNameInput);
|
||||
$this->assertText(format_string('@label settings for @type', array('@label' => $this->fieldLabel, '@type' => $this->contentType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that default value is correctly validated and saved.
|
||||
*/
|
||||
function testDefaultValue() {
|
||||
// Create a test field storage and field.
|
||||
$field_name = 'test';
|
||||
FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'test_field'
|
||||
))->save();
|
||||
$field = FieldConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => $this->contentType,
|
||||
));
|
||||
$field->save();
|
||||
|
||||
entity_get_form_display('node', $this->contentType, 'default')
|
||||
->setComponent($field_name)
|
||||
->save();
|
||||
|
||||
$admin_path = 'admin/structure/types/manage/' . $this->contentType . '/fields/' . $field->id();
|
||||
$element_id = "edit-default-value-input-$field_name-0-value";
|
||||
$element_name = "default_value_input[{$field_name}][0][value]";
|
||||
$this->drupalGet($admin_path);
|
||||
$this->assertFieldById($element_id, '', 'The default value widget was empty.');
|
||||
|
||||
// Check that invalid default values are rejected.
|
||||
$edit = array($element_name => '-1');
|
||||
$this->drupalPostForm($admin_path, $edit, t('Save settings'));
|
||||
$this->assertText("$field_name does not accept the value -1", 'Form validation failed.');
|
||||
|
||||
// Check that the default value is saved.
|
||||
$edit = array($element_name => '1');
|
||||
$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.');
|
||||
|
||||
// Check that the default value shows up in the form
|
||||
$this->drupalGet($admin_path);
|
||||
$this->assertFieldById($element_id, '1', 'The default value widget was displayed with the correct value.');
|
||||
|
||||
// Check that the default value can be emptied.
|
||||
$edit = array($element_name => '');
|
||||
$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.');
|
||||
|
||||
// Check that the default value can be empty when the field is marked as
|
||||
// required and can store unlimited values.
|
||||
$field_storage = FieldStorageConfig::loadByName('node', $field_name);
|
||||
$field_storage->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$field_storage->save();
|
||||
|
||||
$this->drupalGet($admin_path);
|
||||
$edit = array(
|
||||
'required' => 1,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save settings'));
|
||||
|
||||
$this->drupalGet($admin_path);
|
||||
$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.');
|
||||
|
||||
// Check that the default widget is used when the field is hidden.
|
||||
entity_get_form_display($field->getTargetEntityTypeId(), $field->getTargetBundle(), 'default')
|
||||
->removeComponent($field_name)->save();
|
||||
$this->drupalGet($admin_path);
|
||||
$this->assertFieldById($element_id, '', 'The default value widget was displayed when field is hidden.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that deletion removes field storages and fields as expected.
|
||||
*/
|
||||
function testDeleteField() {
|
||||
// Create a new field.
|
||||
$bundle_path1 = 'admin/structure/types/manage/' . $this->contentType;
|
||||
$this->fieldUIAddNewField($bundle_path1, $this->fieldNameInput, $this->fieldLabel);
|
||||
|
||||
// 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, $this->fieldName, $this->fieldLabel);
|
||||
|
||||
// Delete the first field.
|
||||
$this->fieldUIDeleteField($bundle_path1, "node.$this->contentType.$this->fieldName", $this->fieldLabel, $this->contentType);
|
||||
|
||||
// Check that the field was deleted.
|
||||
$this->assertNull(FieldConfig::loadByName('node', $this->contentType, $this->fieldName), 'Field was deleted.');
|
||||
// Check that the field storage was not deleted
|
||||
$this->assertNotNull(FieldStorageConfig::loadByName('node', $this->fieldName), 'Field storage was not deleted.');
|
||||
|
||||
// Delete the second field.
|
||||
$this->fieldUIDeleteField($bundle_path2, "node.$type_name2.$this->fieldName", $this->fieldLabel, $type_name2);
|
||||
|
||||
// Check that the field was deleted.
|
||||
$this->assertNull(FieldConfig::loadByName('node', $type_name2, $this->fieldName), 'Field was deleted.');
|
||||
// Check that the field storage was deleted too.
|
||||
$this->assertNull(FieldStorageConfig::loadByName('node', $this->fieldName), 'Field storage was deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Field UI respects disallowed field names.
|
||||
*/
|
||||
function testDisallowedFieldNames() {
|
||||
// Reset the field prefix so we can test properly.
|
||||
$this->config('field_ui.settings')->set('field_prefix', '')->save();
|
||||
|
||||
$label = 'Disallowed field';
|
||||
$edit = array(
|
||||
'label' => $label,
|
||||
'new_storage_type' => 'test_field',
|
||||
);
|
||||
|
||||
// Try with an entity key.
|
||||
$edit['field_name'] = 'title';
|
||||
$bundle_path = 'admin/structure/types/manage/' . $this->contentType;
|
||||
$this->drupalPostForm("$bundle_path/fields/add-field", $edit, t('Save and continue'));
|
||||
$this->assertText(t('The machine-readable name is already in use. It must be unique.'));
|
||||
|
||||
// Try with a base field.
|
||||
$edit['field_name'] = 'sticky';
|
||||
$bundle_path = 'admin/structure/types/manage/' . $this->contentType;
|
||||
$this->drupalPostForm("$bundle_path/fields/add-field", $edit, t('Save and continue'));
|
||||
$this->assertText(t('The machine-readable name is already in use. It must be unique.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Field UI respects locked fields.
|
||||
*/
|
||||
function testLockedField() {
|
||||
// Create a locked field and attach it to a bundle. We need to do this
|
||||
// programmatically as there's no way to create a locked field through UI.
|
||||
$field_name = strtolower($this->randomMachineName(8));
|
||||
$field_storage = FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'test_field',
|
||||
'cardinality' => 1,
|
||||
'locked' => TRUE
|
||||
));
|
||||
$field_storage->save();
|
||||
FieldConfig::create(array(
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => $this->contentType,
|
||||
))->save();
|
||||
entity_get_form_display('node', $this->contentType, 'default')
|
||||
->setComponent($field_name, array(
|
||||
'type' => 'test_field_widget',
|
||||
))
|
||||
->save();
|
||||
|
||||
// Check that the links for edit and delete are not present.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields');
|
||||
$locked = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field_name));
|
||||
$this->assertTrue(in_array('Locked', $locked), 'Field is marked as Locked in the UI');
|
||||
$edit_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field_name));
|
||||
$this->assertFalse(in_array('edit', $edit_link), 'Edit option for locked field is not present the UI');
|
||||
$delete_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field_name));
|
||||
$this->assertFalse(in_array('delete', $delete_link), 'Delete option for locked field is not present the UI');
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/node.' . $this->contentType . '.' . $field_name . '/delete');
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Field UI respects the 'no_ui' flag in the field type definition.
|
||||
*/
|
||||
function testHiddenFields() {
|
||||
// Check that the field type is not available in the 'add new field' row.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/add-field');
|
||||
$this->assertFalse($this->xpath('//select[@id="edit-new-storage-type"]//option[@value="hidden_test_field"]'), "The 'add new field' select respects field types 'no_ui' property.");
|
||||
$this->assertTrue($this->xpath('//select[@id="edit-new-storage-type"]//option[@value="shape"]'), "The 'add new field' select shows a valid option.");
|
||||
|
||||
// Create a field storage and a field programmatically.
|
||||
$field_name = 'hidden_test_field';
|
||||
FieldStorageConfig::create(array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'type' => $field_name,
|
||||
))->save();
|
||||
$field = array(
|
||||
'field_name' => $field_name,
|
||||
'bundle' => $this->contentType,
|
||||
'entity_type' => 'node',
|
||||
'label' => t('Hidden field'),
|
||||
);
|
||||
FieldConfig::create($field)->save();
|
||||
entity_get_form_display('node', $this->contentType, 'default')
|
||||
->setComponent($field_name)
|
||||
->save();
|
||||
$this->assertTrue(FieldConfig::load('node.' . $this->contentType . '.' . $field_name), format_string('A field of the field storage %field was created programmatically.', array('%field' => $field_name)));
|
||||
|
||||
// Check that the newly added field appears on the 'Manage Fields'
|
||||
// screen.
|
||||
$this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields');
|
||||
$this->assertFieldByXPath('//table[@id="field-overview"]//tr[@id="hidden-test-field"]//td[1]', $field['label'], 'Field was created and appears in the overview page.');
|
||||
|
||||
// Check that the field does not appear in the 're-use existing field' row
|
||||
// on other bundles.
|
||||
$this->drupalGet('admin/structure/types/manage/page/fields/add-field');
|
||||
$this->assertFalse($this->xpath('//select[@id="edit-existing-storage-name"]//option[@value=:field_name]', array(':field_name' => $field_name)), "The 're-use existing field' select respects field types 'no_ui' property.");
|
||||
$this->assertTrue($this->xpath('//select[@id="edit-existing-storage-name"]//option[@value=:field_name]', array(':field_name' => 'field_tags')), "The 're-use existing field' select shows a valid option.");
|
||||
|
||||
// Check that non-configurable fields are not available.
|
||||
$field_types = \Drupal::service('plugin.manager.field.field_type')->getDefinitions();
|
||||
foreach ($field_types as $field_type => $definition) {
|
||||
if (empty($definition['no_ui'])) {
|
||||
$this->assertTrue($this->xpath('//select[@id="edit-new-storage-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), SafeMarkup::format('Configurable field type @field_type is available.', array('@field_type' => $field_type)));
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($this->xpath('//select[@id="edit-new-storage-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), SafeMarkup::format('Non-configurable field type @field_type is not available.', array('@field_type' => $field_type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function testDuplicateFieldName() {
|
||||
// field_tags already exists, so we're expecting an error when trying to
|
||||
// create a new field with the same name.
|
||||
$edit = array(
|
||||
'field_name' => 'tags',
|
||||
'label' => $this->randomMachineName(),
|
||||
'new_storage_type' => 'entity_reference',
|
||||
);
|
||||
$url = 'admin/structure/types/manage/' . $this->contentType . '/fields/add-field';
|
||||
$this->drupalPostForm($url, $edit, t('Save and continue'));
|
||||
|
||||
$this->assertText(t('The machine-readable name is already in use. It must be unique.'));
|
||||
$this->assertUrl($url, array(), 'Stayed on the same page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that deletion removes field storages and fields as expected for a term.
|
||||
*/
|
||||
function testDeleteTaxonomyField() {
|
||||
// Create a new field.
|
||||
$bundle_path = 'admin/structure/taxonomy/manage/tags/overview';
|
||||
|
||||
$this->fieldUIAddNewField($bundle_path, $this->fieldNameInput, $this->fieldLabel);
|
||||
|
||||
// Delete the field.
|
||||
$this->fieldUIDeleteField($bundle_path, "taxonomy_term.tags.$this->fieldName", $this->fieldLabel, 'Tags');
|
||||
|
||||
// Check that the field was deleted.
|
||||
$this->assertNull(FieldConfig::loadByName('taxonomy_term', 'tags', $this->fieldName), 'Field was deleted.');
|
||||
// Check that the field storage was deleted too.
|
||||
$this->assertNull(FieldStorageConfig::loadByName('taxonomy_term', $this->fieldName), 'Field storage was deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that help descriptions render valid HTML.
|
||||
*/
|
||||
function testHelpDescriptions() {
|
||||
// Create an image field
|
||||
FieldStorageConfig::create(array(
|
||||
'field_name' => 'field_image',
|
||||
'entity_type' => 'node',
|
||||
'type' => 'image',
|
||||
))->save();
|
||||
|
||||
FieldConfig::create(array(
|
||||
'field_name' => 'field_image',
|
||||
'entity_type' => 'node',
|
||||
'label' => 'Image',
|
||||
'bundle' => 'article',
|
||||
))->save();
|
||||
|
||||
entity_get_form_display('node', 'article', 'default')->setComponent('field_image')->save();
|
||||
|
||||
$edit = array(
|
||||
'description' => '<strong>Test with an upload field.',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_image', $edit, t('Save settings'));
|
||||
|
||||
// Check that hook_field_widget_form_alter() does believe this is the
|
||||
// default value form.
|
||||
$this->drupalGet('admin/structure/types/manage/article/fields/node.article.field_tags');
|
||||
$this->assertText('From hook_field_widget_form_alter(): Default form is true.', 'Default value form in hook_field_widget_form_alter().');
|
||||
|
||||
$edit = array(
|
||||
'description' => '<em>Test with a non upload field.',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_tags', $edit, t('Save settings'));
|
||||
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertRaw('<strong>Test with an upload field.</strong>');
|
||||
$this->assertRaw('<em>Test with a non upload field.</em>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the field list administration page operates correctly.
|
||||
*/
|
||||
function fieldListAdminPage() {
|
||||
$this->drupalGet('admin/reports/fields');
|
||||
$this->assertText($this->fieldName, 'Field name is displayed in field list.');
|
||||
$this->assertTrue($this->assertLinkByHref('admin/structure/types/manage/' . $this->contentType . '/fields'), 'Link to content type using field is displayed in field list.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the "preconfigured field" functionality.
|
||||
*
|
||||
* @see \Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface
|
||||
*/
|
||||
public function testPreconfiguredFields() {
|
||||
$this->drupalGet('admin/structure/types/manage/article/fields/add-field');
|
||||
|
||||
// Check that the preconfigured field option exist alongside the regular
|
||||
// field type option.
|
||||
$this->assertOption('edit-new-storage-type', 'field_ui:test_field_with_preconfigured_options:custom_options');
|
||||
$this->assertOption('edit-new-storage-type', 'test_field_with_preconfigured_options');
|
||||
|
||||
// Add a field with every possible preconfigured value.
|
||||
$this->fieldUIAddNewField(NULL, 'test_custom_options', 'Test label', 'field_ui:test_field_with_preconfigured_options:custom_options');
|
||||
$field_storage = FieldStorageConfig::loadByName('node', 'field_test_custom_options');
|
||||
$this->assertEqual($field_storage->getCardinality(), FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$this->assertEqual($field_storage->getSetting('test_field_storage_setting'), 'preconfigured_storage_setting');
|
||||
|
||||
$field = FieldConfig::loadByName('node', 'article', 'field_test_custom_options');
|
||||
$this->assertTrue($field->isRequired());
|
||||
$this->assertEqual($field->getSetting('test_field_setting'), 'preconfigured_field_setting');
|
||||
|
||||
$form_display = entity_get_form_display('node', 'article', 'default');
|
||||
$this->assertEqual($form_display->getComponent('field_test_custom_options')['type'], 'test_field_widget_multiple');
|
||||
$view_display = entity_get_display('node', 'article', 'default');
|
||||
$this->assertEqual($view_display->getComponent('field_test_custom_options')['type'], 'field_test_multiple');
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue