custom_search-8.x-1.x-dev/src/Form/CustomSearchBlockForm.php

src/Form/CustomSearchBlockForm.php
<?php

namespace Drupal\custom_search\Form;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\search\SearchPageRepositoryInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Utility\Html;

/**
 * Builds the search form for the search block.
 */
class CustomSearchBlockForm extends FormBase {

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

  /**
   * The search page repository.
   *
   * @var \Drupal\search\SearchPageRepositoryInterface
   */
  protected $searchPageRepository;

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

  /**
   * The entity repository.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected $entityRepository;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

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

  /**
   * Constructs a new SearchBlockForm.
   *
   * @param \Drupal\search\SearchPageRepositoryInterface $search_page_repository
   *   The search page repository.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The Module handler object.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
   *   The entity repository.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\Core\Path\CurrentPathStack $current_path
   *   The current path.
   */
  public function __construct(
    SearchPageRepositoryInterface $search_page_repository,
    ModuleHandlerInterface $module_handler,
    EntityTypeManagerInterface $entity_type_manager,
    EntityRepositoryInterface $entity_repository,
    LanguageManagerInterface $language_manager,
    CurrentPathStack $current_path,
  ) {
    $this->searchPageRepository = $search_page_repository;
    $this->moduleHandler = $module_handler;
    $this->entityTypeManager = $entity_type_manager;
    $this->entityRepository = $entity_repository;
    $this->languageManager = $language_manager;
    $this->currentPath = $current_path;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('search.search_page_repository'),
      $container->get('module_handler'),
      $container->get('entity_type.manager'),
      $container->get('entity.repository'),
      $container->get('language_manager'),
      $container->get('path.current'),
    );
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = func_get_arg(2);
    $form['#method'] = 'post';

    // Popup.
    $form['popup'] = [
      '#type'       => 'fieldset',
      '#weight'     => 1 + $config['search_box']['weight'],
      '#attributes' => ['class' => ['custom_search-popup']],
    ];

    // Search box.
    $form['keys'] = [
      '#type'           => 'search',
      '#title'          => Html::escape($config['search_box']['label']),
      '#title_display'  => $config['search_box']['label_visibility'] ? 'before' : 'invisible',
      '#size'           => $config['search_box']['size'],
      '#maxlength'      => $config['search_box']['max_length'],
      '#default_value'  => '',
      '#placeholder'    => ['title' => Html::escape($config['search_box']['placeholder'])],
      '#attributes'     => [
        'title' => Html::escape($config['search_box']['title']),
        'class' => ['custom_search-keys'],
      ],
      '#weight'         => $config['search_box']['weight'],
    ];

    // Content.
    $toptions = [];
    $types = array_keys(array_filter($config['content']['types']));
    if (count($types)) {
      $names = node_type_get_names();
      if (count($types) > 1 || $config['content']['any']['force']) {
        $toptions['c-all'] = $config['content']['any']['text'];
      }
      foreach ($types as $type) {
        $toptions['c-' . $type] = $names[$type];
      }
    }
    $options = [];
    // Other searches.
    $others = !empty($config['content']['other']) ? array_keys(array_filter($config['content']['other'])) : [];
    // If content types and other searches are combined, make an optgroup.
    if (count($others) && count($toptions) && $config['content']['selector']['type'] == 'select') {
      $search_page = $this->entityTypeManager->getStorage('search_page')->load($config['content']['page']);
      $options[Html::escape($search_page->label())] = $toptions;
    }
    else {
      $options = $toptions;
    }
    if (count($others)) {
      $other_pages = $this->entityTypeManager->getStorage('search_page')->loadMultiple($others);
      foreach ($others as $other) {
        $options['o-' . Html::escape($other_pages[$other]->id())] = Html::escape($other_pages[$other]->label());
      }
    }
    if (count($options)) {
      $selector_type = $config['content']['selector']['type'];
      if ($selector_type == 'selectmultiple') {
        $selector_type = 'select';
        $multiple = TRUE;
      }
      else {
        $multiple = FALSE;
      }
      $form['types'] = [
        '#type'           => $selector_type,
        '#multiple'       => $multiple,
        '#title'          => Html::escape($config['content']['selector']['label']),
        '#title_display'  => $config['content']['selector']['label_visibility'] ? 'before' : 'invisible',
        '#options'        => $options,
        '#default_value'  => ($selector_type == 'checkboxes') ? ['c-all'] : 'c-all',
        '#attributes'     => ['class' => ['custom-search-selector', 'custom-search-types']],
        '#weight'         => $config['content']['weight'],
        '#validated'      => TRUE,
      ];
      // If there's only one type, hide the selector.
      if (count($others) + count($types) == 1 && !$config['content']['any']['force']) {
        $form['custom_search_types']['#type'] = 'hidden';
        $form['custom_search_types']['#default_value'] = key(array_slice($options, count($options) - 1));
      }
      elseif ($config['content']['region'] == 'popup') {
        $form['popup']['types'] = $form['types'];
        unset($form['types']);
      }

    }

    // Taxonomy.
    $vocabularies = $this->entityTypeManager->getStorage('taxonomy_vocabulary')->loadMultiple();
    if (count($config['taxonomy']) > 0) {
      $taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term');

      foreach ($vocabularies as $voc) {
        $vid = $voc->id();
        if (empty($config['taxonomy'][$vid]['type']) || $config['taxonomy'][$vid]['type'] == 'disabled') {
          continue;
        }
        $options = [];
        $options['c-all'] = $config['taxonomy'][$vid]['all_text'];
        $vocabulary_depth = (!$config['taxonomy'][$vid]['depth']) ? NULL : $config['taxonomy'][$vid]['depth'];
        $terms = $taxonomy_term_storage->loadTree($vid, 0, $vocabulary_depth, TRUE);
        foreach ($terms as $term) {
          $termName = Html::escape($this->entityRepository->getTranslationFromContext($term)->label());
          $options['c-' . $term->id()] = (mb_substr($config['taxonomy'][$vid]['type'], 0, 6) == 'select') ? str_repeat('-', $term->depth) . ' ' . $termName : $termName;
        }
        $selector_type = $config['taxonomy'][$vid]['type'];
        if ($selector_type == 'selectmultiple') {
          $selector_type = 'select';
          $multiple = TRUE;
        }
        else {
          $multiple = FALSE;
        }
        $form['vocabulary_' . $vid] = [
          '#type'           => $selector_type,
          '#multiple'       => $multiple,
          '#title'          => Html::escape($config['taxonomy'][$vid]['label']),
          '#title_display'  => $config['taxonomy'][$vid]['label_visibility'] ? 'before' : 'invisible',
          '#options'        => $options,
          '#default_value'  => ($selector_type == 'checkboxes') ? ['c-all'] : 'c-all',
          '#attributes'     => ['class' => ['custom-search-selector', 'custom-search-vocabulary']],
          '#weight'         => $config['taxonomy'][$vid]['weight'],
        ];

        if ($config['taxonomy'][$vid]['region'] == 'popup') {
          $form['popup']['vocabulary_' . $vid] = $form['vocabulary_' . $vid];
          unset($form['vocabulary_' . $vid]);
        }
      }
    }

    // Languages.
    $options = [];
    $languages = array_keys(array_filter($config['languages']['languages']));
    if (count($languages)) {
      if (count($languages) > 1 || $config['languages']['any']['force']) {
        $options['c-all'] = $config['languages']['any']['text'];
      }
      $current_language = $this->languageManager->getCurrentLanguage();
      $current_language_id = $current_language->getId();
      foreach ($languages as $language) {
        switch ($language) {
          case 'current':
            $options['c-' . $language] = t('- Current language (@current) -', ['@current' => $current_language->getName()]);
            break;

          case Language::LANGCODE_NOT_SPECIFIED:
            $options['c-' . $language] = t('- Not specified -');
            break;

          case Language::LANGCODE_NOT_APPLICABLE:
            $options['c-' . $language] = t('- Not applicable -');
            break;

          default:
            if ($language != $current_language_id || ($language != $current_language_id && !array_key_exists('c-' . $language, $options))) {
              $options['c-' . $language] = $this->languageManager->getLanguageName($language);
            }
        }
      }
    }
    if (count($options)) {
      $selector_type = $config['languages']['selector']['type'];
      if ($selector_type == 'selectmultiple') {
        $selector_type = 'select';
        $multiple = TRUE;
      }
      else {
        $multiple = FALSE;
      }
      $form['languages'] = [
        '#type'           => $selector_type,
        '#multiple'       => $multiple,
        '#title'          => Html::escape($config['languages']['selector']['label']),
        '#title_display'  => $config['languages']['selector']['label_visibility'] ? 'before' : 'invisible',
        '#options'        => $options,
        '#default_value'  => ($selector_type == 'checkboxes') ? ['c-all'] : 'c-all',
        '#attributes'     => ['class' => ['custom-search-selector', 'custom-search-language']],
        '#weight'         => $config['languages']['weight'],
        '#validated'      => TRUE,
      ];
      // If there's only one type, hide the selector.
      if (count($languages) == 1 && !$config['languages']['any']['force']) {
        $form['languages']['#type'] = 'hidden';
        $form['languages']['#default_value'] = key(array_slice($options, count($options) - 1));
      }
      elseif ($config['languages']['region'] == 'popup') {
        $form['popup']['languages'] = $form['languages'];
        unset($form['languages']);
      }
    }

    // Custom Paths.
    $paths = $config['paths']['list'];
    if ($paths != '') {
      $options = [];
      $lines = explode("\n", $paths);
      foreach ($lines as $line) {
        $temp = explode('|', $line);
        $options[$temp[0]] = (count($temp) >= 2) ? t('@label', ['@label' => $temp[1]]) : '';
      }
      if (count($options) == 1) {
        $form['paths'] = [
          '#type'           => 'hidden',
          '#default_value'  => key($options),
        ];
      }
      else {
        $form['paths'] = [
          '#type'           => $config['paths']['selector']['type'],
          '#title'          => Html::escape($config['paths']['selector']['label']),
          '#title_display'  => $config['paths']['selector']['label_visibility'] ? 'before' : 'invisible',
          '#options'        => $options,
          '#default_value'  => key($options),
          '#weight'         => $config['paths']['weight'],
        ];
        if ($config['paths']['region'] == 'popup') {
          $form['popup']['paths'] = $form['paths'];
          unset($form['paths']);
        }
      }
    }

    // Criteria.
    $criteria = ['or', 'phrase', 'negative'];
    foreach ($criteria as $c) {
      if ($config['criteria'][$c]['display']) {
        $form['criteria_' . $c] = [
          '#type'       => 'textfield',
          '#title'      => Html::escape($config['criteria'][$c]['label']),
          '#size'       => 15,
          '#maxlength'  => 255,
          '#weight'     => $config['criteria'][$c]['weight'],
        ];
        if ($config['criteria'][$c]['region'] == 'popup') {
          $form['popup']['criteria_' . $c] = $form['criteria_' . $c];
          unset($form['criteria_' . $c]);
        }
      }
    }

    // Actions.
    $form['actions'] = ['#type' => 'actions'];
    $form['actions']['submit'] = [
      '#type'   => 'submit',
      '#value'  => Html::escape($config['submit']['text']),
      // Prevent op from showing up in the query string.
      '#name'   => '',
      '#weight' => $config['submit']['weight'],
    ];
    if ($config['submit']['image_path'] != '') {
      $form['actions']['submit']['#type'] = 'image_button';
      $form['actions']['submit']['#src'] = $config['submit']['image_path'];
      $form['actions']['submit']['#attributes'] = [
        'alt'   => Html::escape($config['submit']['text']),
        'class' => ['custom-search-button'],
      ];
      unset($form['actions']['submit']['#value']);
    }
    elseif ($form['actions']['submit']['#value'] == '') {
      $form['actions']['submit']['#attributes'] = ['style' => 'display:none;'];
    }

    // If nothing has been added to the popup, don't output any markup.
    if (!count(Element::children($form['popup']))) {
      unset($form['popup']);
    }

    // Add attributes.
    $form['#attributes']['role'] = 'search';

    // Passes the config for later use.
    $form_state->set('config', $config);

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $form_state->get('config');
    $filters = [];

    // Keywords.
    $keys = trim($form_state->getValue('keys'));

    // Filter Types.
    $types = $form_state->hasValue('types') ? $form_state->getValue('types') : [];
    if (!is_array($types)) {
      $types = [$types];
    }

    // Check if we're using another search (ie. Users).
    $first_type = current($types);
    if (substr($first_type, 0, 2) == 'o-') {
      $search_page_id = substr($first_type, 2);
      $search_pages = $this->entityTypeManager->getStorage('search_page')->loadMultiple([$search_page_id]);
      if (!empty($search_pages)) {
        $route = 'search.view_' . $search_page_id;
      }
    }
    else {
      // Build route.
      $route = 'search.view_' . $config['content']['page'];
      // Types filters.
      $types = array_map(function ($val) {
        return $this->filterKeys($val);
      }, array_filter($types));
      $excluded = array_map(function ($val) {
        return $this->filterKeys($val);
      }, array_filter($config['content']['excluded']));
      if (count($types)) {
        if (in_array('all', $types)) {
          // If - Any - is set to restrict the search, grab the content types.
          if ($config['content']['any']['restricts']) {
            $types = array_keys(array_filter($config['content']['types']));
          }
          // If exclusion has to be made, specify all the other types.
          if (!empty($excluded)) {
            $types = array_keys(node_type_get_names());
          }
          $types = array_diff($types, $excluded);
          if (!in_array('all', $types)) {
            foreach ($types as $type) {
              $filters[] = 'type:' . $type;
            }
          }
        }
        // If it's not - Any -, search for that type.
        else {
          $types = array_diff($types, $excluded);
          foreach ($types as $type) {
            $filters[] = 'type:' . $type;
          }
        }
      }
      // If there's no type selector but exclusion has to be made, specify all
      // the other types.
      elseif (!empty($excluded)) {
        $types = array_diff(array_keys(node_type_get_names()), $excluded);
        foreach ($types as $type) {
          $filters[] = 'type:' . $type;
        }
      }
      // Taxonomy filters.
      if ($this->moduleHandler->moduleExists('taxonomy')) {
        $terms = [];
        $vocabularies = $this->entityTypeManager->getStorage('taxonomy_vocabulary')->loadMultiple();
        foreach ($vocabularies as $voc) {
          $vid = $voc->id();
          if ($form_state->hasValue('vocabulary_' . $vid)) {
            $vterms = $form_state->getValue('vocabulary_' . $vid);
            if (!is_array($vterms)) {
              $vterms = [$vterms];
            }
            $terms = array_merge($terms, $vterms);
          }
        }
        // Uses array_values() to filter here to get numerical index, so we can
        // splice the array later if needed (see line below the array_map()).
        $terms = array_map(function ($val) {
          return $this->filterKeys($val);
        }, array_values(array_filter($terms)));
        // If one or more -Any- is selected, delete them.
        while (($index = array_search('all', $terms)) !== FALSE) {
          array_splice($terms, $index, 1);
        }
        if (count($terms)) {
          foreach ($terms as $term) {
            $filters[] = 'term:' . $term;
          }
        }
      }
      // Criteria filters.
      if ($form_state->hasValue('criteria_or') && trim($form_state->getValue('criteria_or')) != '') {
        $keys .= ' ' . str_replace(' ', ' OR ', trim($form_state->getValue('criteria_or')));
      }
      if ($form_state->hasValue('criteria_negative') && trim($form_state->getValue('criteria_negative')) != '') {
        $keys .= ' -' . str_replace(' ', ' -', trim($form_state->getValue('criteria_negative')));
      }
      if ($form_state->hasValue('criteria_phrase') && trim($form_state->getValue('criteria_phrase')) != '') {
        $keys .= ' "' . trim($form_state->getValue('criteria_phrase')) . '"';
      }
      // Language filters.
      $languages = $form_state->hasValue('languages') ? $form_state->getValue('languages') : [];
      if (!is_array($languages)) {
        $languages = [$languages];
      }
      $languages = array_map(function ($val) {
        return $this->filterKeys($val);
      }, array_filter($languages));
      if (count($languages)) {
        // If - Any - is selected and - Any - is set to restrict the search,
        // grab the languages.
        if (in_array('all', $languages) && $config['languages']['any']['restricts']) {
          $languages = array_keys(array_filter($config['languages']['languages']));
        }
        // If it's not - Any -, search for that language.
        if (!in_array('all', $languages)) {
          foreach ($languages as $language) {
            if ($language == 'current') {
              $filters[] = 'language:' . $this->languageManager->getCurrentLanguage()->getId();
            }
            else {
              $filters[] = 'language:' . $language;
            }
          }
        }
      }
    }

    // Build a custom path if needed.
    if ($form_state->hasValue('paths') && $form_state->getValue('paths') != '') {
      $route = $form_state->getValue('paths');
      $route = str_replace('[current_path]', $this->currentPath->getPath(), $route);
      $route = str_replace('[key]', $keys, $route);
      if (strpos($route, '[types]') !== FALSE) {
        $route = str_replace('[types]', (isset($types) && count($types)) ? implode($config['paths']['separator'], $types) : '', $route);
      }
      if (strpos($route, '[terms]') !== FALSE) {
        $route = str_replace('[terms]', (isset($terms) && count($terms)) ? implode($config['paths']['separator'], $terms) : '', $route);
      }
      // Check for a query string.
      $query = [];
      $route_query_position = strpos($route, '?');
      if ($route_query_position !== FALSE) {
        $query_tmp = substr($route, 1 + $route_query_position);
        $query_tmp = str_replace('&amp;', '&', $query_tmp);
        $query_tmp = explode('&', $query_tmp);
        foreach ($query_tmp as $param) {
          $param_exploded = explode('=', $param);
          $query[$param_exploded[0]] = $param_exploded[1];
        }
        $route = substr($route, 0, $route_query_position);
      }
      // If not an external URL, add the base url scheme.
      if (substr($route, 0, 4) != 'http') {
        $route = 'base://' . $route;
      }
      // Generate the final url.
      $url = Url::fromUri($route, ['query' => $query]);
      // Redirect.
      if ($url->isExternal()) {
        $form_state->setResponse(new TrustedRedirectResponse($url->toUriString(), 302));
      }
      else {
        $form_state->setRedirectUrl($url);
      }

    }
    else {
      $query['keys'] = $keys;
      if (count($filters)) {
        $query['f'] = $filters;
      }
      $form_state->setRedirect(
        $route,
        [],
        ['query' => $query]
      );
    }

  }

  /**
   * Helper functions.
   */
  private static function filterKeys($val) {
    return (strlen($val) > 2 && $val[1] == '-') ? mb_substr($val, 2) : $val;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc