Apply the field states to a form element.

Due to various form elements having different array structure, the states array has to be put in a different spot for different widgets. Most common locations are `value` and `target_id` or for multiple value forms, on the wrapper.

Parameters

array $element: The field widget form elements as constructed by \Drupal\Core\Field\WidgetBase::formMultipleElements().

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form.

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 also

hook_field_widget_multivalue_form_alter().

File

src/FieldStateManager.php, line 81

Class

FieldStateManager
Manages field state plugins.

Namespace

Drupal\field_states_ui

Code

public function apply(&$element, FormStateInterface $form_state, $context) {
    
    /** @var \Drupal\Core\Field\PluginSettingsInterface $plugin */
    $plugin = $context['widget'];
    // Check that it is enabled for this field.
    if (empty($plugin->getThirdPartySettings('field_states_ui')['field_states'])) {
        return;
    }
    $states = $plugin->getThirdPartySettings('field_states_ui')['field_states'];
    
    /** @var \Drupal\Core\Field\FieldItemListInterface $field_item */
    $field_item = $context['items'];
    $field_definition = $field_item->getFieldDefinition();
    $type = $field_definition->getType();
    $plugin_id = $plugin->getPluginId();
    // Handle the type of field appropriately.
    switch ($type) {
        case 'entity_reference':
            switch ($plugin_id) {
                case 'chosen_select':
                case 'options_select':
                case 'options_buttons':
                case 'media_library_widget':
                    $target =& $element;
                    break;
                case 'entity_browser_entity_reference':
                    if (!isset($element[0])) {
                        $target =& $element;
                    }
                    else {
                        $target =& $element[0];
                    }
                    break;
                case 'entity_reference_autocomplete':
                case 'entity_reference_autocomplete_tags':
                    if (!isset($element[0])) {
                        $target =& $element['target_id'];
                    }
                    else {
                        $target =& $element[0]['target_id'];
                    }
                    break;
                default:
                    // Log a notice so that user(s) can report unrecognized field
                    // plugin_id.
                    $this->logger
                        ->notice(t('Field type: "@type" with plugin_id "@id" was unrecognized. Please report on the @link. For quickest resolution, please include what module it comes from.', [
                        '@type' => $type,
                        '@id' => $plugin_id,
                        '@link' => Link::fromTextAndUrl(t('Field States UI Issue Queue'), Url::fromUri('https://www.drupal.org/project/issues/field_states_ui'))->toString(),
                    ]));
                    if (isset($element[0]['target_id'])) {
                        $target =& $element[0]['target_id'];
                    }
                    elseif (isset($element['target_id'])) {
                        $target =& $element['target_id'];
                    }
                    else {
                        $target =& $element;
                    }
                    break;
            }
            break;
        case 'boolean':
            switch ($plugin_id) {
                case 'options_buttons':
                    $target =& $element[0];
                    break;
                case 'boolean_checkbox':
                    $target =& $element['value'];
                    break;
                default:
                    $target =& $element[0]['value'];
                    break;
            }
            break;
        case 'address_country':
        case 'decimal':
        case 'float':
        case 'integer':
        case 'string':
        case 'string_long':
            $target =& $element[0]['value'];
            break;
        case 'text_with_summary':
        case 'text_long':
        case 'list_float':
        case 'list_integer':
        case 'list_string':
        case 'link':
        case 'entity_reference_revisions':
        case 'datetime':
        case 'color_field_type':
        case 'address_zone':
        case 'address':
            if (!isset($element[0])) {
                $target =& $element;
            }
            else {
                $target =& $element[0];
            }
            break;
        case 'name':
            $target =& $element[0];
            $container = TRUE;
            break;
        default:
            // Log a notice so that user(s) can report unrecognized field types.
            $this->logger
                ->notice(t('Field type: "@type" was unrecognized. Please report on the @link. For quickest resolution, please include the element details: @details', [
                '@type' => $type,
                '@link' => Link::fromTextAndUrl(t('Field States UI Issue Queue'), Url::fromUri('https://www.drupal.org/project/issues/field_states_ui'))->toString(),
                '@details' => var_export(array_keys($element[0]), TRUE),
            ]));
            $target =& $element[0];
            $container = TRUE;
            break;
    }
    if (!isset($target['#field_parents'])) {
        $parents = [];
        $this->logger
            ->notice(t('#field_parents key not found. This will may cause problems. If so, please report on the @link. For quickest resolution, please include the element details: @details', [
            '@link' => Link::fromTextAndUrl(t('Field States UI Issue Queue'), Url::fromUri('https://www.drupal.org/project/issues/field_states_ui'))->toString(),
            '@details' => var_export(array_keys($element[0]), TRUE),
        ]));
    }
    else {
        $parents = $target['#field_parents'];
    }
    if (isset($element['#cardinality_multiple']) && $element['#cardinality_multiple']) {
        // Multiple widget field. Put states on the wrapper.
        $element = [
            'element' => $element,
            '#type' => 'container',
            '#states' => $this->getStates($states, $form_state, $context, $element, $parents),
        ];
    }
    elseif (isset($container)) {
        // Add a container element and set states on that to ensure it works.
        // This increases divitis which is already common on Drupal forms so
        // it is better to handle the element properly. There are elements that it
        // does make sense to do this to (ie name) but avoid if possible.
        $element = [
            'element' => $element,
            '#type' => 'container',
            '#states' => $this->getStates($states, $form_state, $context, $element, $parents),
        ];
    }
    else {
        $target['#states'] = $this->getStates($states, $form_state, $context, $element, $parents);
    }
}