View source  
  <?php
namespace Drupal\context_ui\Form;
use Drupal\Core\Form\FormState;
use Drupal\context\ContextManager;
use Drupal\context\Entity\Context;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class ContextFormBase extends EntityForm {
  
  protected $entity;
  
  protected $contextManager;
  
  protected $contextRepository;
  
  function __construct(ContextManager $contextManager, ContextRepositoryInterface $contextRepository) {
    $this->contextManager = $contextManager;
    $this->contextRepository = $contextRepository;
  }
  
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('context.manager'), $container
      ->get('context.repository'));
  }
  
  public function form(array $form, FormStateInterface $formState) {
    $form['general'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('General details'),
    ];
    $form['general']['label'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Label'),
      '#default_value' => $this->entity
        ->getLabel(),
      '#required' => TRUE,
      '#description' => $this
        ->t('Enter label for this context.'),
    ];
    $form['general']['name'] = [
      '#type' => 'machine_name',
      '#title' => $this
        ->t('Machine name'),
      '#default_value' => $this->entity
        ->getName(),
      '#machine_name' => [
        'source' => [
          'general',
          'label',
        ],
        'exists' => [
          $this,
          'contextExists',
        ],
      ],
    ];
    $form['general']['group'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Group'),
      '#default_value' => $this->entity
        ->getGroup(),
      '#description' => $this
        ->t('Enter name of the group this context should belong to.'),
      '#autocomplete_route_name' => 'context.groups.autocomplete',
    ];
    $form['general']['description'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Description'),
      '#default_value' => $this->entity
        ->getDescription(),
      '#description' => $this
        ->t('Enter a description for this context definition.'),
    ];
    return $form;
  }
  
  public function validateForm(array &$form, FormStateInterface $form_state) {
    if ($form_state
      ->hasValue('reactions')) {
      $this
        ->validateReactions($form, $form_state);
    }
  }
  
  public function submitForm(array &$form, FormStateInterface $form_state) {
    
    if ($form_state
      ->hasValue('require_all_conditions')) {
      $this->entity
        ->setRequireAllConditions($form_state
        ->getValue('require_all_conditions'));
    }
    if ($form_state
      ->hasValue('conditions')) {
      $this
        ->handleConditions($form, $form_state);
    }
    if ($form_state
      ->hasValue('reactions')) {
      $this
        ->handleReactions($form, $form_state);
    }
    
    if ($form_state
      ->hasValue('group') && empty($form_state
      ->getValue('group'))) {
      $form_state
        ->setValue('group', Context::CONTEXT_GROUP_NONE);
    }
    
    parent::submitForm($form, $form_state);
  }
  
  private function handleConditions(array &$form, FormStateInterface $form_state) {
    $conditions = $form_state
      ->getValue('conditions', []);
    
    foreach ($conditions as $condition_id => $configuration) {
      $condition = $this->entity
        ->getCondition($condition_id);
      $condition_values = (new FormState())
        ->setValues($configuration);
      $condition
        ->submitConfigurationForm($form, $condition_values);
      
      if ($condition instanceof ContextAwarePluginInterface) {
        $condition
          ->setContextMapping($condition_values
          ->getValue('context_mapping', []));
      }
    }
  }
  
  private function handleReactions(array &$form, FormStateInterface $form_state) {
    $reactions = $form_state
      ->getValue('reactions', []);
    
    foreach ($reactions as $reaction_id => $configuration) {
      $reaction = $this->entity
        ->getReaction($reaction_id);
      $reaction_values = (new FormState())
        ->setValues($configuration);
      $reaction
        ->submitConfigurationForm($form, $reaction_values);
    }
  }
  
  private function validateReactions(array &$form, FormStateInterface $form_state) {
    $reactions = $form_state
      ->getValue('reactions', []);
    
    foreach ($reactions as $reaction_id => $configuration) {
      $reaction = $this->entity
        ->getReaction($reaction_id);
      $reaction_values = (new FormState())
        ->setValues($configuration);
      $reaction
        ->validateConfigurationForm($form, $reaction_values);
      if ($reaction_values
        ->hasAnyErrors()) {
        
        foreach ($reaction_values
          ->getErrors() as $element => $error) {
          $form_state
            ->setErrorByName("reactions][{$reaction_id}][{$element}", $error);
        }
      }
    }
  }
  
  public function contextExists($name) {
    return $this->contextManager
      ->contextExists($name);
  }
}