View source
<?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\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;
class CustomSearchBlockForm extends FormBase {
protected $moduleHandler;
protected $searchPageRepository;
protected $entityTypeManager;
protected $entityRepository;
public function __construct(SearchPageRepositoryInterface $search_page_repository, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository) {
$this->searchPageRepository = $search_page_repository;
$this->moduleHandler = $module_handler;
$this->entityTypeManager = $entity_type_manager;
$this->entityRepository = $entity_repository;
}
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'));
}
public function getFormId() {
return 'custom_search_block_form';
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = func_get_arg(2);
$form['#method'] = 'post';
$form['popup'] = [
'#type' => 'fieldset',
'#weight' => 1 + $config['search_box']['weight'],
'#attributes' => [
'class' => [
'custom_search-popup',
],
],
];
$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'],
];
$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 = [];
$others = !empty($config['content']['other']) ? array_keys(array_filter($config['content']['other'])) : [];
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 (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']);
}
}
$vocabularies = $this->entityTypeManager
->getStorage('taxonomy_vocabulary')
->loadMultiple();
if (count($config['taxonomy']) > 0) {
$taxonomy_term_storage = \Drupal::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]);
}
}
}
$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 = \Drupal::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] = \Drupal::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 (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']);
}
}
$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($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 = [
'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]);
}
}
}
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => Html::escape($config['submit']['text']),
'#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 (!count(Element::children($form['popup']))) {
unset($form['popup']);
}
$form['#attributes']['role'] = 'search';
$form_state
->set('config', $config);
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$config = $form_state
->get('config');
$filters = [];
$keys = trim($form_state
->getValue('keys'));
$types = $form_state
->hasValue('types') ? $form_state
->getValue('types') : [];
if (!is_array($types)) {
$types = [
$types,
];
}
$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 {
$route = 'search.view_' . $config['content']['page'];
$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 ($config['content']['any']['restricts']) {
$types = array_keys(array_filter($config['content']['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;
}
}
}
else {
$types = array_diff($types, $excluded);
foreach ($types as $type) {
$filters[] = 'type:' . $type;
}
}
}
elseif (!empty($excluded)) {
$types = array_diff(array_keys(node_type_get_names()), $excluded);
foreach ($types as $type) {
$filters[] = 'type:' . $type;
}
}
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);
}
}
$terms = array_map(function ($val) {
return $this
->filterKeys($val);
}, array_values(array_filter($terms)));
while (($index = array_search('all', $terms)) !== FALSE) {
array_splice($terms, $index, 1);
}
if (count($terms)) {
foreach ($terms as $term) {
$filters[] = 'term:' . $term;
}
}
}
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')) . '"';
}
$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 (in_array('all', $languages) && $config['languages']['any']['restricts']) {
$languages = array_keys(array_filter($config['languages']['languages']));
}
if (!in_array('all', $languages)) {
foreach ($languages as $language) {
if ($language == 'current') {
$filters[] = 'language:' . \Drupal::languageManager()
->getCurrentLanguage()
->getId();
}
else {
$filters[] = 'language:' . $language;
}
}
}
}
}
if ($form_state
->hasValue('paths') && $form_state
->getValue('paths') != '') {
$route = $form_state
->getValue('paths');
$route = str_replace('[current_path]', \Drupal::service('path.current')
->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);
}
$query = [];
$route_query_position = strpos($route, '?');
if ($route_query_position !== FALSE) {
$query_tmp = substr($route, 1 + $route_query_position);
$query_tmp = str_replace('&', '&', $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 (substr($route, 0, 4) != 'http') {
$route = 'base://' . $route;
}
$url = Url::fromUri($route, [
'query' => $query,
]);
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,
]);
}
}
private static function filterKeys($val) {
return strlen($val) > 2 && $val[1] == '-' ? mb_substr($val, 2) : $val;
}
}