entity_agree-2.0.x-dev/src/Plugin/Field/FieldWidget/AgreementWidget.php
src/Plugin/Field/FieldWidget/AgreementWidget.php
<?php namespace Drupal\entity_agree\Plugin\Field\FieldWidget; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; use Drupal\entity_agree\Plugin\Field\FieldType\AgreementItem; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Agreement configuration field widget. * * @FieldWidget( * id = "entity_agree_default", * label = @Translation("Agreement configuration"), * field_types = { * "entity_agree" * }, * multiple_values = TRUE * ) */ class AgreementWidget extends WidgetBase { /** * Agreement handler plugin manager. * * @var \Drupal\entity_agree\AgreementHandlerPluginManager */ protected $agreementHandlerPluginManager; /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { $widget = parent::create($container, $configuration, $plugin_id, $plugin_definition); $widget->agreementHandlerPluginManager = $container->get('plugin.manager.entity_agree_handler'); return $widget; } /** * {@inheritdoc} */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $element['#id'] = Html::getId('entity-agree-widget'); $element['#type'] = 'fieldset'; $ajax = [ 'callback' => [$this, 'ajax'], 'wrapper' => $element['#id'], 'element' => $element['#field_parents'] + [$items->getName(), 'widget'], ]; $element['value'] = [ '#title' => $this->t('Agreement status'), '#type' => 'select', '#options' => [ AgreementItem::ENTITY_AGREE_STATUS_NA => $this->t('Not an agreement'), AgreementItem::ENTITY_AGREE_STATUS_ACTIVE => $this->t('Active'), AgreementItem::ENTITY_AGREE_STATUS_INACTIVE => $this->t('Inactive'), ], '#default_value' => $items[0]->value, ]; // Try to obtain the handler config from widget state. $config = $this->getHandlerConfig($element, $form_state); // If NULL, that means the handler config has not been set into widget // state (initial load), so use the value form the field item. if ($config === NULL) { $config = unserialize($items[0]->config, ['allowed_classes' => FALSE]); } // When initializing, this could be NULL, etc., so just make it an array. if (!is_array($config)) { $config = []; } $this->setHandlerConfig($element, $form_state, $config); // Build out handler plugin config forms. $plugin_ids_used = []; foreach ($config as $key => $plugin_config) { $plugin_ids_used[] = $plugin_config['id']; /** @var \Drupal\entity_agree\AgreementHandlerInterface $plugin */ $plugin = $this->agreementHandlerPluginManager->createInstance($plugin_config['id'], $plugin_config['config']); $element['config'][$key] = [ '#type' => 'fieldset', '#title' => $plugin->getCategory() . ' - ' . $plugin->getLabel(), ]; $plugin_form = []; $element['config'][$key]['config'] = $plugin->buildConfigurationForm($plugin_form, $form_state); // Removal button. $name = $element['#field_parents'] + [ $this->fieldDefinition->getName(), $key, 'remove', ]; $element['config'][$key]['remove'] = [ '#type' => 'button', '#name' => Html::getId(implode('--', $name)), '#value' => $this->t('Remove'), '#entity_agree_op' => 'remove_handler', '#entity_agree_pos' => $key, '#limit_validation_errors' => [], '#ajax' => $ajax, ]; } $element['add_handler']['plugin_id'] = [ '#title' => $this->t('Handler'), '#type' => 'select', '#options' => $this->agreementHandlerPluginManager->getPluginSelectionOptions($plugin_ids_used), ]; $element['add_handler']['button'] = [ '#type' => 'button', '#value' => $this->t('Add'), '#entity_agree_op' => 'add_handler', '#limit_validation_errors' => [], '#ajax' => $ajax, ]; $element['#element_validate'] = [[$this, 'elementValidate']]; return $element; } /** * {@inheritdoc} */ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { // Serialize the config array. $values['config'] = serialize($values['config']); unset($values['add_handler']); return $values; } /** * Validation callback. */ public function elementValidate(&$element, FormStateInterface $form_state, &$form) { $op = $form_state->getTriggeringElement()['#entity_agree_op'] ?? NULL; $value = $form_state->getValue($element['#parents']); $config = $this->getHandlerConfig($element, $form_state); switch ($op) { case 'add_handler': // Add handler. $config[] = [ 'id' => $value['add_handler']['plugin_id'], 'config' => [], ]; $form_state->setRebuild(); break; case 'remove_handler': // Remove handler. $pos = $form_state->getTriggeringElement()['#entity_agree_pos'] ?? NULL; if ($pos !== NULL && isset($config[$pos])) { unset($config[$pos]); $config = array_values($config); } $form_state->setRebuild(); break; } // Run through the plugins, validate, obtain updated config. foreach ($config as $key => $plugin_config) { /** @var \Drupal\entity_agree\AgreementHandlerInterface $plugin */ $plugin = $this->agreementHandlerPluginManager->createInstance($plugin_config['id'], []); if (!empty($element['config'][$key]['config'])) { $plugin->validateConfigurationForm($element['config'][$key]['config'], $form_state); } $config[$key]['config'] = $plugin->getConfiguration(); } // Set the changes into form state and the handler config. $value['config'] = $config; $form_state->setValue($element['#parents'], $value); $this->setHandlerConfig($element, $form_state, $config); } /** * Ajax callback. */ public function ajax(array $form, FormStateInterface $form_state) { return NestedArray::getValue($form, $form_state->getTriggeringElement()['#ajax']['element']); } /** * Get the widget's handler configuration. * * @param array $element * The widget's main form element. * @param \Drupal\Core\Form\FormStateInterface $form_state * Form state. * * @return array|null * The widget's handler configuration. */ protected function getHandlerConfig(array $element, FormStateInterface $form_state) { $field_state = static::getWidgetState($element['#field_parents'], $this->fieldDefinition->getName(), $form_state); return $field_state['config'] ?? NULL; } /** * Set the widget's handler configuration. * * @param array $element * The widget's main form element. * @param \Drupal\Core\Form\FormStateInterface $form_state * Form state. * @param array $config * The widget's handler configuration. */ protected function setHandlerConfig(array $element, FormStateInterface $form_state, array $config) { $field_state = static::getWidgetState($element['#field_parents'], $this->fieldDefinition->getName(), $form_state); $field_state['config'] = $config; static::setWidgetState($element['#field_parents'], $this->fieldDefinition->getName(), $form_state, $field_state); } }