Skip to content
Snippets Groups Projects
ServiceSearchForm.php 8.38 KiB
Newer Older
<?php

namespace Drupal\uw_ct_service\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\path_alias\AliasManager;
use Drupal\Core\Messenger\MessengerInterface;

/**
 * Class ServiceSearchForm.
 *
 * Form for searching services.
 */
class ServiceSearchForm extends FormBase {

  /**
   * Entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The variable for current path.
   *
   * @var \Drupal\Core\Path\CurrentPathStack
   */
  protected $currentPath;

  /**
   * The variable for route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The variable for alias manager.
   *
   * @var \Drupal\path_alias\AliasManager
   */
  protected $aliasManager;

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\Core\Path\CurrentPathStack $currentPath
   *   The currentPath.
   * @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch
   *   The routeMatch.
   * @param \Drupal\path_alias\AliasManager $aliasManager
   *   The aliasManager.
   * @param Drupal\Core\Messenger\MessengerInterface $messenger
   *   The Drupal messenger.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function __construct(EntityTypeManagerInterface $entityTypeManager, CurrentPathStack $currentPath, RouteMatchInterface $routeMatch, AliasManager $aliasManager, MessengerInterface $messenger) {
    $this->entityTypeManager = $entityTypeManager;
    $this->currentPath = $currentPath;
    $this->routeMatch = $routeMatch;
    $this->aliasManager = $aliasManager;
    $this->messenger = $messenger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Instantiates this form class.
    return new static(
      $container->get('entity_type.manager'),
      $container->get('path.current'),
      $container->get('current_route_match'),
      $container->get('path_alias.manager'),
      $container->get('messenger')
    );
  }

  /**
   * Returns a unique string identifying the form.
   *
   * The returned ID should be a unique string that can be a valid PHP function
   * name, since it's used in hook implementation names such as
   * hook_form_FORM_ID_alter().
   *
   * @return string
   *   The unique string identifying the form.
   */
  public function getFormId(): string {
    return 'service_search_form';
  }

  /**
   * 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 int $tid
   *   The term id.
   * @param string $description
   *   The description for the input element.
   * @param bool $use_placeholder
   *   A flag to use a placeholder.
   * @param string $placeholder
   *   The placeholder string.
   *
   * @return array
   *   The form structure.
   */
  public function buildForm(array $form, FormStateInterface $form_state, int $tid = NULL, string $description = NULL, bool $use_placeholder = TRUE, string $placeholder = NULL): array {

    // Get the current route.
    $route = $this->routeMatch->getRouteName();

    // If the route is the all services page, set placeholder to
    // search with all services.
    if ($route == 'view.uw_view_services.services_page') {

      // Set the placeholder for all services.
      $placeholder = 'Search within all services';
    }

    // If this is a service term page, then set placeholder to
    // search within <service_name>.
    elseif ($route == 'entity.taxonomy_term.canonical') {

      // Load the term.
      $term = $this->routeMatch->getParameter('taxonomy_term');

      // Ensure that we are going to use a placeholder then set it.
      if ($use_placeholder && !$placeholder) {

        // Set the placeholder for specific catalog.
        $placeholder = 'Search within ' . $term->label();
      }
    }

    // If this is a node page, we need to set the tid in the form
    // state so that it can be used later to load name and path.
    elseif ($route == 'entity.node.canonical') {

      // If we are to use a placeholder, set it.
      if ($use_placeholder && !$placeholder) {

        // Load the term in from the tid.
        $term = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid);

        // Set the placeholder.
        $placeholder = 'Search within ' . $term->label();
      }

      // Set the tid in the form state.
      $form_state->set('tid', $tid);
    }

    // If this is any other route mainly:
    // /services/<service_name>/<new,category,audience, etc...>,
    // Then we have to get the tid from the URL, but ensure that
    // we are not in layout builder or error will be thrown.
    else {

      // Ensure that we are not on a layout builder page.
      // We do not need the tid on a layout builder page, because
      // this form can never get submitted on a layout builder page.
      if (strpos($route, 'layout_builder') !== 0) {

        // Get the current path.
        $url = $this->currentPath->getPath();

        // Break the path into parts.
        $url = explode('/', $url);

        // The tid will always be the 4th element.
        $tid = $url[3] ?? NULL;

        // One last check to ensure that we have a tid.
        // If we do not have a tid, throw a Drupal error.
        if (is_numeric($tid)) {

          // If we are to use a placeholder, set it.
          if ($use_placeholder && !$placeholder) {

            // Load the term in from the tid.
            $term = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid);

            // Set the placeholder.
            $placeholder = 'Search within ' . $term->label();
          }

          // Set the tid into the form state, so it can be used
          // in the form submit.
          $form_state->set('tid', $url[3]);
        }
      }
    }

    // The search input.
    $form['search_input'] = [
      '#type' => 'textfield',
      '#placeholder' => $use_placeholder ? $placeholder : NULL,
      '#description' => $description ?? NULL,
      '#required' => TRUE,
    ];

    // Add a submit button that handles the submission of the form.
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => '',
      '#attributes' => ['aria-label' => 'search'],
    ];

    return $form;
  }

  /**
   * 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) {

    // Get the values of the form state.
    $values = $form_state->getValues();

    // Get the tid from form state, if there is not one
    // it will be NULL.
    $tid = $form_state->get('tid');

    // This is an internal URL.
    $url = 'internal:';

    // If the tid is NULL, we are on a /catalogs page, so we
    // can just build the url from the current route.
    // If tid is not NULL, we have to determine if this is a
    // search all catalogs or specific and set things accordingly.
    if ($tid === NULL) {

      // Get the current route as the view for catalog
      // search will handle all and specific, based on URL.
      $url .= Url::fromRoute('<current>')->toString();
    }
    else {

      // If the tid is 0, this is a search all catalogs,
      // so set the URL to the /services.
      // If not set the search to /services/<service_path>.
      if ($tid == 0) {
        $url .= '/services';
      }
      else {
        $url .= $this->aliasManager->getAliasByPath('/taxonomy/term/' . $tid);
      }
    }

    // Add the search string.
    $url .= '/search?search-input=' . $values['search_input'];

    // Get a URL object.
    $url = Url::fromUri($url);

    // Set the form redirection URL.
    $form_state->setRedirectUrl($url);
  }

}