ContextConfigure.php

Same filename in other branches
  1. 8.x-3.x src/Form/ContextConfigure.php

Namespace

Drupal\ctools\Form

File

src/Form/ContextConfigure.php

View source
<?php

namespace Drupal\ctools\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextInterface;
use Drupal\Core\Plugin\Context\EntityContextDefinition;
use Drupal\Core\TempStore\SharedTempStoreFactory;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Configure Context Form.
 */
abstract class ContextConfigure extends FormBase {
    
    /**
     * Tempstore Factory.
     *
     * @var \Drupal\Core\TempStore\SharedTempStoreFactory
     */
    protected $tempstore;
    
    /**
     * Entity Type Manager.
     *
     * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     */
    protected $entityTypeManager;
    
    /**
     * The Tempstore ID.
     *
     * @var string
     */
    protected $tempstore_id;
    
    /**
     * The form machine name.
     *
     * @var string
     */
    protected $machine_name;
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container) {
        return new static($container->get('tempstore.shared'), $container->get('entity_type.manager'));
    }
    
    /**
     * Configure Context Form constructor.
     *
     * @param \Drupal\Core\TempStore\SharedTempStoreFactory $tempstore
     *   The tempstore factory.
     * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
     *   The entity type manager.
     */
    public function __construct(SharedTempStoreFactory $tempstore, EntityTypeManagerInterface $entity_type_manager) {
        $this->tempstore = $tempstore;
        $this->entityTypeManager = $entity_type_manager;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getFormId() {
        return 'ctools_context_configure';
    }
    
    /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state, $context_id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
        $this->tempstore_id = $tempstore_id;
        $this->machine_name = $machine_name;
        $cached_values = $this->tempstore
            ->get($this->tempstore_id)
            ->get($this->machine_name);
        $contexts = $this->getContexts($cached_values);
        $edit = FALSE;
        if (!empty($contexts[$context_id])) {
            $context = $contexts[$context_id];
            $machine_name = $context_id;
            $edit = TRUE;
        }
        else {
            if (strpos($context_id, 'entity:') === 0) {
                $context_definition = new EntityContextDefinition($context_id);
            }
            else {
                $context_definition = new ContextDefinition($context_id);
            }
            $context = new Context($context_definition);
            $machine_name = '';
        }
        $label = $context->getContextDefinition()
            ->getLabel();
        $description = $context->getContextDefinition()
            ->getDescription();
        $data_type = $context->getContextDefinition()
            ->getDataType();
        $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
        $form['context_id'] = [
            '#type' => 'value',
            '#value' => $context_id,
        ];
        $form['label'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Label'),
            '#default_value' => $label,
            '#required' => TRUE,
        ];
        $form['machine_name'] = [
            '#type' => 'machine_name',
            '#title' => $this->t('Machine Name'),
            '#default_value' => $machine_name,
            '#required' => TRUE,
            '#maxlength' => 128,
            '#machine_name' => [
                'source' => [
                    'label',
                ],
                'exists' => [
                    $this,
                    'contextExists',
                ],
            ],
            '#disabled' => $this->disableMachineName($cached_values, $machine_name),
        ];
        $form['description'] = [
            '#type' => 'textarea',
            '#title' => $this->t('Description'),
            '#default_value' => $description,
        ];
        if (strpos($data_type, 'entity:') === 0) {
            [
                ,
                $entity_type,
            ] = explode(':', $data_type);
            
            /** @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter $entity */
            $entity = $edit ? $context->getContextValue() : NULL;
            $form['context_value'] = [
                '#type' => 'entity_autocomplete',
                '#required' => TRUE,
                '#target_type' => $entity_type,
                '#default_value' => $entity,
                '#title' => $this->t('Select entity'),
            ];
        }
        else {
            $value = $context->getContextData()
                ->getValue();
            $form['context_value'] = [
                '#title' => $this->t('Set a context value'),
                '#type' => 'textfield',
                '#required' => TRUE,
                '#default_value' => $value,
            ];
        }
        $form['submit'] = [
            '#type' => 'submit',
            '#value' => $this->t('Save'),
            '#ajax' => [
                'callback' => [
                    $this,
                    'ajaxSave',
                ],
            ],
        ];
        return $form;
    }
    
    /**
     * {@inheritdoc}
     */
    public function validateForm(array &$form, FormStateInterface $form_state) {
        // If these are not equal, then we're adding a new context and should not override an existing context.
        if ($form_state->getValue('machine_name') != $form_state->getValue('context_id')) {
            $machine_name = $form_state->getValue('machine_name');
            $cached_values = $this->tempstore
                ->get($this->tempstore_id)
                ->get($this->machine_name);
            if (!empty($this->getContexts($cached_values)[$machine_name])) {
                $form_state->setError($form['machine_name'], $this->t('That machine name is in use by another context definition.'));
            }
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function submitForm(array &$form, FormStateInterface $form_state) {
        $cached_values = $this->tempstore
            ->get($this->tempstore_id)
            ->get($this->machine_name);
        $contexts = $this->getContexts($cached_values);
        if ($form_state->getValue('machine_name') != $form_state->getValue('context_id')) {
            $data_type = $form_state->getValue('context_id');
            if (strpos($data_type, 'entity:') === 0) {
                $context_definition = new EntityContextDefinition($data_type, $form_state->getValue('label'), TRUE, FALSE, $form_state->getValue('description'));
            }
            else {
                $context_definition = new ContextDefinition($data_type, $form_state->getValue('label'), TRUE, FALSE, $form_state->getValue('description'));
            }
        }
        else {
            $context = $contexts[$form_state->getValue('machine_name')];
            $context_definition = $context->getContextDefinition();
            $context_definition->setLabel($form_state->getValue('label'));
            $context_definition->setDescription($form_state->getValue('description'));
        }
        // We're dealing with an entity and should make sure it's loaded.
        if (strpos($context_definition->getDataType(), 'entity:') === 0) {
            [
                ,
                $entity_type,
            ] = explode(':', $context_definition->getDataType());
            if (is_numeric($form_state->getValue('context_value'))) {
                $value = $this->entityTypeManager
                    ->getStorage($entity_type)
                    ->load($form_state->getValue('context_value'));
            }
        }
        else {
            $value = $form_state->getValue('context_value');
        }
        $context = new Context($context_definition, $value);
        $cached_values = $this->addContext($cached_values, $form_state->getValue('machine_name'), $context);
        $this->tempstore
            ->get($this->tempstore_id)
            ->set($this->machine_name, $cached_values);
        [
            $route_name,
            $route_parameters,
        ] = $this->getParentRouteInfo($cached_values);
        $form_state->setRedirect($route_name, $route_parameters);
    }
    
    /**
     * Ajax Save Method.
     *
     * @param array $form
     *   Drupal Form.
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     *   Form State.
     *
     * @return \Drupal\Core\Ajax\AjaxResponse
     *   The ajax data in the response.
     */
    public function ajaxSave(array &$form, FormStateInterface $form_state) {
        $response = new AjaxResponse();
        $cached_values = $this->tempstore
            ->get($this->tempstore_id)
            ->get($this->machine_name);
        [
            $route_name,
            $route_parameters,
        ] = $this->getParentRouteInfo($cached_values);
        $url = new Url($route_name, $route_parameters);
        $response->addCommand(new RedirectCommand($url->toString()));
        $response->addCommand(new CloseModalDialogCommand());
        return $response;
    }
    
    /**
     * Document the route name and parameters for redirect after submission.
     *
     * @param $cached_values
     *
     * @return array
     *   In the format of
     *   return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name]];
     */
    protected abstract function getParentRouteInfo($cached_values);
    
    /**
     * Custom logic for retrieving the contexts array from cached_values.
     *
     * @param $cached_values
     *
     * @return \Drupal\Core\Plugin\Context\ContextInterface[]
     */
    protected abstract function getContexts($cached_values);
    
    /**
     * Custom logic for adding a context to the cached_values contexts array.
     *
     * @param array $cached_values
     *   The cached_values currently in use.
     * @param string $context_id
     *   The context identifier.
     * @param \Drupal\Core\Plugin\Context\ContextInterface $context
     *   The context to add or update within the cached values.
     *
     * @return mixed
     *   Return the $cached_values
     */
    protected abstract function addContext($cached_values, $context_id, ContextInterface $context);
    
    /**
     * Custom "exists" logic for the context to be created.
     *
     * @param string $value
     *   The name of the context.
     * @param $element
     *   The machine_name element
     * @param \Drupal\Core\Form\FormStateInterface $form_state
     *   The form state.
     *
     * @return bool
     *   Return true if a context of this name exists.
     */
    public abstract function contextExists($value, $element, $form_state);
    
    /**
     * Determines if the machine_name should be disabled.
     *
     * @param $cached_values
     *
     * @return bool
     */
    protected abstract function disableMachineName($cached_values, $machine_name);

}

Classes

Title Deprecated Summary
ContextConfigure Configure Context Form.