Commit 4586ea12 authored by alexpott's avatar alexpott

Issue #2014821 by amateescu, swentel: Introduce form modes UI and their configuration entity.

parent 264d1d97
......@@ -105,6 +105,44 @@ function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = N
module_invoke_all('entity_bundle_' . $hook, $entity_type, $bundle, $bundle_new);
}
/**
* Returns the entity form mode info.
*
* @param string|null $entity_type
* The entity type whose form mode info should be returned, or NULL for all
* form mode info. Defaults to NULL.
*
* @return array
* The form mode info for a specific entity type, or all entity types.
*/
function entity_get_form_modes($entity_type = NULL) {
$form_modes = &drupal_static(__FUNCTION__);
if (!$form_modes) {
$langcode = language(Language::TYPE_INTERFACE)->langcode;
if ($cache = cache()->get("entity_form_mode_info:$langcode")) {
$form_modes = $cache->data;
}
else {
$form_modes = array();
foreach (entity_load_multiple('form_mode') as $form_mode) {
list($form_mode_entity_type, $form_mode_name) = explode('.', $form_mode->id(), 2);
$form_modes[$form_mode_entity_type][$form_mode_name] = (array) $form_mode;
}
drupal_alter('entity_form_mode_info', $form_modes);
cache()->set("entity_form_mode_info:$langcode", $form_modes, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
}
}
if (empty($entity_type)) {
return $form_modes;
}
elseif (isset($form_modes[$entity_type])) {
return $form_modes[$entity_type];
}
return array();
}
/**
* Returns the entity view mode info.
*
......@@ -791,9 +829,13 @@ function entity_get_render_form_display(EntityInterface $entity, $form_mode) {
$entity_type = $entity->entityType();
$bundle = $entity->bundle();
// @todo Form modes don't have custom settings yet, so just return the display
// for the form mode that was requested.
$form_display = entity_get_form_display($entity_type, $bundle, $form_mode);
// Determine the form display to use for rendering this entity form. Depending
// on the configuration of the form mode for this bundle, this will be either
// the form display associated to the form mode, or the 'default' display.
$form_mode_settings = field_form_mode_settings($entity_type, $bundle);
$render_form_mode = !empty($form_mode_settings[$form_mode]['status']) ? $form_mode : 'default';
$form_display = entity_get_form_display($entity_type, $bundle, $render_form_mode);
$form_display->originalMode = $form_mode;
return $form_display;
......
......@@ -129,15 +129,13 @@ protected function init(array &$form_state) {
$form_state['controller'] = $this;
$this->prepareEntity();
// @todo Allow the usage of different form modes by exposing a hook and the
// UI for them.
$form_display = entity_get_render_form_display($this->entity, 'default');
$form_display = entity_get_render_form_display($this->entity, $this->getOperation());
// Let modules alter the form display.
$form_display_context = array(
'entity_type' => $this->entity->entityType(),
'bundle' => $this->entity->bundle(),
'form_mode' => 'default',
'form_mode' => $this->getOperation(),
);
\Drupal::moduleHandler()->alter('entity_form_display', $form_display, $form_display_context);
......@@ -158,12 +156,8 @@ public function form(array $form, array &$form_state) {
field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state));
}
// Assign the weights configured in the form display.
foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) {
if (isset($form[$name])) {
$form[$name]['#weight'] = $options['weight'];
}
}
// Add a process callback so we can assign weights and hide extra fields.
$form['#process'][] = array($this, 'processForm');
if (!isset($form['langcode'])) {
// If the form did not specify otherwise, default to keeping the existing
......@@ -177,6 +171,30 @@ public function form(array $form, array &$form_state) {
return $form;
}
/**
* Process callback: assigns weights and hides extra fields.
*
* @see \Drupal\Core\Entity\EntityFormController::form()
*/
public function processForm($element, $form_state, $form) {
// Assign the weights configured in the form display.
foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) {
if (isset($element[$name])) {
$element[$name]['#weight'] = $options['weight'];
}
}
// Hide extra fields.
$extra_fields = field_info_extra_fields($this->entity->entityType(), $this->entity->bundle(), 'form');
foreach ($extra_fields as $extra_field => $info) {
if (!$this->getFormDisplay($form_state)->getComponent($extra_field)) {
$element[$extra_field]['#access'] = FALSE;
}
}
return $element;
}
/**
* Returns the action form element for the current entity form.
*/
......
......@@ -31,12 +31,8 @@ public function form(array $form, array &$form_state) {
field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state));
}
// Assign the weights configured in the form display.
foreach ($this->getFormDisplay($form_state)->getComponents() as $name => $options) {
if (isset($form[$name])) {
$form[$name]['#weight'] = $options['weight'];
}
}
// Add a process callback so we can assign weights and hide extra fields.
$form['#process'][] = array($this, 'processForm');
return $form;
}
......
......@@ -28,11 +28,17 @@ public function getOperations(EntityInterface $entity) {
'options' => $uri['options'],
'weight' => 15,
);
$operations['manage-form-display'] = array(
'title' => t('Manage form display'),
'href' => $uri['path'] . '/form-display',
'options' => $uri['options'],
'weight' => 20,
);
$operations['manage-display'] = array(
'title' => t('Manage display'),
'href' => $uri['path'] . '/display',
'options' => $uri['options'],
'weight' => 20,
'weight' => 25,
);
}
return $operations;
......
......@@ -257,8 +257,10 @@ function comment_menu_alter(&$items) {
// See comment_entity_bundle_info().
$items['admin/structure/types/manage/{bundle}/comment/fields']['title'] = 'Comment fields';
$items['admin/structure/types/manage/{bundle}/comment/fields']['weight'] = 3;
$items['admin/structure/types/manage/{bundle}/comment/form-display']['title'] = 'Comment form display';
$items['admin/structure/types/manage/{bundle}/comment/form-display']['weight'] = 4;
$items['admin/structure/types/manage/{bundle}/comment/display']['title'] = 'Comment display';
$items['admin/structure/types/manage/{bundle}/comment/display']['weight'] = 4;
$items['admin/structure/types/manage/{bundle}/comment/display']['weight'] = 5;
}
/**
......
......@@ -314,16 +314,16 @@ function contact_mail($key, &$message, $params) {
*
* Add the enable personal contact form to an individual user's account page.
*
* @see user_profile_form()
* @see \Drupal\user\ProfileFormController::form()
*/
function contact_form_user_profile_form_alter(&$form, &$form_state) {
function contact_form_user_form_alter(&$form, &$form_state) {
$form['contact'] = array(
'#type' => 'details',
'#title' => t('Contact settings'),
'#weight' => 5,
);
$account = $form_state['controller']->getEntity();
$account_data = Drupal::service('user.data')->get('contact', $account->id(), 'enabled');
$account_data = !user_is_anonymous() ? Drupal::service('user.data')->get('contact', $account->id(), 'enabled') : NULL;
$form['contact']['contact'] = array(
'#type' => 'checkbox',
'#title' => t('Personal contact form'),
......
......@@ -27,11 +27,17 @@ public function getOperations(EntityInterface $entity) {
'options' => $uri['options'],
'weight' => 11,
);
$operations['manage-form-display'] = array(
'title' => t('Manage form display'),
'href' => $uri['path'] . '/form-display',
'options' => $uri['options'],
'weight' => 12,
);
$operations['manage-display'] = array(
'title' => t('Manage display'),
'href' => $uri['path'] . '/display',
'options' => $uri['options'],
'weight' => 12,
'weight' => 13,
);
}
return $operations;
......
......@@ -237,7 +237,6 @@ function testSiteWideContact() {
'fields[_add_new_field][label]' => $field_label = $this->randomName(),
'fields[_add_new_field][field_name]' => Unicode::strtolower($this->randomName()),
'fields[_add_new_field][type]' => 'text',
'fields[_add_new_field][widget_type]' => 'text_textfield',
);
$field_name = 'field_' . $edit['fields[_add_new_field][field_name]'];
$this->drupalPost(NULL, $edit, t('Save'));
......
......@@ -188,4 +188,19 @@ function settingsForm(array $form, array &$form_state) {
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = array();
$summary[] = t('Date part order: !order', array('!order' => $this->getSetting('date_order')));
if ($this->getFieldSetting('datetime_type') == 'datetime') {
$summary[] = t('Time type: !time_type', array('!time_type' => $this->getSetting('time_type')));
}
$summary[] = t('Time increments: !increment', array('!increment' => $this->getSetting('increment')));
return $summary;
}
}
......@@ -68,7 +68,7 @@ public function generate(EntityInterface $entity, FieldInstance $instance, $lang
}
// Early-return if no editor is available.
$formatter_id = entity_get_render_display($entity, $view_mode)->getFormatter($instance['field_name'])->getPluginId();
$formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($instance['field_name'])->getPluginId();
$items = $entity->getTranslation($langcode, FALSE)->get($field_name)->getValue();
$editor_id = $this->editorSelector->getEditor($formatter_id, $instance, $items);
if (!isset($editor_id)) {
......
......@@ -41,6 +41,23 @@ public function settingsForm(array $form, array &$form_state) {
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = array();
$placeholder = $this->getSetting('placeholder');
if (!empty($placeholder)) {
$summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
}
else {
$summary[] = t('No placeholder');
}
return $summary;
}
/**
* Implements Drupal\field\Plugin\Type\Widget\WidgetInterface::formElement().
*/
......
......@@ -163,7 +163,7 @@ public function createCopy($mode) {
public function getComponents() {
$result = array();
foreach ($this->content as $name => $options) {
if (!isset($options['visible']) || $options['visible'] === TRUE) {
if (!isset($options['visible']) || $options['visible'] == TRUE) {
unset($options['visible']);
$result[$name] = $options;
}
......
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\entity\Plugin\Core\Entity\EntityDisplayBaseInterface.
* Contains \Drupal\entity\EntityDisplayBaseInterface.
*/
namespace Drupal\entity;
......@@ -81,4 +81,15 @@ public function removeComponent($name);
*/
public function getHighestWeight();
/**
* Returns the renderer plugin for a field (e.g. widget, formatter).
*
* @param string $field_name
* The field name.
*
* @return \Drupal\field\Plugin\PluginSettingsInterface|null
* A widget or formatter plugin or NULL if the field does not exist.
*/
public function getRenderer($field_name);
}
......@@ -14,16 +14,4 @@
*/
interface EntityDisplayInterface extends EntityDisplayBaseInterface {
/**
* Returns the Formatter plugin for a field.
*
* @param string $field_name
* The field name.
*
* @return \Drupal\field\Plugin\Type\Formatter\FormatterInterface
* If the field is not hidden, the Formatter plugin to use for rendering
* it.
*/
public function getFormatter($field_name);
}
<?php
/**
* @file
* Contains \Drupal\entity\EntityDisplayModeBase.
*/
namespace Drupal\entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Base class for config entity types that hold settings for form and view modes.
*/
abstract class EntityDisplayModeBase extends ConfigEntityBase {
/**
* The ID of the form or view mode.
*
* @var string
*/
public $id;
/**
* The UUID of the form or view mode.
*
* @var string
*/
public $uuid;
/**
* The human-readable name of the form or view mode.
*
* @var string
*/
public $label;
/**
* The entity type this form or view mode is used for.
*
* This is not to be confused with EntityViewMode::entityType which is
* inherited from Entity::entityType.
*
* @var string
*/
public $targetEntityType;
/**
* Whether or not this form or view mode has custom settings by default.
*
* If FALSE, entities displayed in this mode will reuse the 'default' display
* settings by default (e.g. right after the module exposing the form or view
* mode is enabled), but administrators can later use the Field UI to apply
* custom display settings specific to the form or view mode.
*
* @var bool
*/
public $status = FALSE;
}
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\entity\EntityViewModeStorageController.
* Contains \Drupal\entity\EntityDisplayModeStorageController.
*/
namespace Drupal\entity;
......@@ -11,9 +11,9 @@
use Drupal\Core\Entity\EntityInterface;
/**
* Defines the storage controller class for entity view modes.
* Defines the storage controller class for entity form and view modes.
*/
class EntityViewModeStorageController extends ConfigStorageController {
class EntityDisplayModeStorageController extends ConfigStorageController {
/**
* {@inheritdoc}
......
......@@ -14,15 +14,4 @@
*/
interface EntityFormDisplayInterface extends EntityDisplayBaseInterface {
/**
* Returns the Widget plugin for a field.
*
* @param string $field_name
* The field name.
*
* @return \Drupal\field\Plugin\Type\Widget\WidgetInterface|null
* A Widget plugin or NULL if the field does not exist.
*/
public function getWidget($field_name);
}
<?php
/**
* @file
* Contains \Drupal\entity\EntityFormModeInterface.
*/
namespace Drupal\entity;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface defining an entity form mode entity type.
*/
interface EntityFormModeInterface extends ConfigEntityInterface {
}
......@@ -10,7 +10,7 @@
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface defining an entity view mode entity.
* Provides an interface defining an entity view mode entity type.
*/
interface EntityViewModeInterface extends ConfigEntityInterface {
......
......@@ -45,7 +45,7 @@ public function __construct(array $values, $entity_type) {
/**
* {@inheritdoc}
*/
public function getFormatter($field_name) {
public function getRenderer($field_name) {
if (isset($this->plugins[$field_name])) {
return $this->plugins[$field_name];
}
......
......@@ -45,7 +45,7 @@ public function __construct(array $values, $entity_type) {
/**
* {@inheritdoc}
*/
public function getWidget($field_name) {
public function getRenderer($field_name) {
if (isset($this->plugins[$field_name])) {
return $this->plugins[$field_name];
}
......
<?php
/**
* @file
* Contains \Drupal\entity\Plugin\Core\Entity\EntityFormMode.
*/
namespace Drupal\entity\Plugin\Core\Entity;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
use Drupal\entity\EntityDisplayModeBase;
use Drupal\entity\EntityFormModeInterface;
/**
* Defines the form mode configuration entity class.
*
* Form modes allow entity forms to be displayed differently depending on the
* context. For instance, the user entity form can be displayed with a set of
* fields on the 'profile' page (user edit page) and with a different set of
* fields (or settings) on the user registration page. Modules taking part in
* the display of the entity form (notably the Field API) can adjust their
* behavior depending on the requested form mode. An additional 'default' form
* mode is available for all entity types. For each available form mode,
* administrators can configure whether it should use its own set of field
* display settings, or just replicate the settings of the 'default' form mode,
* thus reducing the amount of form display configurations to keep track of.
*
* @see entity_get_form_modes()
* @see hook_entity_form_mode_info_alter()
*
* @EntityType(
* id = "form_mode",
* label = @Translation("Form mode"),
* module = "entity",
* controllers = {
* "storage" = "Drupal\entity\EntityDisplayModeStorageController"
* },
* config_prefix = "entity.form_mode",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* }
* )
*/
class EntityFormMode extends EntityDisplayModeBase implements EntityFormModeInterface {
}
......@@ -7,9 +7,9 @@
namespace Drupal\entity\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
use Drupal\entity\EntityDisplayModeBase;
use Drupal\entity\EntityViewModeInterface;
/**
......@@ -35,7 +35,7 @@
* label = @Translation("View mode"),
* module = "entity",
* controllers = {
* "storage" = "Drupal\entity\EntityViewModeStorageController"
* "storage" = "Drupal\entity\EntityDisplayModeStorageController"
* },
* config_prefix = "entity.view_mode",
* entity_keys = {
......@@ -45,50 +45,6 @@
* }
* )
*/
class EntityViewMode extends ConfigEntityBase implements EntityViewModeInterface {
/**
* The ID of the view mode.
*
* @var string
*/
public $id;
/**
* The UUID of the view mode.
*
* @var string
*/
public $uuid;
/**
* The human-readable name of the view mode.
*
* @var string
*/
public $label;
/**
* The entity type this view mode is used for.
*
* This is not to be confused with EntityViewMode::entityType which is
* inherited from Entity::entityType and equals 'view_mode' for any view mode
* entity.
*
* @var string
*/
public $targetEntityType;
/**
* Whether or not this view mode has custom settings by default.
*
* If FALSE, entities displayed in this view mode will reuse the 'default'
* display settings by default (e.g. right after the module exposing the view
* mode is enabled), but administrators can later use the Field UI to apply
* custom display settings specific to the view mode.
*
* @var bool
*/
public $status = FALSE;
class EntityViewMode extends EntityDisplayModeBase implements EntityViewModeInterface {
}
......@@ -167,7 +167,7 @@ public function testFieldComponent() {
$this->assertEqual($display->getComponent($field_name), $expected);
// Check that the getFormatter() method returns the correct formatter plugin.
$formatter = $display->getFormatter($field_name);
$formatter = $display->getRenderer($field_name);
$this->assertEqual($formatter->getPluginId(), $default_formatter);
$this->assertEqual($formatter->getSettings(), $default_settings);
......@@ -175,14 +175,14 @@ public function testFieldComponent() {
// arbitrary property and reading it back.
$random_value = $this->randomString();
$formatter->randomValue = $random_value;
$formatter = $display->getFormatter($field_name);
$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->getFormatter($field_name);
$formatter = $display->getRenderer($field_name);
$this->assertEqual($formatter->getPluginId(), 'field_test_multiple');
$this->assertFalse(isset($formatter->randomValue));
......@@ -194,7 +194,7 @@ public function testFieldComponent() {
));
$options = $display->getComponent($field_name);
$this->assertEqual($options['type'], 'unknown_formatter');
$formatter = $display->getFormatter($field_name);
$formatter = $display->getRenderer($field_name);
$this->assertEqual($formatter->getPluginId(), $default_formatter);
}
......
......@@ -88,7 +88,7 @@ public function testFieldComponent() {
$this->assertEqual($form_display->getComponent($field_name), $expected);
// Check that the getWidget() method returns the correct widget plugin.
$widget = $form_display->getWidget($field_name);
$widget = $form_display->getRenderer($field_name);
$this->assertEqual($widget->getPluginId(), $default_widget);
$this->assertEqual($widget->getSettings(), $default_settings);
......@@ -96,14 +96,14 @@ public function testFieldComponent() {
// arbitrary property and reading it back.
$random_value = $this->randomString();
$widget->randomValue = $random_value;
$widget = $form_display->getWidget($field_name);
$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->getWidget($field_name);
$widget = $form_display->getRenderer($field_name);
$this->assertEqual($widget->getPluginId(), 'test_field_widget');
$this->assertFalse(isset($widget->randomValue));
......@@ -115,7 +115,7 @@ public function testFieldComponent() {
));
$options = $form_display->getComponent($field_name);
$this->assertEqual($options['type'], 'unknown_widget');
$widget = $form_display->getWidget($field_name);
$widget = $form_display->getRenderer($field_name);
$this->assertEqual($widget->getPluginId(), $default_widget);
}
......