You are here

abstract class BlockFormBase in Context 8.4

Same name and namespace in other branches
  1. 8 src/Reaction/Blocks/Form/BlockFormBase.php \Drupal\context\Reaction\Blocks\Form\BlockFormBase
  2. 8.0 src/Reaction/Blocks/Form/BlockFormBase.php \Drupal\context\Reaction\Blocks\Form\BlockFormBase

Provides a Block Form Base for blocks reactions.

Hierarchy

Expanded class hierarchy of BlockFormBase

File

src/Reaction/Blocks/Form/BlockFormBase.php, line 33

Namespace

Drupal\context\Reaction\Blocks\Form
View source
abstract class BlockFormBase extends FormBase {
  use AjaxFormTrait;

  /**
   * The plugin being configured.
   *
   * @var \Drupal\Core\Block\BlockPluginInterface
   */
  protected $block;

  /**
   * The context entity the reaction belongs to.
   *
   * @var \Drupal\context\ContextInterface
   */
  protected $context;

  /**
   * The blocks reaction this block should be added to.
   *
   * @var \Drupal\context\Plugin\ContextReaction\Blocks
   */
  protected $reaction;

  /**
   * The block manager.
   *
   * @var \Drupal\Component\Plugin\PluginManagerInterface
   */
  protected $blockManager;

  /**
   * The Drupal context repository.
   *
   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
   */
  protected $contextRepository;

  /**
   * The handler of the available themes.
   *
   * @var \Drupal\Core\Extension\ThemeHandlerInterface
   */
  protected $themeHandler;

  /**
   * The form builder.
   *
   * @var \Drupal\Core\Form\FormBuilderInterface
   */
  protected $formBuilder;

  /**
   * The context reaction manager.
   *
   * @var \Drupal\context\ContextReactionManager
   */
  protected $contextReactionManager;

  /**
   * The Context modules context manager.
   *
   * @var \Drupal\context\ContextManager
   */
  protected $contextManager;

  /**
   * The current request.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $request;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Constructs a new VariantPluginFormBase.
   *
   * @param \Drupal\Component\Plugin\PluginManagerInterface $block_manager
   *   The block manager.
   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $contextRepository
   *   The Drupal context repository.
   * @param \Drupal\Core\Extension\ThemeHandlerInterface $themeHandler
   *   The handler of the available themes.
   * @param \Drupal\Core\Form\FormBuilderInterface $formBuilder
   *   The form builder.
   * @param \Drupal\context\ContextReactionManager $contextReactionManager
   *   The context reaction manager.
   * @param \Drupal\context\ContextManager $contextManager
   *   The Context modules context manager.
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
   *   The current request.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
   *   The module handler.
   */
  public function __construct(PluginManagerInterface $block_manager, ContextRepositoryInterface $contextRepository, ThemeHandlerInterface $themeHandler, FormBuilderInterface $formBuilder, ContextReactionManager $contextReactionManager, ContextManager $contextManager, RequestStack $requestStack, ModuleHandlerInterface $moduleHandler) {
    $this->blockManager = $block_manager;
    $this->contextRepository = $contextRepository;
    $this->themeHandler = $themeHandler;
    $this->formBuilder = $formBuilder;
    $this->contextReactionManager = $contextReactionManager;
    $this->contextManager = $contextManager;
    $this->request = $requestStack
      ->getCurrentRequest();
    $this->moduleHandler = $moduleHandler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('plugin.manager.block'), $container
      ->get('context.repository'), $container
      ->get('theme_handler'), $container
      ->get('form_builder'), $container
      ->get('plugin.manager.context_reaction'), $container
      ->get('context.manager'), $container
      ->get('request_stack'), $container
      ->get('module_handler'));
  }

  /**
   * Prepares the block plugin based on the block ID.
   *
   * @param string $block_id
   *   Either a block ID, or the plugin ID used to create a new block.
   *
   * @return \Drupal\Core\Block\BlockPluginInterface
   *   The block plugin.
   */
  protected abstract function prepareBlock($block_id);

  /**
   * Get the value to use for the submit button.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   An object that, when cast to a string, returns the translated string.
   */
  protected abstract function getSubmitValue();

  /**
   * Form constructor.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param \Drupal\context\ContextInterface $context
   *   The context the reaction belongs to.
   * @param string|null $reaction_id
   *   The ID of the blocks reaction the block should be added to.
   * @param string|null $block_id
   *   The ID of the block to show a configuration form for.
   *
   * @return array
   *   The form structure.
   */
  public function buildForm(array $form, FormStateInterface $form_state, ContextInterface $context = NULL, $reaction_id = NULL, $block_id = NULL) {
    $this->context = $context;
    $this->reaction = $this->context
      ->getReaction($reaction_id);
    $this->block = $this
      ->prepareBlock($block_id);

    // If a theme was defined in the query use this theme for the block
    // otherwise use the default theme.
    $theme = $this
      ->getRequest()->query
      ->get('theme', $this->themeHandler
      ->getDefault());

    // Some blocks require the theme name in the form state like Site Branding.
    $form_state
      ->set('block_theme', $theme);

    // Some blocks require contexts, set a temporary value with gathered
    // contextual values.
    $form_state
      ->setTemporaryValue('gathered_contexts', $this->contextRepository
      ->getAvailableContexts());
    $configuration = $this->block
      ->getConfiguration();
    $form['#tree'] = TRUE;
    $form['settings'] = $this->block
      ->buildConfigurationForm([], $form_state);
    $form['settings']['id'] = [
      '#type' => 'value',
      '#value' => $this->block
        ->getPluginId(),
    ];
    $form['custom_id'] = [
      '#type' => 'machine_name',
      '#maxlength' => 64,
      '#description' => $this
        ->t('A unique name for this block instance. Must be alpha-numeric and underscore separated.'),
      '#default_value' => isset($configuration['custom_id']) ? $configuration['custom_id'] : preg_replace("/\\W+/", "_", $this->block
        ->getPluginId()),
      '#machine_name' => [
        'source' => [
          'settings',
          'label',
        ],
      ],
      '#required' => TRUE,
    ];
    $form['region'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Region'),
      '#description' => $this
        ->t('Select the region where this block should be displayed.'),
      '#options' => $this
        ->getThemeRegionOptions($theme),
      '#default_value' => isset($configuration['region']) ? $configuration['region'] : '',
    ];
    $form['unique'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Unique'),
      '#description' => $this
        ->t('Check if the block should be uniquely placed. This means that the block can not be overridden by other blocks of the same type in the selected region. Most often you want this checked if a block unintentionally contains the same content as another block on the same page.'),
      '#default_value' => isset($configuration['unique']) ? $configuration['unique'] : FALSE,
    ];
    $form['theme'] = [
      '#type' => 'value',
      '#value' => $theme,
    ];
    $form['css_class'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Block Class'),
      '#default_value' => isset($configuration['css_class']) ? $configuration['css_class'] : '',
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this
        ->getSubmitValue(),
      '#button_type' => 'primary',
      '#ajax' => [
        'callback' => '::submitFormAjax',
      ],
    ];

    // Remove ajax from submit, if this is not ajax request.
    if (!$this->request
      ->isXmlHttpRequest()) {
      unset($form['actions']['submit']['#ajax']);
    }

    // Disable cache on form to prevent ajax forms from failing.
    $form_state
      ->disableCache();

    // Call hook_form_alter and hook_form_block_form_alter so form alter hooks
    // changing the block_form will also be called here for e.g. adding
    // third party settings.
    $dummy_form_id = 'block_form';
    $this->moduleHandler
      ->alter([
      'form',
      'form_block_form',
    ], $form, $form_state, $dummy_form_id);
    return $form;
  }

  /**
   * Form validation handler.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $settings = (new FormState())
      ->setValues($form_state
      ->getValue('settings'));

    // Call the plugin validate handler.
    $this->block
      ->validateConfigurationForm($form['settings'], $settings);

    // Update the original form values, including errors.
    $form_state
      ->setValue('settings', $settings
      ->getValues());
    foreach ($settings
      ->getErrors() as $name => $error) {
      $form_state
        ->setErrorByName($name, $error);
    }
  }

  /**
   * Form submission handler.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $settings = SubformState::createForSubform($form['settings'], $form, $form_state);

    // Call the plugin submit handler.
    $this->block
      ->submitConfigurationForm($form, $settings);

    // Update the original form values.
    $form_state
      ->setValue('settings', $settings
      ->getValues());

    // Add available contexts if this is a context aware block.
    if ($this->block instanceof ContextAwarePluginInterface) {
      $this->block
        ->setContextMapping($form_state
        ->getValue([
        'settings',
        'context_mapping',
      ], []));
    }
    $configuration = array_merge($this->block
      ->getConfiguration(), [
      'custom_id' => $form_state
        ->getValue('custom_id'),
      'region' => $form_state
        ->getValue('region'),
      'theme' => $form_state
        ->getValue('theme'),
      'css_class' => $form_state
        ->getValue('css_class'),
      'unique' => $form_state
        ->getValue('unique'),
      'context_id' => $this->context
        ->id(),
      'third_party_settings' => $form_state
        ->getValue('third_party_settings', []),
    ]);

    // Add/Update the block.
    if (!isset($configuration['uuid'])) {
      $this->reaction
        ->addBlock($configuration);
    }
    else {
      $this->reaction
        ->updateBlock($configuration['uuid'], $configuration);
    }
    $this->context
      ->save();
    $form_state
      ->setRedirectUrl(Url::fromRoute('entity.context.edit_form', [
      'context' => $this->context
        ->id(),
    ]));
  }

  /**
   * Handle when the form is submitted trough AJAX.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   An AJAX response.
   */
  public function submitFormAjax(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    if ($form_state
      ->getErrors()) {
      $messages = StatusMessages::renderMessages(NULL);
      $output[] = $messages;
      $output[] = $form;
      $form_class = '.' . str_replace('_', '-', $form_state
        ->getFormObject()
        ->getFormId());

      // Remove any previously added error messages.
      $response
        ->addCommand(new RemoveCommand('#drupal-modal .messages--error'));

      // Replace old form with new one and with error message.
      $response
        ->addCommand(new ReplaceCommand($form_class, $output));
    }
    else {
      $form = $this->contextManager
        ->getForm($this->context, 'edit');
      $response
        ->addCommand(new CloseModalDialogCommand());
      $response
        ->addCommand(new ReplaceCommand('#context-reactions', $form['reactions']));
    }
    return $response;
  }

  /**
   * Get a list of regions for the select list.
   *
   * @param string $theme
   *   The theme to get a list of regions for.
   * @param string $show
   *   What type of regions that should be returned, defaults to all regions.
   *
   * @return array
   *   The regions of the theme.
   */
  protected function getThemeRegionOptions($theme, $show = BlockRepositoryInterface::REGIONS_ALL) {
    $regions = system_region_list($theme, $show);
    foreach ($regions as $region => $title) {
      $regions[$region] = $title;
    }
    return $regions;
  }

  /**
   * Returns a block entity based on the configured values in context.
   *
   * Method that can be used by modules depending on
   * hook_form_block_form_alter(). Since that form is an entity form, the
   * getEntity method is available. Since hook_form_block_form_alter is also
   * called in this form, this will break modules depending on this method.
   *
   * @return \Drupal\block\BlockInterface
   *   A block entity.
   */
  public function getEntity() {
    return Block::create($this->block
      ->getConfiguration() + [
      'plugin' => $this->block
        ->getPluginId(),
    ]);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AjaxFormTrait::getAjaxAttributes public static function Gets attributes for use with an AJAX modal.
AjaxFormTrait::getAjaxButtonAttributes public static function Gets attributes for use with an add button AJAX modal.
BlockFormBase::$block protected property The plugin being configured.
BlockFormBase::$blockManager protected property The block manager.
BlockFormBase::$context protected property The context entity the reaction belongs to.
BlockFormBase::$contextManager protected property The Context modules context manager.
BlockFormBase::$contextReactionManager protected property The context reaction manager.
BlockFormBase::$contextRepository protected property The Drupal context repository.
BlockFormBase::$formBuilder protected property The form builder.
BlockFormBase::$moduleHandler protected property The module handler.
BlockFormBase::$reaction protected property The blocks reaction this block should be added to.
BlockFormBase::$request protected property The current request.
BlockFormBase::$themeHandler protected property The handler of the available themes.
BlockFormBase::buildForm public function Form constructor. Overrides FormInterface::buildForm
BlockFormBase::create public static function Instantiates a new instance of this class. Overrides FormBase::create
BlockFormBase::getEntity public function Returns a block entity based on the configured values in context.
BlockFormBase::getSubmitValue abstract protected function Get the value to use for the submit button. 2
BlockFormBase::getThemeRegionOptions protected function Get a list of regions for the select list.
BlockFormBase::prepareBlock abstract protected function Prepares the block plugin based on the block ID. 2
BlockFormBase::submitForm public function Form submission handler. Overrides FormInterface::submitForm
BlockFormBase::submitFormAjax public function Handle when the form is submitted trough AJAX.
BlockFormBase::validateForm public function Form validation handler. Overrides FormBase::validateForm
BlockFormBase::__construct public function Constructs a new VariantPluginFormBase.
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FormBase::$configFactory protected property The config factory. 1
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 1
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
FormInterface::getFormId public function Returns a unique string identifying the form. 236
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.