Problem/Motivation
This issue attempts to solve a couple of inter-related problems with the Search module:
1. Submitting a search form (either from the Search block or the Search page) is currently redirecting you to a page with URL "search/(specific_page_URL)/(keywords)". This is not great because:
- If you submit the form again, you have a mixture of the previous keywords and the new submission, which caused various problems, including sometimes not being able to get rid of a problematic search submission.
- It wasn't a very standard URL pattern. Most search engines use GET parameters for the keywords.
- It causes problems if you try to search for something like "../../admin" and that gets into the URL.
2. When submitting a new search from a search results page, you ended up doing the old search query first, and then the new one, leading to inefficiency and sometimes carrying over error/warning messages from the previous search to the new results page.
3. The SearchQuery extender was calling drupal_set_message() and form_set_error(). form_set_error() calls would not work anyway (it is not a form and doesn't know what form the error should go to), and other query extenders do not call drupal_set_message(), so this is non-standard behavior. So it needs to have a different method for passing information back to users of the search query that there were problems parsing or executing the search query.
The warnings and errors are as follows:
a) In parseSearchExpression() if someone searches for something like "cat or dog" instead of using "cat OR dog", they get a warning message.
b) In executeFirstPass() it calls form_set_error() if there are no "positive keywords" (as opposed to "negative keywords" that are excluded) to search for, and aborts the query. We need to fix that, but see also #1126688: Allow users to use advanced search without keywords entered -- this message is not actually desirable in all cases, such as an advanced search.
c) In executeFirstPass() it calls drupal_set_message() if there was a large number of search terms (to prevent DOS attacks). The query can still work in this case, but the user needs to be warned. (Came from #1265946: DoS against core using a large number of OR search query terms.)
As a note... These issues may not seem related, but it proved to be impossible to fix them separately, so they were combined into one issue.
Proposed resolution
1. Change the redirection so that instead of going to "search/(specific_page_url)/(keywords)" we instead redirect to "search/(type of search)" with a GET param named "keys", and other GET parameters as needed for certain search plugins. See also #894486: Use the query string for search keys rather than appending them to the URL.
2. SearchQuery needs to not call any warning/error/message functions. Instead, it should keep track of query "status" and provide a method for users of SearchQuery to check and see what happened after a search query, and generate the appropriate messages itself. This will also take care of #1789768: search_box_form_submit() improperly calls form_set_error().
3. We need to be more flexible than in the past about generating the "Please enter some keywords" message, because in a Node advanced search, keywords can come from the main keywords field or some of the "advanced" sections (where you can enter "or" words and phrases). But we still need the message if no keywords or advanced stuff is entered at all. We have a searchIsExecutable() method for search plugins, which was set up for this exact purpose; we need NodeSearch to implement this method. See #2170411: Please enter some keywords message has vanished and #1126688: Allow users to use advanced search without keywords entered, which are fixed by this issue's patch.
[As a note, it turned out that there wasn't really a good way to fix #2 and #3 here without also fixing #1. We needed to separate out the query, the plugin, the page, the form, and the messages properly. This has since them became the main goal of this patch.]
4. The SearchQuery class methods and documentation needed to be somewhat overhauled, after which we probably won't need to do any more in #582938: Fix up documentation and member names in SearchQuery, and it may also be possible to take care of #1435834: Cannot alter search queries, tag added too late during the overhaul.
Remaining tasks
a) Get the patch fully working and reviewed. As of the patch in #34, it works when tested manually and all the Search module tests also pass. [Patch still needs a review.]
b) Add tests for all the Related Issues that are supposedly fixed by this patch, to verify that they are in fact fixed. [This has been done]
c) Note that there is one @todo added to in the SearchBlockForm::submitForm() -- but it's been filed as a separate issue and it was not introduced by this patch:
#2174521: Page processing order: form submits vs. main page content is inefficient if form submit is a redirect
User interface changes
a) The URL for searching when you submit keywords is changing from (page url)/(keywords)?(additional query params) to (page url)?keys=(keywords)&(additional query params).
b) All the error and warning messages from searching are generated with drupal_set_message and not form_set_error, so they might look very slightly different.
c) Some warning/error messages that weren't working in 8 due to regression bugs will reappear.
d) The form element in the Search block form where you type in your keywords is changed from being named 'search_block_form' to being 'keys', and the search block form submits directly to the default search page with GET instead of redirecting.
API changes
(See also the UI changes, which may affect themers and modules that use form alters on the search form.)
a) Users of SearchQuery will need to check query status using the new getStatus() method and warn the user accordingly, instead of having the messages generated in SearchQuery itself.
b) Search plugins using the searchFormAlter() method to add fields to the search form (e.g., for advanced search) no longer need to define their own form submit, and in fact are discouraged from doing so. Instead, they should implement the new buildSearchUrlQuery() method. Search plugins that do not use searchFormAlter do not need to change in any way.
c) The misleadingly-named mostly-internal executeFirstPass() method in SearchQuery is renamed prepareAndNormalize(). After this patch, there are actually no core calls to this method.