diff --git a/core/modules/node/config/search.search.node_search.yml b/core/modules/node/config/search.search.node_search.yml index 5c73892..7e9ac7e 100644 --- a/core/modules/node/config/search.search.node_search.yml +++ b/core/modules/node/config/search.search.node_search.yml @@ -1,7 +1,9 @@ id: node_search -label: Node +label: 'Node search' uuid: 25687eeb-4bb5-469c-ad05-5eb24cd7012c status: '1' langcode: en +path: node +title: Content plugin: node_search configuration: { } diff --git a/core/modules/node/node.module b/core/modules/node/node.module index ae14496..87481e6 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -1562,8 +1562,7 @@ function node_page_view(EntityInterface $node) { * @see node_search_validate() */ function node_form_search_form_alter(&$form, $form_state) { - - if (isset($form['module']) && $form['module']['#value'] == 'node' && user_access('use advanced search')) { + if ($form_state['search_plugin'] == 'node_search' && user_access('use advanced search')) { // Keyword boxes: $form['advanced'] = array( '#type' => 'details', diff --git a/core/modules/search/config/search.settings.yml b/core/modules/search/config/search.settings.yml index ff32f97..f6fa8fc 100644 --- a/core/modules/search/config/search.settings.yml +++ b/core/modules/search/config/search.settings.yml @@ -1,5 +1,5 @@ and_or_limit: '7' -default_entity: node_search +default_type: node_search index: cron_limit: '100' overlap_cjk: '1' diff --git a/core/modules/search/lib/Drupal/search/Controller/SearchController.php b/core/modules/search/lib/Drupal/search/Controller/SearchController.php index 7c7f54f..71d1a65 100644 --- a/core/modules/search/lib/Drupal/search/Controller/SearchController.php +++ b/core/modules/search/lib/Drupal/search/Controller/SearchController.php @@ -74,7 +74,7 @@ public static function create(ContainerInterface $container) { * @return array * A list of search plugins that can be configured. */ - public function addSearchConfig() { + public function addSearchType() { // @todo Remove this when https://drupal.org/node/2032535 is in. drupal_set_title(t('Add new search configuration')); diff --git a/core/modules/search/lib/Drupal/search/Form/SearchAddForm.php b/core/modules/search/lib/Drupal/search/Form/SearchAddForm.php index 6e11b77..a3afa35 100644 --- a/core/modules/search/lib/Drupal/search/Form/SearchAddForm.php +++ b/core/modules/search/lib/Drupal/search/Form/SearchAddForm.php @@ -26,7 +26,9 @@ protected function init(array &$form_state) { public function buildForm(array $form, array &$form_state, $search_plugin_id = NULL) { $this->entity->setPlugin($search_plugin_id); $definition = $this->entity->getPluginDefinition(); + $this->entity->set('path', $definition['path']); $this->entity->set('label', $definition['title']); + $this->entity->set('title', $definition['title']); return parent::buildForm($form, $form_state); } diff --git a/core/modules/search/lib/Drupal/search/Form/SearchFormBase.php b/core/modules/search/lib/Drupal/search/Form/SearchFormBase.php index f310210..bd1083d 100644 --- a/core/modules/search/lib/Drupal/search/Form/SearchFormBase.php +++ b/core/modules/search/lib/Drupal/search/Form/SearchFormBase.php @@ -10,6 +10,7 @@ use Drupal\Core\Entity\EntityControllerInterface; use Drupal\Core\Entity\EntityFormController; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\Query\QueryFactory; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\ConfigurablePluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -34,24 +35,24 @@ protected $plugin; /** - * The search storage controller. + * The entity query factory. * - * @var \Drupal\Core\Entity\EntityStorageControllerInterface + * @var \Drupal\Core\Entity\Query\QueryFactory */ - protected $storageController; + protected $entityQuery; /** * Constructs a new search form. * - * @param \Drupal\Core\Extension\ModuleHandlerInterface + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler service. - * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage_controller - * The search storage controller. + * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query + * The entity query. */ - public function __construct(ModuleHandlerInterface $module_handler, EntityStorageControllerInterface $storage_controller) { + public function __construct(ModuleHandlerInterface $module_handler, QueryFactory $entity_query) { parent::__construct($module_handler); - $this->storageController = $storage_controller; + $this->entityQuery = $entity_query; } /** @@ -60,13 +61,20 @@ public function __construct(ModuleHandlerInterface $module_handler, EntityStorag public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { return new static( $container->get('module_handler'), - $container->get('plugin.manager.entity')->getStorageController($entity_type) + $container->get('entity.query') ); } /** * {@inheritdoc} */ + public function getBaseFormID() { + return 'search_entity_form'; + } + + /** + * {@inheritdoc} + */ public function buildForm(array $form, array &$form_state) { $this->plugin = $this->entity->getPlugin(); return parent::buildForm($form, $form_state); @@ -79,6 +87,7 @@ public function form(array $form, array &$form_state) { $form['label'] = array( '#type' => 'textfield', '#title' => t('Label'), + '#description' => t('The administrative label for this search'), '#default_value' => $this->entity->label(), '#maxlength' => '255', ); @@ -92,6 +101,20 @@ public function form(array $form, array &$form_state) { 'exists' => array($this, 'exists'), ), ); + $form['title'] = array( + '#type' => 'textfield', + '#title' => t('Menu title'), + '#description' => t('The title used by the local tab on the search page'), + '#default_value' => $this->entity->getTitle(), + '#maxlength' => '255', + ); + $form['path'] = array( + '#type' => 'textfield', + '#title' => t('Path'), + '#field_prefix' => 'search/', + '#default_value' => $this->entity->getPath(), + '#maxlength' => '255', + ); $form['plugin'] = array( '#type' => 'value', '#value' => $this->entity->get('plugin'), @@ -118,8 +141,10 @@ public function form(array $form, array &$form_state) { * TRUE if the search configuration exists, FALSE otherwise. */ public function exists($id) { - $search = $this->storageController->load($id); - return !empty($search); + $entity = $this->entityQuery->get('search') + ->condition('id', $id) + ->execute(); + return (bool) $entity; } /** @@ -137,6 +162,15 @@ protected function actions(array $form, array &$form_state) { public function validate(array $form, array &$form_state) { parent::validate($form, $form_state); + // Ensure each path is unique. + $path = $this->entityQuery->get('search') + ->condition('path', $form_state['values']['path']) + ->condition('id', $form_state['values']['id'], '<>') + ->execute(); + if ($path) { + form_set_error('path', t('The search path must be unique')); + } + if ($this->plugin instanceof ConfigurablePluginInterface) { $this->plugin->validate($form, $form_state); } diff --git a/core/modules/search/lib/Drupal/search/Plugin/Core/Entity/Search.php b/core/modules/search/lib/Drupal/search/Plugin/Core/Entity/Search.php index 42d2f9e..3d5357e 100644 --- a/core/modules/search/lib/Drupal/search/Plugin/Core/Entity/Search.php +++ b/core/modules/search/lib/Drupal/search/Plugin/Core/Entity/Search.php @@ -78,6 +78,16 @@ class Search extends ConfigEntityBase implements SearchInterface { protected $plugin; /** + * @var string + */ + protected $path; + + /** + * @var string + */ + protected $title; + + /** * The plugin bag that stores search plugins. * * @var \Drupal\Core\Plugin\DefaultPluginBag @@ -126,7 +136,29 @@ public function isConfigurable() { * {@inheritdoc} */ public function isDefaultSearch() { - return \Drupal::service('config.factory')->get('search.settings')->get('default_entity') == $this->id(); + return \Drupal::service('config.factory')->get('search.settings')->get('default_type') == $this->id(); + } + + /** + * {@inheritdoc} + */ + public function getTitle() { + return $this->title; + } + + /** + * {@inheritdoc} + */ + public function getPath() { + return $this->path; + } + + /** + * {@inheritdoc} + */ + public function getProvider() { + $definition = $this->getPluginDefinition(); + return $definition['provider']; } /** @@ -148,6 +180,8 @@ public function uri() { public function getExportProperties() { $properties = parent::getExportProperties(); $names = array( + 'path', + 'title', 'plugin', 'configuration', ); diff --git a/core/modules/search/lib/Drupal/search/SearchInterface.php b/core/modules/search/lib/Drupal/search/SearchInterface.php index 853d552..19618e1 100644 --- a/core/modules/search/lib/Drupal/search/SearchInterface.php +++ b/core/modules/search/lib/Drupal/search/SearchInterface.php @@ -54,4 +54,19 @@ public function getPluginDefinition(); */ public function isDefaultSearch(); + /** + * @return string + */ + public function getPath(); + + /** + * @return string + */ + public function getProvider(); + + /** + * @return string + */ + public function getTitle(); + } diff --git a/core/modules/search/lib/Drupal/search/SearchListController.php b/core/modules/search/lib/Drupal/search/SearchListController.php index 592e07d..7bff6ae 100644 --- a/core/modules/search/lib/Drupal/search/SearchListController.php +++ b/core/modules/search/lib/Drupal/search/SearchListController.php @@ -93,10 +93,20 @@ public function render() { * {@inheritdoc} */ public function buildHeader() { - $header['label'] = t('Label'); - $header['plugin'] = t('Plugin'); - $header['status'] = t('Status'); - $header['operations'] = t('Operations'); + $header['label'] = array( + 'data' => t('Label'), + ); + $header['plugin'] = array( + 'data' => t('Plugin'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + $header['status'] = array( + 'data' => t('Status'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + $header['operations'] = array( + 'data' => t('Operations'), + ); return $header; } @@ -180,18 +190,18 @@ public function buildForm(array $form, array &$form_state) { '#description' => t('Whether to apply a simple Chinese/Japanese/Korean tokenizer based on overlapping sequences. Turn this off if you want to use an external preprocessor for this instead. Does not affect other languages.') ); - $form['search_plugins'] = array( + $form['search_types'] = array( '#type' => 'details', - '#title' => t('Search plugins'), + '#title' => t('Search types'), ); - $form['search_plugins']['inline_actions'] = array( + $form['search_types']['inline_actions'] = array( '#prefix' => '', ); - $form['search_plugins']['inline_actions']['add'] = array( + $form['search_types']['inline_actions']['add'] = array( '#theme' => 'menu_local_action', '#link' => array( - 'title' => t('Add new search settings'), + 'title' => t('Add new search type'), 'href' => 'admin/config/search/settings/add', ), ); @@ -199,13 +209,13 @@ public function buildForm(array $form, array &$form_state) { foreach ($entities as $entity) { $rows[$entity->id()] = $this->buildRow($entity); } - $form['search_plugins']['default_entity'] = array( + $form['search_types']['default_type'] = array( '#type' => 'tableselect', '#header' => $this->buildHeader(), '#options' => $rows, '#required' => TRUE, '#multiple' => FALSE, - '#default_value' => $search_settings->get('default_entity'), + '#default_value' => $search_settings->get('default_type'), ); $form['actions']['#type'] = 'actions'; @@ -252,14 +262,14 @@ public function submitForm(array &$form, array &$form_state) { } // If the default search is disabled, enable it. - $entity = $this->storage->load($form_state['values']['default_entity']); + $entity = $this->storage->load($form_state['values']['default_type']); if (!$entity->status()) { $entity->enable()->save(); } $search_settings ->set('index.cron_limit', $form_state['values']['cron_limit']) - ->set('default_entity', $form_state['values']['default_entity']) + ->set('default_type', $form_state['values']['default_type']) ->save(); drupal_set_message(t('The configuration options have been saved.')); diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php index 118a8e7..3086c21 100644 --- a/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php @@ -105,7 +105,7 @@ function testSearchModuleSettingsPage() { // Enable search for the test module $edit = array( - 'default_entity' => 'dummy_search_type', + 'default_type' => 'dummy_search_type', 'minimum_word_size' => 5, ); $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); @@ -162,7 +162,7 @@ function testSearchModuleDisabling() { // Test each module if it's enabled as the only search module. foreach ($modules as $module) { // Enable the one module and disable other ones. - $edit = array('default_entity' => $module); + $edit = array('default_type' => $module); $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); foreach ($modules as $other) { @@ -208,7 +208,7 @@ function testSearchModuleDisabling() { $search->enable()->save(); } - $edit = array('default_entity' => 'node_search'); + $edit = array('default_type' => 'node_search'); $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); foreach (array('search/node/pizza', 'search/node') as $path) { diff --git a/core/modules/search/search.module b/core/modules/search/search.module index ffe969b..c0004c4 100644 --- a/core/modules/search/search.module +++ b/core/modules/search/search.module @@ -162,7 +162,7 @@ function search_menu() { 'route_name' => 'search.add', ); $items['admin/config/search/settings/add/%'] = array( - 'route_name' => 'search.add_settings', + 'route_name' => 'search.add_type', ); $items['admin/config/search/settings'] = array( 'title' => 'Search settings', @@ -193,39 +193,36 @@ function search_menu() { // system appears to be having two sets of tabs. See discussion on issue // http://drupal.org/node/245103 for details. - $default_info = search_get_default_entity_info(); - if ($default_info) { - foreach (entity_load_multiple_by_properties('search', array('status' => '1')) as $search_id => $entity) { - $search_info = $entity->getPluginDefinition(); - $path = 'search/' . $search_info['path']; - $items[$path] = array( - 'title' => $search_info['title'], - 'page callback' => 'search_view', - 'page arguments' => array($search_id, ''), - 'access callback' => '_search_menu_access', - 'access arguments' => array($search_info['provider']), - 'type' => MENU_LOCAL_TASK, - 'file' => 'search.pages.inc', - 'weight' => $search_info['provider'] == $default_info['provider'] ? -10 : 0, - ); - $items["$path/%menu_tail"] = array( - 'title' => $search_info['title'], - 'load arguments' => array('%map', '%index'), - 'page callback' => 'search_view', - 'page arguments' => array($search_id, 2), - 'access callback' => '_search_menu_access', - 'access arguments' => array($search_info['provider']), - // The default local task points to its parent, but this item points to - // where it should so it should not be changed. - 'type' => MENU_LOCAL_TASK, - 'file' => 'search.pages.inc', - 'weight' => 0, - // These tabs are not subtabs. - 'tab_root' => 'search/' . $default_info['path'] . '/%', - // These tabs need to display at the same level. - 'tab_parent' => 'search/' . $default_info['path'], - ); - } + $default_type = search_get_default_type(); + foreach (entity_load_multiple_by_properties('search', array('status' => '1')) as $search_id => $entity) { + $path = 'search/' . $entity->getPath(); + $items[$path] = array( + 'title' => $entity->getTitle(), + 'page callback' => 'search_view', + 'page arguments' => array($search_id, ''), + 'access callback' => '_search_menu_access', + 'access arguments' => array($entity->getProvider()), + 'type' => MENU_LOCAL_TASK, + 'file' => 'search.pages.inc', + 'weight' => $entity->isDefaultSearch() ? -10 : 0, + ); + $items["$path/%menu_tail"] = array( + 'title' => $entity->getTitle(), + 'load arguments' => array('%map', '%index'), + 'page callback' => 'search_view', + 'page arguments' => array($search_id, 2), + 'access callback' => '_search_menu_access', + 'access arguments' => array($entity->getProvider()), + // The default local task points to its parent, but this item points to + // where it should so it should not be changed. + 'type' => MENU_LOCAL_TASK, + 'file' => 'search.pages.inc', + 'weight' => 0, + // These tabs are not subtabs. + 'tab_root' => 'search/' . $default_type->getPath() . '/%', + // These tabs need to display at the same level. + 'tab_parent' => 'search/' . $default_type->getPath(), + ); } return $items; } @@ -258,14 +255,13 @@ function search_is_active() { } /** - * Returns information about the default search module. + * Returns the default search entity. * - * @return array - * The search plugin definition for the default search module, if any. + * @return \Drupal\search\SearchInterface + * The search entity. */ -function search_get_default_entity_info() { - $definition = array(); - $default = config('search.settings')->get('default_entity'); +function search_get_default_type() { + $default = config('search.settings')->get('default_type'); if (!$default || !$entity = search_load($default, TRUE)) { // The variable setting does not match any active plugin, so just return // the info for the first active plugin (if any). @@ -273,9 +269,9 @@ function search_get_default_entity_info() { ->condition('status', 1) ->range(0, 1) ->execute(); - $definition = entity_load('search', reset($id))->getPluginDefinition(); + $entity = entity_load('search', reset($id)); } - return $definition; + return $entity; } /** @@ -954,17 +950,11 @@ function search_expression_insert($expression, $option, $value = NULL) { * @see search_form_validate() * @see search_form_submit() */ -function search_form($form, &$form_state, $action = '', $keys = '', $plugin_id = NULL, $prompt = NULL) { - if (!$plugin_id) { - $module_info = search_get_default_entity_info(); - } - else { - $entity = entity_load('search', $plugin_id); - $module_info = $entity->getPluginDefinition(); - } +function search_form($form, &$form_state, $action = '', $keys = '', $entity_id = NULL, $prompt = NULL) { + $entity = $entity_id ? entity_load('search', $entity_id) : search_get_default_type(); if (!$action) { - $action = 'search/' . $module_info['path']; + $action = 'search/' . $entity->getPath(); } if (!isset($prompt)) { $prompt = t('Enter your keywords'); @@ -972,8 +962,8 @@ function search_form($form, &$form_state, $action = '', $keys = '', $plugin_id = $form['#action'] = url($action); // Record the $action for later use in redirecting. + $form_state['search_plugin'] = $entity->getPlugin()->getPluginId(); $form_state['action'] = $action; - $form['module'] = array('#type' => 'value', '#value' => $module_info['provider']); $form['basic'] = array('#type' => 'container', '#attributes' => array('class' => array('container-inline'))); $form['basic']['keys'] = array( '#type' => 'search', @@ -1038,9 +1028,8 @@ function search_box_form_submit($form, &$form_state) { } $form_id = $form['form_id']['#value']; - $info = search_get_default_entity_info(); - if ($info) { - $form_state['redirect'] = 'search/' . $info['path'] . '/' . trim($form_state['values'][$form_id]); + if ($entity = search_get_default_type()) { + $form_state['redirect'] = 'search/' . $entity->getPath() . '/' . trim($form_state['values'][$form_id]); } else { form_set_error(NULL, t('Search is currently disabled.'), 'error'); diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc index ed9449c..15d3e7b 100644 --- a/core/modules/search/search.pages.inc +++ b/core/modules/search/search.pages.inc @@ -27,19 +27,18 @@ function search_view($entity_id = NULL, $keys = '') { // No path or invalid path: find the default module. Note that if there // are no enabled search modules, this function should never be called, // since hook_menu() would not have defined any search paths. - $info = search_get_default_entity_info(); + $entity = search_get_default_type(); // Redirect from bare /search or an invalid path to the default search path. - $path = 'search/' . $info['path']; + $path = 'search/' . $entity->getPath(); if ($keys) { $path .= '/' . $keys; } return new RedirectResponse(url($path, array('absolute' => TRUE))); } - $plugin = $entity->getPlugin(); $request = Drupal::request(); + $plugin = $entity->getPlugin(); $plugin->setSearch($keys, $request->query->all(), $request->attributes->all()); - $info = $plugin->getPluginDefinition(); // Default results output is an empty string. $results = array('#markup' => ''); // Process the search form. Note that if there is $_POST data, @@ -51,7 +50,7 @@ function search_view($entity_id = NULL, $keys = '') { // Only search if there are keywords or non-empty conditions. if ($plugin->isSearchExecutable()) { // Log the search keys. - watchdog('search', 'Searched %type for %keys.', array('%keys' => $keys, '%type' => $info['title']), WATCHDOG_NOTICE, l(t('results'), 'search/' . $info['path'] . '/' . $keys)); + watchdog('search', 'Searched %type for %keys.', array('%keys' => $keys, '%type' => $entity->getTitle()), WATCHDOG_NOTICE, l(t('results'), 'search/' . $entity->getPath() . '/' . $keys)); // Collect the search results. $results = $plugin->buildResults(); diff --git a/core/modules/search/search.routing.yml b/core/modules/search/search.routing.yml index fac9ba2..833573c 100644 --- a/core/modules/search/search.routing.yml +++ b/core/modules/search/search.routing.yml @@ -15,11 +15,11 @@ search_reindex_confirm: search.add: pattern: '/admin/config/search/settings/add' defaults: - _content: '\Drupal\search\Controller\SearchController::addSearchConfig' + _content: '\Drupal\search\Controller\SearchController::addSearchType' requirements: _permission: 'administer search' -search.add_settings: +search.add_type: pattern: '/admin/config/search/settings/add/{search_plugin_id}' defaults: _entity_form: 'search.add' diff --git a/core/modules/search/tests/modules/search_extra_type/config/search.search.dummy_search_type.yml b/core/modules/search/tests/modules/search_extra_type/config/search.search.dummy_search_type.yml index b6e4996..cfebc79 100644 --- a/core/modules/search/tests/modules/search_extra_type/config/search.search.dummy_search_type.yml +++ b/core/modules/search/tests/modules/search_extra_type/config/search.search.dummy_search_type.yml @@ -3,5 +3,7 @@ label: 'Dummy search type' uuid: b55858d4-f428-474c-8200-ef47a4597aef status: '1' langcode: en +path: dummy_path +title: 'Dummy search type' plugin: search_extra_type_search configuration: { } diff --git a/core/modules/user/config/search.search.user_search.yml b/core/modules/user/config/search.search.user_search.yml index 5134b69..94c43ce 100644 --- a/core/modules/user/config/search.search.user_search.yml +++ b/core/modules/user/config/search.search.user_search.yml @@ -1,7 +1,9 @@ id: user_search -label: User +label: 'User search' uuid: c0d6b9a7-09a7-415f-b71a-26957bef635c status: '1' langcode: en +path: user +title: Users plugin: user_search configuration: { }