Commit 518c4d10 authored by alexpott's avatar alexpott

Issue #1875992 by amateescu, swentel, yched: Add EntityFormDisplay objects for entity forms.

parent 750b5273
...@@ -451,6 +451,27 @@ function hook_entity_display_alter(\Drupal\entity\Plugin\Core\Entity\EntityDispl ...@@ -451,6 +451,27 @@ function hook_entity_display_alter(\Drupal\entity\Plugin\Core\Entity\EntityDispl
} }
} }
/**
* Alters the settings used for displaying an entity form.
*
* @param \Drupal\entity\Plugin\Core\Entity\EntityFormDisplay $form_display
* The entity_form_display object that will be used to display the entity form
* components.
* @param array $context
* An associative array containing:
* - entity_type: The entity type, e.g., 'node' or 'user'.
* - bundle: The bundle, e.g., 'page' or 'article'.
* - form_mode: The form mode, e.g. 'default', 'profile', 'register'...
*/
function hook_entity_form_display_alter(\Drupal\entity\Plugin\Core\Entity\EntityFormDisplay $form_display, array $context) {
// Hide the 'user_picture' field from the register form.
if ($context['entity_type'] == 'user' && $context['form_mode'] == 'register') {
$form_display->setComponent('user_picture', array(
'type' => 'hidden',
));
}
}
/** /**
* Define custom entity properties. * Define custom entity properties.
* *
......
...@@ -662,7 +662,7 @@ function entity_get_display($entity_type, $bundle, $view_mode) { ...@@ -662,7 +662,7 @@ function entity_get_display($entity_type, $bundle, $view_mode) {
$display = entity_create('entity_display', array( $display = entity_create('entity_display', array(
'targetEntityType' => $entity_type, 'targetEntityType' => $entity_type,
'bundle' => $bundle, 'bundle' => $bundle,
'viewMode' => $view_mode, 'mode' => $view_mode,
)); ));
} }
...@@ -691,7 +691,7 @@ function entity_get_display($entity_type, $bundle, $view_mode) { ...@@ -691,7 +691,7 @@ function entity_get_display($entity_type, $bundle, $view_mode) {
* @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay * @return \Drupal\entity\Plugin\Core\Entity\EntityDisplay
* The display object that should be used to render the entity. * The display object that should be used to render the entity.
* *
* @see entity_get_render_display(). * @see entity_get_display().
*/ */
function entity_get_render_display(EntityInterface $entity, $view_mode) { function entity_get_render_display(EntityInterface $entity, $view_mode) {
$entity_type = $entity->entityType(); $entity_type = $entity->entityType();
...@@ -704,11 +704,98 @@ function entity_get_render_display(EntityInterface $entity, $view_mode) { ...@@ -704,11 +704,98 @@ function entity_get_render_display(EntityInterface $entity, $view_mode) {
$render_view_mode = !empty($view_mode_settings[$view_mode]['status']) ? $view_mode : 'default'; $render_view_mode = !empty($view_mode_settings[$view_mode]['status']) ? $view_mode : 'default';
$display = entity_get_display($entity_type, $bundle, $render_view_mode); $display = entity_get_display($entity_type, $bundle, $render_view_mode);
$display->originalViewMode = $view_mode; $display->originalMode = $view_mode;
return $display; return $display;
} }
/**
* Returns the entity_form_display object associated to a bundle and form mode.
*
* The function reads the entity_form_display object from the current
* configuration, or returns a ready-to-use empty one if configuration entry
* exists yet for this bundle and form mode. This streamlines manipulation of
* EntityFormDisplay objects by always returning a consistent object that
* reflects the current state of the configuration.
*
* Example usage:
* - Set the 'body' field to be displayed with the 'text_textarea_with_summary'
* widget and the 'field_image' field to be hidden on article nodes in the
* 'default' form mode.
* @code
* entity_get_form_display('node', 'article', 'default')
* ->setComponent('body', array(
* 'type' => 'text_textarea_with_summary',
* 'weight' => 1,
* ))
* ->setComponent('field_image', array(
* 'type' => 'hidden',
* ))
* ->save();
* @endcode
*
* @param string $entity_type
* The entity type.
* @param string $bundle
* The bundle.
* @param string $form_mode
* The form mode.
*
* @return \Drupal\entity\Plugin\Core\Entity\EntityFormDisplay
* The EntityFormDisplay object associated to the form mode.
*/
function entity_get_form_display($entity_type, $bundle, $form_mode) {
// Try loading the entity from configuration.
$entity_form_display = entity_load('entity_form_display', $entity_type . '.' . $bundle . '.' . $form_mode);
// If not found, create a fresh entity object. We do not preemptively create
// new EntityFormDisplay configuration entries for each existing entity type
// and bundle whenever a new form mode becomes available. Instead,
// configuration entries are only created when a EntityFormDisplay object is
// explicitly configured and saved.
if (!$entity_form_display) {
$entity_form_display = entity_create('entity_form_display', array(
'targetEntityType' => $entity_type,
'bundle' => $bundle,
'mode' => $form_mode,
));
}
return $entity_form_display;
}
/**
* Returns the entity_form_display object used to render an entity form.
*
* This function should only be used internally when rendering an entity form.
* When assigning suggested form display options for a component in a given form
* mode, entity_get_form_display() should be used instead, in order to avoid
* inadvertently modifying the output of other form modes that might happen to
* use the 'default' form display too. Those options will then be effectively
* applied only if the form mode is configured to use them.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity for which the form is being rendered.
* @param string $form_mode
* The form mode being rendered.
*
* @return \Drupal\entity\Plugin\Core\Entity\EntityFormDisplay
* The form display object that should be used to render the entity form.
*
* @see entity_get_form_display().
*/
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);
$form_display->originalMode = $form_mode;
return $form_display;
}
/** /**
* Generic access callback for entity pages. * Generic access callback for entity pages.
* *
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace Drupal\Core\Entity; namespace Drupal\Core\Entity;
use Drupal\entity\EntityFormDisplayInterface;
/** /**
* Base class for entity form controllers. * Base class for entity form controllers.
*/ */
...@@ -117,6 +119,20 @@ protected function init(array &$form_state) { ...@@ -117,6 +119,20 @@ protected function init(array &$form_state) {
// module-provided form handlers there. // module-provided form handlers there.
$form_state['controller'] = $this; $form_state['controller'] = $this;
$this->prepareEntity(); $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');
// Let modules alter the form display.
$form_display_context = array(
'entity_type' => $this->entity->entityType(),
'bundle' => $this->entity->bundle(),
'form_mode' => 'default',
);
\Drupal::moduleHandler()->alter('entity_form_display', $form_display, $form_display_context);
$this->setFormDisplay($form_display, $form_state);
} }
/** /**
...@@ -132,6 +148,14 @@ public function form(array $form, array &$form_state) { ...@@ -132,6 +148,14 @@ public function form(array $form, array &$form_state) {
if (!empty($info['fieldable'])) { if (!empty($info['fieldable'])) {
field_attach_form($entity, $form, $form_state, $this->getFormLangcode($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'];
}
}
if (!isset($form['langcode'])) { if (!isset($form['langcode'])) {
// If the form did not specify otherwise, default to keeping the existing // If the form did not specify otherwise, default to keeping the existing
// language of the entity or defaulting to the site default language for // language of the entity or defaulting to the site default language for
...@@ -393,6 +417,21 @@ protected function prepareEntity() { ...@@ -393,6 +417,21 @@ protected function prepareEntity() {
// @todo Perform common prepare operations and add a hook. // @todo Perform common prepare operations and add a hook.
} }
/**
* {@inheritdoc}
*/
public function getFormDisplay(array $form_state) {
return isset($form_state['form_display']) ? $form_state['form_display'] : NULL;
}
/**
* {@inheritdoc}
*/
public function setFormDisplay(EntityFormDisplayInterface $form_display, array &$form_state) {
$form_state['form_display'] = $form_display;
return $this;
}
/** /**
* Implements \Drupal\Core\Entity\EntityFormControllerInterface::getOperation(). * Implements \Drupal\Core\Entity\EntityFormControllerInterface::getOperation().
*/ */
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\Core\Entity; namespace Drupal\Core\Entity;
use Drupal\Core\Form\BaseFormIdInterface; use Drupal\Core\Form\BaseFormIdInterface;
use Drupal\entity\EntityFormDisplayInterface;
/** /**
* Defines a common interface for entity form controller classes. * Defines a common interface for entity form controller classes.
...@@ -44,6 +45,30 @@ public function isDefaultFormLangcode(array $form_state); ...@@ -44,6 +45,30 @@ public function isDefaultFormLangcode(array $form_state);
*/ */
public function getOperation(); public function getOperation();
/**
* Returns the form display.
*
* @param array $form_state
* An associative array containing the current state of the form.
*
* @return \Drupal\entity\EntityFormDisplayInterface
* The current form display.
*/
public function getFormDisplay(array $form_state);
/**
* Sets the form display.
*
* Sets the form display which will be used for populating form element
* defaults.
*
* @param \Drupal\entity\EntityFormDisplayInterface $form_display
* The form display that the current form operates with.
* @param array $form_state
* An associative array containing the current state of the form.
*/
public function setFormDisplay(EntityFormDisplayInterface $form_display, array &$form_state);
/** /**
* Returns the form entity. * Returns the form entity.
* *
......
...@@ -30,6 +30,14 @@ public function form(array $form, array &$form_state) { ...@@ -30,6 +30,14 @@ public function form(array $form, array &$form_state) {
if (!empty($info['fieldable'])) { if (!empty($info['fieldable'])) {
field_attach_form($entity, $form, $form_state, $this->getFormLangcode($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'];
}
}
return $form; return $form;
} }
......
...@@ -259,11 +259,19 @@ function block_update_8008() { ...@@ -259,11 +259,19 @@ function block_update_8008() {
'entity_type' => 'custom_block', 'entity_type' => 'custom_block',
'bundle' => 'basic', 'bundle' => 'basic',
'label' => 'Block body', 'label' => 'Block body',
'widget' => array('type' => 'text_textarea_with_summary'),
'settings' => array('display_summary' => FALSE), 'settings' => array('display_summary' => FALSE),
); );
_update_7000_field_create_instance($body_field, $instance); _update_7000_field_create_instance($body_field, $instance);
module_load_install('entity');
// Assign form settings for the 'default' form mode.
$form_display = _update_8000_entity_get_form_display('custom_block', 'basic', 'default');
$form_display->set('content.user_picture', array(
'type' => 'text_textarea_with_summary',
))
->save();
update_config_manifest_add('entity.form_display', array($form_display->get('id')));
// Initialize state for future calls. // Initialize state for future calls.
$sandbox['last'] = 0; $sandbox['last'] = 0;
$sandbox['count'] = 0; $sandbox['count'] = 0;
......
...@@ -214,11 +214,17 @@ function custom_block_add_body_field($block_type_id, $label = 'Block body') { ...@@ -214,11 +214,17 @@ function custom_block_add_body_field($block_type_id, $label = 'Block body') {
'entity_type' => 'custom_block', 'entity_type' => 'custom_block',
'bundle' => $block_type_id, 'bundle' => $block_type_id,
'label' => $label, 'label' => $label,
'widget' => array('type' => 'text_textarea_with_summary'),
'settings' => array('display_summary' => FALSE), 'settings' => array('display_summary' => FALSE),
); );
$instance = field_create_instance($instance); $instance = field_create_instance($instance);
// Assign widget settings for the 'default' form mode.
entity_get_form_display('custom_block', $block_type_id, 'default')
->setComponent('block_body', array(
'type' => 'text_textarea_with_summary',
))
->save();
// Assign display settings for 'default' view mode. // Assign display settings for 'default' view mode.
entity_get_display('custom_block', $block_type_id, 'default') entity_get_display('custom_block', $block_type_id, 'default')
->setComponent('block_body', array( ->setComponent('block_body', array(
......
...@@ -77,17 +77,18 @@ public function testBlockFields() { ...@@ -77,17 +77,18 @@ public function testBlockFields() {
'settings' => array( 'settings' => array(
'title' => DRUPAL_OPTIONAL, 'title' => DRUPAL_OPTIONAL,
), ),
'widget' => array(
'type' => 'link_default',
),
);
$display_options = array(
'type' => 'link',
'label' => 'hidden',
); );
field_create_instance($this->instance); field_create_instance($this->instance);
entity_get_form_display('custom_block', 'link', 'default')
->setComponent($this->field['field_name'], array(
'type' => 'link_default',
))
->save();
entity_get_display('custom_block', 'link', 'default') entity_get_display('custom_block', 'link', 'default')
->setComponent($this->field['field_name'], $display_options) ->setComponent($this->field['field_name'], array(
'type' => 'link',
'label' => 'hidden',
))
->save(); ->save();
// Create a block. // Create a block.
......
...@@ -365,6 +365,15 @@ function _comment_body_field_create($info) { ...@@ -365,6 +365,15 @@ function _comment_body_field_create($info) {
'required' => TRUE, 'required' => TRUE,
); );
field_create_instance($instance); field_create_instance($instance);
// Assign widget settings for the 'default' form mode.
entity_get_form_display('comment', 'comment_node_' . $info->type, 'default')
->setComponent('comment_body', array(
'type' => 'text_textarea',
))
->save();
// Assign display settings for the 'default' view mode.
entity_get_display('comment', 'comment_node_' . $info->type, 'default') entity_get_display('comment', 'comment_node_' . $info->type, 'default')
->setComponent('comment_body', array( ->setComponent('comment_body', array(
'label' => 'hidden', 'label' => 'hidden',
......
...@@ -134,9 +134,7 @@ function datetime_field_settings_form($field, $instance, $has_data) { ...@@ -134,9 +134,7 @@ function datetime_field_settings_form($field, $instance, $has_data) {
* Implements hook_field_instance_settings_form(). * Implements hook_field_instance_settings_form().
*/ */
function datetime_field_instance_settings_form($field, $instance) { function datetime_field_instance_settings_form($field, $instance) {
$widget = $instance['widget'];
$settings = $instance['settings']; $settings = $instance['settings'];
$widget_settings = $instance['widget']['settings'];
$form['default_value'] = array( $form['default_value'] = array(
'#type' => 'select', '#type' => 'select',
......
...@@ -36,23 +36,12 @@ ...@@ -36,23 +36,12 @@
class DateTimeDatelistWidget extends WidgetBase { class DateTimeDatelistWidget extends WidgetBase {
/** /**
* Constructs a DateTimeDatelist Widget object. * {@inheritdoc}
*
* @param array $plugin_id
* The plugin_id for the widget.
* @param array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\field\Plugin\Core\Entity\FieldInstance $instance
* The field instance to which the widget is associated.
* @param array $settings
* The widget settings.
* @param int $weight
* The widget weight.
*/ */
public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings, $weight) { public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings) {
// Identify the function used to set the default value. // Identify the function used to set the default value.
$instance['default_value_function'] = $this->defaultValueFunction(); $instance['default_value_function'] = $this->defaultValueFunction();
parent::__construct($plugin_id, $plugin_definition, $instance, $settings, $weight); parent::__construct($plugin_id, $plugin_definition, $instance, $settings);
} }
/** /**
......
...@@ -30,23 +30,12 @@ ...@@ -30,23 +30,12 @@
class DateTimeDefaultWidget extends WidgetBase { class DateTimeDefaultWidget extends WidgetBase {
/** /**
* Constructs a DateTimeDefault Widget object. * {@inheritdoc}
*
* @param array $plugin_id
* The plugin_id for the widget.
* @param array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\field\Plugin\Core\Entity\FieldInstance $instance
* The field instance to which the widget is associated.
* @param array $settings
* The widget settings.
* @param int $weight
* The widget weight.
*/ */
public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings, $weight) { public function __construct($plugin_id, array $plugin_definition, FieldInstance $instance, array $settings) {
// Identify the function used to set the default value. // Identify the function used to set the default value.
$instance['default_value_function'] = $this->defaultValueFunction(); $instance['default_value_function'] = $this->defaultValueFunction();
parent::__construct($plugin_id, $plugin_definition, $instance, $settings, $weight); parent::__construct($plugin_id, $plugin_definition, $instance, $settings);
} }
/** /**
......
...@@ -57,14 +57,17 @@ function setUp() { ...@@ -57,14 +57,17 @@ function setUp() {
'field_name' => $this->field['field_name'], 'field_name' => $this->field['field_name'],
'entity_type' => 'test_entity', 'entity_type' => 'test_entity',
'bundle' => 'test_bundle', 'bundle' => 'test_bundle',
'widget' => array(
'type' => 'datetime_default',
),
'settings' => array( 'settings' => array(
'default_value' => 'blank', 'default_value' => 'blank',
), ),
)); ));
entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
->setComponent($this->field['field_name'], array(
'type' => 'datetime_default',
))
->save();
$this->display_options = array( $this->display_options = array(
'type' => 'datetime_default', 'type' => 'datetime_default',
'label' => 'hidden', 'label' => 'hidden',
...@@ -217,17 +220,16 @@ function testDatelistWidget() { ...@@ -217,17 +220,16 @@ function testDatelistWidget() {
field_update_field($this->field); field_update_field($this->field);
// Change the widget to a datelist widget. // Change the widget to a datelist widget.
$increment = 1; entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
$date_order = 'YMD'; ->setComponent($this->instance['field_name'], array(
$time_type = '12'; 'type' => 'datetime_datelist',
'settings' => array(
$this->instance['widget']['type'] = 'datetime_datelist'; 'increment' => 1,
$this->instance['widget']['settings'] = array( 'date_order' => 'YMD',
'increment' => $increment, 'time_type' => '12',
'date_order' => $date_order, ),
'time_type' => $time_type, ))
); ->save();
field_update_instance($this->instance);
field_cache_clear(); field_cache_clear();
// Display creation form. // Display creation form.
......
...@@ -59,6 +59,20 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name ...@@ -59,6 +59,20 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name
$form_state['entity'] = $entity; $form_state['entity'] = $entity;
$form_state['field_name'] = $field_name; $form_state['field_name'] = $field_name;
// @todo Allow the usage of different form modes by exposing a hook and the
// UI for them.
$form_display = entity_get_render_form_display($entity, 'default');
// Let modules alter the form display.
$form_display_context = array(
'entity_type' => $entity->entityType(),
'bundle' => $entity->bundle(),
'form_mode' => 'default',
);
\Drupal::moduleHandler()->alter('entity_form_display', $form_display, $form_display_context);
$form_state['form_display'] = $form_display;
} }
/** /**
......
...@@ -70,13 +70,16 @@ function createFieldWithInstance($field_name, $type, $cardinality, $label, $inst ...@@ -70,13 +70,16 @@ function createFieldWithInstance($field_name, $type, $cardinality, $label, $inst
'description' => $label, 'description' => $label,
'weight' => mt_rand(0, 127), 'weight' => mt_rand(0, 127),
'settings' => $instance_settings, 'settings' => $instance_settings,