You are here

class LayouterForm in Layouter - WYSIWYG layout templates 8

Provides multistep ajax form for an layout choice.

Hierarchy

Expanded class hierarchy of LayouterForm

1 string reference to 'LayouterForm'
layouter.routing.yml in ./layouter.routing.yml
layouter.routing.yml

File

src/Form/LayouterForm.php, line 17

Namespace

Drupal\layouter\Form
View source
class LayouterForm extends FormBase {

  /**
   * The steps count of multiform.
   *
   * @var int
   */
  protected $steps = 2;

  /**
   * All layouter templates invoked by hook_layouter_templates_info.
   *
   * @var array
   */
  protected $templates;

  /**
   * {@inheritdoc}
   */
  public function __construct() {
    $this->templates = \Drupal::moduleHandler()
      ->invokeAll('layouter_templates_info');
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'layouter_multistep_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $textarea_id = NULL) {
    $step = $form_state
      ->get('step');
    if (!$step) {
      $step = 1;
      $form_state
        ->set('step', $step);
    }
    $form['#prefix'] = '<div id="layouter-form-wrapper" class="layouter-form">';
    $form['#sufix'] = '</div>';
    $form['errors'] = [];
    $button_label = '';
    if ($step == 1) {
      $options = [];
      foreach ($this->templates as $id => $params) {
        $options[$id] = $params['title']
          ->render();
      }
      $form['data']['type'] = [
        '#title' => $this
          ->t('Choose the layout'),
        '#type' => 'radios',
        '#options' => $options,
        '#required' => TRUE,
        '#after_build' => [
          '::processLayoutTypeRadios',
        ],
      ];
      $button_label = $this
        ->t('Next');
    }
    if ($step == 2) {
      $this
        ->buildLayouterFields($form, $form_state);
      $button_label = $this
        ->t('Submit');
    }
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $button_label,
      '#name' => 'submit_button',
      '#attributes' => [
        'class' => [
          'use-ajax-submit',
        ],
      ],
      '#ajax' => [
        'callback' => '::ajaxResponse',
      ],
    ];
    $form['actions']['cancel'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Cancel'),
      '#name' => 'cancel_button',
      '#submit' => [
        '::cancelForm',
      ],
      '#limit_validation_errors' => [],
      '#attributes' => [
        'class' => [
          'use-ajax-submit',
        ],
      ],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $step = $form_state
      ->get('step');
    if ($step < $this->steps) {
      $form_state
        ->setRebuild();
      if ($step == 1) {
        $form_state
          ->set('type', $form_state
          ->getValue('type'));
      }
    }
    $step++;
    $form_state
      ->set('step', $step);
  }

  /**
   * Ajax callback prints rebuilded form.
   *
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   Returns Ajax Response.
   */
  public function ajaxResponse(array &$form, FormStateInterface $form_state) {
    if ($form_state
      ->hasAnyErrors()) {
      $form['errors']['#prefix'] = '<div class="messages messages--error">';
      $form['errors']['#suffix'] = '</div>';
      $form['errors']['#markup'] = '';
      $mess = $this
        ->messenger()
        ->messagesByType('error');
      foreach ($mess as $errors) {
        foreach ($errors as $error) {
          $form['errors']['#markup'] .= $error . '<br />';
        }
      }
      $form_state
        ->clearErrors();
    }
    $step = $form_state
      ->get('step');
    $response = new AjaxResponse();
    if ($step == $this->steps + 1 && $form_state
      ->isExecuted()) {
      $textarea_id = $form_state
        ->getBuildInfo()['args'][0];
      $content = $this
        ->buildResponseHtml($form_state);
      $command = new CloseModalDialogCommand();
      $response
        ->addCommand($command);
      $command = new InvokeCommand(NULL, 'layouterAddContent', [
        $textarea_id,
        $content,
      ]);
      $response
        ->addCommand($command);
    }
    else {
      $command = new ReplaceCommand('#layouter-form-wrapper', $form);
      $response
        ->addCommand($command);
    }
    return $response;
  }

  /**
   * Form submit handler triggered by 'cancel' button. Closes popup form.
   *
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   */
  public function cancelForm(array &$form, FormStateInterface $form_state) {

    // Delete loaded files.
    if ($form_state
      ->hasFileElement()) {
      foreach ($form_state
        ->get('fields') as $name => $params) {
        if ($params['type'] == 'image') {
          $input = $form_state
            ->getUserInput();
          if (!empty($input[$name]['fids'])) {
            File::load($input[$name]['fids'])
              ->delete();
          }
        }
      }
    }
    $response = new AjaxResponse();
    $response
      ->addCommand(new CloseModalDialogCommand());
    $form_state
      ->setResponse($response);
  }

  /**
   * Wraps each radio button item in the 'radios' set into additional container.
   *
   * After-build callback.
   *
   * @param array $element
   *   Form element.
   *
   * @return array
   *   Form element.
   */
  public function processLayoutTypeRadios(array $element) {
    foreach ($this->templates as $id => $params) {
      if (!empty($element[$id])) {
        $element[$id]['#prefix'] = '<div class="layouter-radio-wrapper ' . $id . '" title="' . $params['title'] . '">';
        $element[$id]['#suffix'] = '</div>';
      }
    }
    return $element;
  }

  /**
   * Returns the 'textarea' form item.
   *
   * @param string $name
   *   Field name.
   * @param array $params
   *   Additional parameters for field from layouter template.
   *
   * @return array
   *   Renderable array for textfield.
   */
  private function textContentHandler($name, array $params) {
    $result[$name] = [
      '#type' => 'textarea',
      '#title' => $params['title'],
      '#description' => $params['description'],
      '#rows' => 10,
      '#required' => 1,
    ];
    return $result;
  }

  /**
   * Returns the form item with actual settings, to upload image.
   *
   * @param string $name
   *   Field name.
   * @param array $params
   *   Additional parameters for field from layouter template.
   *
   * @return array
   *   Renderable array for file field.
   */
  private function imageContentHandler($name, array $params) {
    $fieldset_name = 'image_' . $name;

    // Fieldset for image fields.
    $result['#type'] = 'fieldset';
    $result['#title'] = $params['title'];

    // Prepare managed_file field.
    $allowed_extensions = [
      'png gif jpeg jpg',
    ];
    $max_upload_size_mb = (int) ini_get('upload_max_filesize');
    $max_upload_size = [
      $max_upload_size_mb * 1024 * 1024,
    ];
    $image_field_description = $this
      ->t('Files must be less than @size.', [
      '@size' => format_size($max_upload_size[0]),
    ]);
    $image_field_description .= '<br />' . $this
      ->t('Allowed file types: @extensions.', [
      '@extensions' => $allowed_extensions[0],
    ]);
    if (!empty($params['description'])) {
      $image_field_description .= '<br />' . $params['description'];
    }
    $location_scheme = \Drupal::config('layouter.settings')
      ->get('uri_scheme');

    // Add managed_file field and textfield for image alternative text.
    $result[$name] = [
      '#type' => 'managed_file',
      '#title' => $this
        ->t('Image'),
      '#field_name' => 'layouter_image',
      '#description' => $image_field_description,
      '#required' => 1,
      '#upload_location' => $location_scheme . '://layouter_images',
      '#upload_validators' => [
        'file_validate_extensions' => $allowed_extensions,
        'file_validate_size' => [
          $max_upload_size,
        ],
      ],
    ];
    $result[$name . '_alt'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Alternative text'),
    ];

    // Prepare list field with allowed image styles.
    if (\Drupal::currentUser()
      ->hasPermission('administer image styles')) {
      $url = Url::fromRoute('entity.image_style.collection')
        ->getInternalPath();
      $description = $this
        ->t('You can also') . ' <a href="/' . $url . '" target="_blank">' . $this
        ->t('add your own image style') . '</a> ' . $this
        ->t('if you need to.');
      $admin_image_style_description = $description;
    }
    else {
      $admin_image_style_description = '';
    }
    $image_styles = \Drupal::config('layouter.settings')
      ->get('image_styles');
    $image_styles_options['none'] = 'none';
    foreach ($image_styles as $k => $v) {
      if ($v != '0') {
        $image_styles_options[$k] = $v;
      }
    }

    // Add image style field to result.
    $result[$name . '_style'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Image style'),
      '#required' => TRUE,
      '#options' => $image_styles_options,
      '#description' => $admin_image_style_description,
    ];
    $fieldset[$fieldset_name] = $result;
    return $fieldset;
  }

  /**
   * Builds HTML that will be added to textarea.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   *
   * @return null
   *   Content for output.
   */
  private function buildResponseHtml(FormStateInterface $form_state) {
    $content = [
      '#theme' => $this->templates[$form_state
        ->get('type')]['theme'],
    ];
    $fields = $form_state
      ->get('fields');
    foreach ($fields as $field_name => $fiels_params) {
      switch ($fiels_params['type']) {
        case 'image':
          $image_fid = $form_state
            ->getValue($field_name)[0];
          $image = File::load($image_fid);
          $image
            ->setPermanent();
          $image
            ->save();
          $image_style = $form_state
            ->getValue($field_name . '_style');
          if ($image_style == 'none') {
            $image_content = [
              '#theme' => 'image',
            ];
          }
          else {
            $image_content = [
              '#theme' => 'image_style',
              '#style_name' => $image_style,
            ];
          }
          $image_content['#uri'] = $image
            ->getFileUri();
          $image_content['#alt'] = $form_state
            ->getValue($field_name . '_alt');
          $content['#' . $field_name] = render($image_content);
          break;
        case 'text':
          $content['#' . $field_name] = $form_state
            ->getValue($field_name);
          break;
      }
    }
    return render($content);
  }

  /**
   * Sets up and builds fields from selected layouter template.
   *
   * @param array $form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   */
  private function buildLayouterFields(array &$form, FormStateInterface $form_state) {
    $type = $form_state
      ->get('type');
    $fields = $this->templates[$type]['fields'];
    if (!is_null($fields)) {
      $form_state
        ->set('fields', $fields);
      $form['data'] = [];
      foreach ($fields as $name => $params) {
        $params['description'] = isset($params['description']) ? $params['description'] : '';
        if ($params['type'] == 'image') {
          $params['title'] = isset($params['title']) ? $params['title'] : $this
            ->t('Image settings');
          $form['data'] += $this
            ->imageContentHandler($name, $params);
        }
        if ($params['type'] == 'text') {
          $params['title'] = isset($params['title']) ? $params['title'] : $this
            ->t('Text');
          $form['data'] += $this
            ->textContentHandler($name, $params);
        }
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
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::create public static function Instantiates a new instance of this class. Overrides ContainerInjectionInterface::create 87
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.
FormBase::validateForm public function Form validation handler. Overrides FormInterface::validateForm 62
LayouterForm::$steps protected property The steps count of multiform.
LayouterForm::$templates protected property All layouter templates invoked by hook_layouter_templates_info.
LayouterForm::ajaxResponse public function Ajax callback prints rebuilded form.
LayouterForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
LayouterForm::buildLayouterFields private function Sets up and builds fields from selected layouter template.
LayouterForm::buildResponseHtml private function Builds HTML that will be added to textarea.
LayouterForm::cancelForm public function Form submit handler triggered by 'cancel' button. Closes popup form.
LayouterForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
LayouterForm::imageContentHandler private function Returns the form item with actual settings, to upload image.
LayouterForm::processLayoutTypeRadios public function Wraps each radio button item in the 'radios' set into additional container.
LayouterForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
LayouterForm::textContentHandler private function Returns the 'textarea' form item.
LayouterForm::__construct public function
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.