Issue #2940201 by xjm, amateescu, benjifisher, tedbow, tim.plunkett, Berdir: hook_field_widget_form_alter() can no longer affect the whole widget for multi-value fields
parent
17a47b8e93
commit
c924020c45
|
@ -241,6 +241,19 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface
|
|||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Allow modules to alter the field multi-value widget form element.
|
||||
// This hook can also be used for single-value fields.
|
||||
$context = [
|
||||
'form' => $form,
|
||||
'widget' => $this,
|
||||
'items' => $items,
|
||||
'default' => $this->isDefaultValueWidget($form_state),
|
||||
];
|
||||
\Drupal::moduleHandler()->alter([
|
||||
'field_widget_multivalue_form',
|
||||
'field_widget_multivalue_' . $this->getPluginId() . '_form',
|
||||
], $elements, $form_state, $context);
|
||||
}
|
||||
|
||||
return $elements;
|
||||
|
|
|
@ -164,6 +164,11 @@ function hook_field_widget_info_alter(array &$info) {
|
|||
/**
|
||||
* Alter forms for field widgets provided by other modules.
|
||||
*
|
||||
* This hook can only modify individual elements within a field widget and
|
||||
* cannot alter the top level (parent element) for multi-value fields. In most
|
||||
* cases, you should use hook_field_widget_multivalue_form_alter() instead and
|
||||
* loop over the elements.
|
||||
*
|
||||
* @param $element
|
||||
* The field widget form element as constructed by
|
||||
* \Drupal\Core\Field\WidgetBaseInterface::form().
|
||||
|
@ -183,6 +188,7 @@ function hook_field_widget_info_alter(array &$info) {
|
|||
* @see \Drupal\Core\Field\WidgetBaseInterface::form()
|
||||
* @see \Drupal\Core\Field\WidgetBase::formSingleElement()
|
||||
* @see hook_field_widget_WIDGET_TYPE_form_alter()
|
||||
* @see hook_field_widget_multivalue_form_alter()
|
||||
*/
|
||||
function hook_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
|
||||
// Add a css class to widget form elements for all fields of type mytype.
|
||||
|
@ -200,6 +206,11 @@ function hook_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInte
|
|||
* specific widget form, rather than using hook_field_widget_form_alter() and
|
||||
* checking the widget type.
|
||||
*
|
||||
* This hook can only modify individual elements within a field widget and
|
||||
* cannot alter the top level (parent element) for multi-value fields. In most
|
||||
* cases, you should use hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
|
||||
* instead and loop over the elements.
|
||||
*
|
||||
* @param $element
|
||||
* The field widget form element as constructed by
|
||||
* \Drupal\Core\Field\WidgetBaseInterface::form().
|
||||
|
@ -212,6 +223,7 @@ function hook_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInte
|
|||
* @see \Drupal\Core\Field\WidgetBaseInterface::form()
|
||||
* @see \Drupal\Core\Field\WidgetBase::formSingleElement()
|
||||
* @see hook_field_widget_form_alter()
|
||||
* @see hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
|
||||
*/
|
||||
function hook_field_widget_WIDGET_TYPE_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
|
||||
// Code here will only act on widgets of type WIDGET_TYPE. For example,
|
||||
|
@ -220,6 +232,74 @@ function hook_field_widget_WIDGET_TYPE_form_alter(&$element, \Drupal\Core\Form\F
|
|||
$element['#autocomplete_route_name'] = 'mymodule.autocomplete_route';
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter forms for multi-value field widgets provided by other modules.
|
||||
*
|
||||
* To alter the individual elements within the widget, loop over
|
||||
* \Drupal\Core\Render\Element::children($elements).
|
||||
*
|
||||
* @param array $elements
|
||||
* The field widget form elements as constructed by
|
||||
* \Drupal\Core\Field\WidgetBase::formMultipleElements().
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following key-value pairs:
|
||||
* - form: The form structure to which widgets are being attached. This may be
|
||||
* a full form structure, or a sub-element of a larger form.
|
||||
* - widget: The widget plugin instance.
|
||||
* - items: The field values, as a
|
||||
* \Drupal\Core\Field\FieldItemListInterface object.
|
||||
* - default: A boolean indicating whether the form is being shown as a dummy
|
||||
* form to set default values.
|
||||
*
|
||||
* @see \Drupal\Core\Field\WidgetBaseInterface::form()
|
||||
* @see \Drupal\Core\Field\WidgetBase::formMultipleElements()
|
||||
* @see hook_field_widget_multivalue_WIDGET_TYPE_form_alter()
|
||||
*/
|
||||
function hook_field_widget_multivalue_form_alter(array &$elements, \Drupal\Core\Form\FormStateInterface $form_state, array $context) {
|
||||
// Add a css class to widget form elements for all fields of type mytype.
|
||||
$field_definition = $context['items']->getFieldDefinition();
|
||||
if ($field_definition->getType() == 'mytype') {
|
||||
// Be sure not to overwrite existing attributes.
|
||||
$elements['#attributes']['class'][] = 'myclass';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter multi-value widget forms for a widget provided by another module.
|
||||
*
|
||||
* Modules can implement hook_field_widget_multivalue_WIDGET_TYPE_form_alter() to
|
||||
* modify a specific widget form, rather than using
|
||||
* hook_field_widget_form_alter() and checking the widget type.
|
||||
*
|
||||
* To alter the individual elements within the widget, loop over
|
||||
* \Drupal\Core\Render\Element::children($elements).
|
||||
*
|
||||
* @param array $elements
|
||||
* The field widget form elements as constructed by
|
||||
* \Drupal\Core\Field\WidgetBase::formMultipleElements().
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $context
|
||||
* An associative array. See hook_field_widget_multivalue_form_alter() for
|
||||
* the structure and content of the array.
|
||||
*
|
||||
* @see \Drupal\Core\Field\WidgetBaseInterface::form()
|
||||
* @see \Drupal\Core\Field\WidgetBase::formMultipleElements()
|
||||
* @see hook_field_widget_multivalue_form_alter()
|
||||
*/
|
||||
function hook_field_widget_multivalue_WIDGET_TYPE_form_alter(array &$elements, \Drupal\Core\Form\FormStateInterface $form_state, array $context) {
|
||||
// Code here will only act on widgets of type WIDGET_TYPE. For example,
|
||||
// hook_field_widget_multivalue_mymodule_autocomplete_form_alter() will only
|
||||
// act on widgets of type 'mymodule_autocomplete'.
|
||||
// Change the autcomplete route for each autocomplete element within the
|
||||
// multivalue widget.
|
||||
foreach (Element::children($elements) as $delta => $element) {
|
||||
$elements[$delta]['#autocomplete_route_name'] = 'mymodule.autocomplete_route';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "defgroup field_widget".
|
||||
*/
|
||||
|
|
|
@ -113,6 +113,9 @@ class FormTest extends FieldTestBase {
|
|||
// Check that hook_field_widget_form_alter() does not believe this is the
|
||||
// default value form.
|
||||
$this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
|
||||
// Check that hook_field_widget_form_alter() does not believe this is the
|
||||
// default value form.
|
||||
$this->assertNoText('From hook_field_widget_multivalue_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
|
||||
|
||||
// Submit with invalid value (field-level validation).
|
||||
$edit = [
|
||||
|
@ -634,4 +637,44 @@ class FormTest extends FieldTestBase {
|
|||
$this->assertEscaped("<script>alert('a configurable field');</script>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook_field_widget_multivalue_form_alter().
|
||||
*/
|
||||
public function testFieldFormMultipleWidgetAlter() {
|
||||
$this->widgetAlterTest('hook_field_widget_multivalue_form_alter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook_field_widget_multivalue_WIDGET_TYPE_form_alter().
|
||||
*/
|
||||
public function testFieldFormMultipleWidgetTypeAlter() {
|
||||
$this->widgetAlterTest('hook_field_widget_multivalue_WIDGET_TYPE_form_alter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests widget alter hooks for a given hook name.
|
||||
*/
|
||||
protected function widgetAlterTest($hook) {
|
||||
// Set a flag in state so that the hook implementations will run.
|
||||
\Drupal::state()->set("field_test.$hook", TRUE);
|
||||
|
||||
// Create a field with fixed cardinality, configure the form to use a
|
||||
// "multiple" widget.
|
||||
$field_storage = $this->fieldStorageMultiple;
|
||||
$field_name = $field_storage['field_name'];
|
||||
$this->field['field_name'] = $field_name;
|
||||
FieldStorageConfig::create($field_storage)->save();
|
||||
FieldConfig::create($this->field)->save();
|
||||
entity_get_form_display($this->field['entity_type'], $this->field['bundle'], 'default')
|
||||
->setComponent($field_name, [
|
||||
'type' => 'test_field_widget_multiple',
|
||||
])
|
||||
->save();
|
||||
|
||||
$this->drupalGet('entity_test/add');
|
||||
$this->assertUniqueText("From $hook(): prefix on field_test_text parent element.");
|
||||
$this->assertText("From $hook(): description on field_test_text child element.");
|
||||
$this->drupalGet('entity_test/add');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
|
||||
require_once __DIR__ . '/field_test.entity.inc';
|
||||
|
@ -100,16 +101,6 @@ function field_test_entity_display_build_alter(&$output, $context) {
|
|||
* Implements hook_field_widget_form_alter().
|
||||
*/
|
||||
function field_test_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
|
||||
$field_definition = $context['items']->getFieldDefinition();
|
||||
switch ($field_definition->getName()) {
|
||||
case 'alter_test_text':
|
||||
drupal_set_message('Field size: ' . $context['widget']->getSetting('size'));
|
||||
break;
|
||||
|
||||
case 'alter_test_options':
|
||||
drupal_set_message('Widget type: ' . $context['widget']->getPluginId());
|
||||
break;
|
||||
}
|
||||
// Set a message if this is for the form displayed to set default value for
|
||||
// the field.
|
||||
if ($context['default']) {
|
||||
|
@ -117,6 +108,43 @@ function field_test_field_widget_form_alter(&$element, FormStateInterface $form_
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_multivalue_form_alter().
|
||||
*/
|
||||
function field_test_field_widget_multivalue_form_alter(array &$elements, FormStateInterface $form_state, array $context) {
|
||||
_field_test_alter_widget("hook_field_widget_multivalue_form_alter", $elements, $form_state, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_multivalue_form_alter().
|
||||
*/
|
||||
function field_test_field_widget_multivalue_text_textfield_form_alter(array &$elements, FormStateInterface $form_state, array $context) {
|
||||
_field_test_alter_widget("hook_field_widget_multivalue_WIDGET_TYPE_form_alter", $elements, $form_state, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up alterations for widget alter tests.
|
||||
*
|
||||
* @see \Drupal\field\Tests\FormTest::widgetAlterTest()
|
||||
*/
|
||||
function _field_test_alter_widget($hook, array &$elements, FormStateInterface $form_state, array $context) {
|
||||
|
||||
// Set a message if this is for the form displayed to set default value for
|
||||
// the field.
|
||||
if ($context['default']) {
|
||||
drupal_set_message("From $hook(): Default form is true.");
|
||||
}
|
||||
if (\Drupal::state()->get("field_test.$hook")) {
|
||||
$name = $context['items']->getFieldDefinition()->getName();
|
||||
if ($name === 'field_test_text') {
|
||||
$elements['#prefix'] = "From $hook(): prefix on $name parent element.";
|
||||
foreach (Element::children($elements) as $delta => $element) {
|
||||
$elements[$delta]['#description'] = "From $hook(): description on $name child element.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_query_TAG_alter() for tag 'efq_table_prefixing_test'.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue