diff --git a/core/modules/search/lib/Drupal/search/Controller/SearchController.php b/core/modules/search/lib/Drupal/search/Controller/SearchController.php index eab40a9..7c7f54f 100644 --- a/core/modules/search/lib/Drupal/search/Controller/SearchController.php +++ b/core/modules/search/lib/Drupal/search/Controller/SearchController.php @@ -9,11 +9,14 @@ use Drupal\Component\Plugin\PluginManagerInterface; use Drupal\Core\Controller\ControllerInterface; +use Drupal\Core\KeyValueStore\KeyValueStoreInterface; +use Drupal\Core\Routing\PathBasedGeneratorInterface; +use Drupal\search\SearchInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; /** - * @todo. + * Returns responses for Search routes. */ class SearchController implements ControllerInterface { @@ -25,13 +28,33 @@ class SearchController implements ControllerInterface { protected $searchManager; /** + * Stores the state storage service. + * + * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface + */ + protected $state; + + /** + * The url generator service. + * + * @var \Drupal\Core\Routing\PathBasedGeneratorInterface + */ + protected $urlGenerator; + + /** * Constructs a new SearchController. * * @param \Drupal\Component\Plugin\PluginManagerInterface $search_manager * The search manager. + * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state + * The state key value store. + * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator + * The url generator service. */ - public function __construct(PluginManagerInterface $search_manager) { + public function __construct(PluginManagerInterface $search_manager, KeyValueStoreInterface $state, PathBasedGeneratorInterface $url_generator) { $this->searchManager = $search_manager; + $this->state = $state; + $this->urlGenerator = $url_generator; } /** @@ -39,15 +62,22 @@ public function __construct(PluginManagerInterface $search_manager) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('plugin.manager.search') + $container->get('plugin.manager.search'), + $container->get('state'), + $container->get('url_generator') ); } /** + * Provides a list of eligible search plugins for configuring. + * * @return array + * A list of search plugins that can be configured. */ public function addSearchConfig() { + // @todo Remove this when https://drupal.org/node/2032535 is in. drupal_set_title(t('Add new search configuration')); + $search_types = array(); foreach ($this->searchManager->getDefinitions() as $plugin_id => $search_info) { $search_types[$plugin_id] = array( @@ -62,11 +92,26 @@ public function addSearchConfig() { ); } - public function performOperation($search, $op) { + /** + * Performs an operation on the search entity. + * + * @param \Drupal\search\SearchInterface $search + * The search entity. + * @param string $op + * The operation to perform, usually 'enable' or 'disable'. + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse + * A redirect back to the search settings page. + */ + public function performOperation(SearchInterface $search, $op) { // Perform the operation. - $search->$op()->save(); - \Drupal::state()->set('menu_rebuild_needed', TRUE); - return new RedirectResponse(url('admin/config/search/settings', array('absolute' => TRUE))); + if (!$search->isDefaultSearch()) { + $search->$op()->save(); + } + else { + debug($search->id()); + } + return new RedirectResponse($this->urlGenerator->generateFromPath('admin/config/search/settings', array('absolute' => TRUE))); } } diff --git a/core/modules/search/lib/Drupal/search/Form/SearchDeleteForm.php b/core/modules/search/lib/Drupal/search/Form/SearchDeleteForm.php new file mode 100644 index 0000000..9ff0c2d --- /dev/null +++ b/core/modules/search/lib/Drupal/search/Form/SearchDeleteForm.php @@ -0,0 +1,47 @@ + $this->entity->label())); + } + + /** + * {@inheritdoc} + */ + public function getCancelPath() { + return 'admin/config/search/settings'; + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function submit(array $form, array &$form_state) { + $this->entity->delete(); + $form_state['redirect'] = 'admin/config/search/settings'; + drupal_set_message(t('The %label search has been deleted.', array('%label' => $this->entity->label()))); + } + +} 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 3018f3b..435fa7a 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 @@ -27,7 +27,8 @@ * "list" = "Drupal\search\SearchListController", * "form" = { * "add" = "Drupal\search\Form\SearchAddForm", - * "edit" = "Drupal\search\Form\SearchEditForm" + * "edit" = "Drupal\search\Form\SearchEditForm", + * "delete" = "Drupal\search\Form\SearchDeleteForm" * } * }, * config_prefix = "search.search", @@ -124,6 +125,13 @@ public function isConfigurable() { /** * {@inheritdoc} */ + public function isDefaultSearch() { + return config('search.settings')->get('default_plugin') == $this->id(); + } + + /** + * {@inheritdoc} + */ public function uri() { return array( 'path' => 'admin/config/search/settings/manage/' . $this->id(), @@ -153,6 +161,8 @@ public function getExportProperties() { * {@inheritdoc} */ public function preSave(EntityStorageControllerInterface $storage_controller) { + parent::preSave($storage_controller); + $plugin = $this->getPlugin(); // If this plugin has any configuration, ensure that it is set. if ($plugin instanceof ConfigurablePluginInterface) { @@ -163,6 +173,15 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { /** * {@inheritdoc} */ + public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { + parent::postSave($storage_controller, $update); + + \Drupal::state()->set('menu_rebuild_needed', TRUE); + } + + /** + * {@inheritdoc} + */ public static function sort($a, $b) { if ($a->status != $b->status) { return ($a->status > $b->status) ? -1 : 1; diff --git a/core/modules/search/lib/Drupal/search/Plugin/SearchPluginBase.php b/core/modules/search/lib/Drupal/search/Plugin/SearchPluginBase.php index fbf1b54..86490c3 100644 --- a/core/modules/search/lib/Drupal/search/Plugin/SearchPluginBase.php +++ b/core/modules/search/lib/Drupal/search/Plugin/SearchPluginBase.php @@ -83,7 +83,7 @@ public function buildResults() { return array( '#theme' => 'search_results', '#results' => $results, - '#module' => $this->pluginDefinition['module'], + '#module' => $this->pluginDefinition['provider'], ); } diff --git a/core/modules/search/lib/Drupal/search/SearchInterface.php b/core/modules/search/lib/Drupal/search/SearchInterface.php index d2ce212..99988a1 100644 --- a/core/modules/search/lib/Drupal/search/SearchInterface.php +++ b/core/modules/search/lib/Drupal/search/SearchInterface.php @@ -38,4 +38,9 @@ public function setPlugin($plugin_id); */ public function getPluginDefinition(); + /** + * @return bool + */ + public function isDefaultSearch(); + } diff --git a/core/modules/search/lib/Drupal/search/SearchListController.php b/core/modules/search/lib/Drupal/search/SearchListController.php index 56c25c4..fe85c57 100644 --- a/core/modules/search/lib/Drupal/search/SearchListController.php +++ b/core/modules/search/lib/Drupal/search/SearchListController.php @@ -221,6 +221,20 @@ public function buildForm(array $form, array &$form_state) { /** * {@inheritdoc} */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + // Prevent the default search from being disabled or deleted. + if ($entity->isDefaultSearch()) { + unset($operations['disable'], $operations['delete']); + } + + return $operations; + } + + /** + * {@inheritdoc} + */ public function validateForm(array &$form, array &$form_state) { } @@ -237,6 +251,12 @@ public function submitForm(array &$form, array &$form_state) { search_reindex(); } + // If the default search is disabled, enable it. + $entity = $this->storage->load($form_state['values']['default_plugin']); + if (!$entity->status()) { + $entity->enable()->save(); + } + $search_settings ->set('index.cron_limit', $form_state['values']['cron_limit']) ->set('default_plugin', $form_state['values']['default_plugin']) diff --git a/core/modules/search/lib/Drupal/search/SearchPluginManager.php b/core/modules/search/lib/Drupal/search/SearchPluginManager.php index b0e79b8..c860a86 100644 --- a/core/modules/search/lib/Drupal/search/SearchPluginManager.php +++ b/core/modules/search/lib/Drupal/search/SearchPluginManager.php @@ -43,7 +43,6 @@ public function processDefinition(&$definition, $plugin_id) { $definition += array( 'title' => $definition['provider'], 'path' => $definition['provider'], - 'module' => $definition['provider'], ); } diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php index 0725f76..c98ec5e 100644 --- a/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/lib/Drupal/search/Tests/SearchConfigSettingsFormTest.php @@ -162,16 +162,17 @@ 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. - $info = $module_info[$module]; - $edit = array(); + $edit = array('default_plugin' => $module); + $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); + foreach ($modules as $other) { - $operation = $other == $module ? 'enable' : 'disable'; - $this->drupalGet('admin/config/search/settings/manage/' . $other . '/' . $operation); + if ($other != $module) { + $this->drupalGet('admin/config/search/settings/manage/' . $other . '/disable'); + } } - $edit['default_plugin'] = $module; - $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); // Run a search from the correct search URL. + $info = $module_info[$module]; $this->drupalGet('search/' . $info['path'] . '/' . $info['keys']); $this->assertNoText('no results', $info['title'] . ' search found results'); $this->assertText($info['text'], 'Correct search text found'); @@ -206,7 +207,6 @@ function testSearchModuleDisabling() { foreach (entity_load_multiple('search') as $search) { $search->enable()->save(); } - $this->container->get('state')->set('menu_rebuild_needed', TRUE); $edit = array('default_plugin' => 'node_search'); $this->drupalPost('admin/config/search/settings', $edit, t('Save configuration')); diff --git a/core/modules/search/search.module b/core/modules/search/search.module index 9cebe6b..d447f15 100644 --- a/core/modules/search/search.module +++ b/core/modules/search/search.module @@ -170,6 +170,16 @@ function search_menu() { 'route_name' => 'search_settings', 'weight' => -10, ); + $items['admin/config/search/settings/manage/%search'] = array( + 'title callback' => 'entity_page_label', + 'title arguments' => array(5), + 'route_name' => 'search.edit', + ); + $items['admin/config/search/settings/manage/%search/delete'] = array( + 'title callback' => 'entity_page_label', + 'title arguments' => array(5), + 'route_name' => 'search.delete', + ); $items['admin/config/search/settings/reindex'] = array( 'title' => 'Clear index', 'route_name' => 'search_reindex_confirm', @@ -194,10 +204,10 @@ function search_menu() { 'page callback' => 'search_view', 'page arguments' => array($search_id, ''), 'access callback' => '_search_menu_access', - 'access arguments' => array($search_info['module']), + 'access arguments' => array($search_info['provider']), 'type' => MENU_LOCAL_TASK, 'file' => 'search.pages.inc', - 'weight' => $search_info['module'] == $default_info['module'] ? -10 : 0, + 'weight' => $search_info['provider'] == $default_info['provider'] ? -10 : 0, ); $items["$path/%menu_tail"] = array( 'title' => $search_info['title'], @@ -205,7 +215,7 @@ function search_menu() { 'page callback' => 'search_view', 'page arguments' => array($search_id, 2), 'access callback' => '_search_menu_access', - 'access arguments' => array($search_info['module']), + '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, @@ -222,6 +232,22 @@ function search_menu() { } /** + * Loads an active search entity. + * + * @param string $entity_id + * The search entity ID. + * + * @return \Drupal\search\SearchInterface + * The search entity. + */ +function search_load($entity_id, $active_only = FALSE) { + $entity = entity_load('search', $entity_id); + if (!$active_only || ($entity && $entity->status())) { + return $entity; + } +} + +/** * Determines access for the 'search' path. */ function search_is_active() { @@ -230,23 +256,40 @@ function search_is_active() { } /** - * Returns information about the default search module. + * Returns the search entity of the fallback. * - * @return array - * The search plugin definition for the default search module, if any. + * @param string $entity_id + * The search entity ID. + * + * @return \Drupal\search\SearchInterface + * An active search entity. */ -function search_get_default_module_info() { - $default = config('search.settings')->get('default_plugin'); - if (!$default || !$entity = entity_load('search', $default)) { +function search_get_active($entity_id) { + if (!$entity_id || !$entity = search_load($entity_id, TRUE)) { // The variable setting does not match any active plugin, so just return // the info for the first active plugin (if any). $id = Drupal::entityQuery('search') ->condition('status', 1) - ->count(1) + ->range(0, 1) ->execute(); - $entity = entity_load('search', $id); + $entities = entity_load_multiple('search', $id); + $entity = reset($entities); + } + return $entity; +} +/** + * Returns information about the default search module. + * + * @return array + * The search plugin definition for the default search module, if any. + */ +function search_get_default_module_info() { + $default = config('search.settings')->get('default_plugin'); + $definition = array(); + if ($search = search_get_active($default)) { + $definition = $search->getPluginDefinition(); } - return $entity->getPluginDefinition(); + return $definition; } /** diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc index 705671e..740ff49 100644 --- a/core/modules/search/search.pages.inc +++ b/core/modules/search/search.pages.inc @@ -16,14 +16,14 @@ * @param $keys * Keywords to use for the search. */ -function search_view($plugin_id = NULL, $keys = '') { +function search_view($entity_id = NULL, $keys = '') { $keys = trim($keys); // Also try to pull search keywords out of the $_REQUEST variable to // support old GET format of searches for existing links. if (!$keys && !empty($_REQUEST['keys'])) { $keys = trim($_REQUEST['keys']); } - if (!$plugin_id || !$entity = entity_load('search', $plugin_id)) { + if (!$entity_id || !$entity = search_load($entity_id, TRUE)) { // 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. @@ -58,7 +58,7 @@ function search_view($plugin_id = NULL, $keys = '') { } } // The form may be altered based on whether the search was run. - $build['search_form'] = drupal_get_form('search_form', NULL, $keys, $plugin_id); + $build['search_form'] = drupal_get_form('search_form', NULL, $keys, $entity_id); $build['search_results'] = $results; return $build; diff --git a/core/modules/search/search.routing.yml b/core/modules/search/search.routing.yml index f007ab7..fac9ba2 100644 --- a/core/modules/search/search.routing.yml +++ b/core/modules/search/search.routing.yml @@ -40,3 +40,10 @@ search.disable: requirements: _permission: 'administer search' op: 'enable|disable' + +search.delete: + pattern: '/admin/config/search/settings/manage/{search}/delete' + defaults: + _entity_form: 'search.delete' + requirements: + _entity_access: 'search.delete'