Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
drupal
Manage
Activity
Members
Labels
Plan
Wiki
Custom issue tracker
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Model registry
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
project
drupal
Commits
0623c095
Commit
0623c095
authored
9 years ago
by
Alex Pott
Browse files
Options
Downloads
Patches
Plain Diff
Issue
#278958
by jhodgdon, pwolanin, mgifford: Advanced search form has usability issues
parent
fb35534d
No related branches found
No related tags found
2 merge requests
!7452
Issue #1797438. HTML5 validation is preventing form submit and not fully...
,
!789
Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
core/modules/node/src/Plugin/Search/NodeSearch.php
+95
-0
95 additions, 0 deletions
core/modules/node/src/Plugin/Search/NodeSearch.php
core/modules/search/src/Tests/SearchAdvancedSearchFormTest.php
+48
-5
48 additions, 5 deletions
...modules/search/src/Tests/SearchAdvancedSearchFormTest.php
with
143 additions
and
5 deletions
core/modules/node/src/Plugin/Search/NodeSearch.php
+
95
−
0
View file @
0623c095
...
@@ -114,6 +114,11 @@ class NodeSearch extends ConfigurableSearchPluginBase implements AccessibleInter
...
@@ -114,6 +114,11 @@ class NodeSearch extends ConfigurableSearchPluginBase implements AccessibleInter
'term'
=>
array
(
'column'
=>
'ti.tid'
,
'join'
=>
array
(
'table'
=>
'taxonomy_index'
,
'alias'
=>
'ti'
,
'condition'
=>
'n.nid = ti.nid'
)),
'term'
=>
array
(
'column'
=>
'ti.tid'
,
'join'
=>
array
(
'table'
=>
'taxonomy_index'
,
'alias'
=>
'ti'
,
'condition'
=>
'n.nid = ti.nid'
)),
);
);
/**
* A constant for setting and checking the query string.
*/
const
ADVANCED_FORM
=
'advanced-form'
;
/**
/**
* {@inheritdoc}
* {@inheritdoc}
*/
*/
...
@@ -490,38 +495,59 @@ public function indexStatus() {
...
@@ -490,38 +495,59 @@ public function indexStatus() {
* {@inheritdoc}
* {@inheritdoc}
*/
*/
public
function
searchFormAlter
(
array
&
$form
,
FormStateInterface
$form_state
)
{
public
function
searchFormAlter
(
array
&
$form
,
FormStateInterface
$form_state
)
{
$parameters
=
$this
->
getParameters
();
$keys
=
$this
->
getKeywords
();
$used_advanced
=
!
empty
(
$parameters
[
self
::
ADVANCED_FORM
]);
if
(
$used_advanced
)
{
$f
=
isset
(
$parameters
[
'f'
])
?
(
array
)
$parameters
[
'f'
]
:
array
();
$defaults
=
$this
->
parseAdvancedDefaults
(
$f
,
$keys
);
}
else
{
$defaults
=
array
(
'keys'
=>
$keys
);
}
$form
[
'basic'
][
'keys'
][
'#default_value'
]
=
$defaults
[
'keys'
];
// Add advanced search keyword-related boxes.
// Add advanced search keyword-related boxes.
$form
[
'advanced'
]
=
array
(
$form
[
'advanced'
]
=
array
(
'#type'
=>
'details'
,
'#type'
=>
'details'
,
'#title'
=>
t
(
'Advanced search'
),
'#title'
=>
t
(
'Advanced search'
),
'#attributes'
=>
array
(
'class'
=>
array
(
'search-advanced'
)),
'#attributes'
=>
array
(
'class'
=>
array
(
'search-advanced'
)),
'#access'
=>
$this
->
account
&&
$this
->
account
->
hasPermission
(
'use advanced search'
),
'#access'
=>
$this
->
account
&&
$this
->
account
->
hasPermission
(
'use advanced search'
),
'#open'
=>
$used_advanced
,
);
);
$form
[
'advanced'
][
'keywords-fieldset'
]
=
array
(
$form
[
'advanced'
][
'keywords-fieldset'
]
=
array
(
'#type'
=>
'fieldset'
,
'#type'
=>
'fieldset'
,
'#title'
=>
t
(
'Keywords'
),
'#title'
=>
t
(
'Keywords'
),
);
);
$form
[
'advanced'
][
'keywords'
]
=
array
(
$form
[
'advanced'
][
'keywords'
]
=
array
(
'#prefix'
=>
'<div class="criterion">'
,
'#prefix'
=>
'<div class="criterion">'
,
'#suffix'
=>
'</div>'
,
'#suffix'
=>
'</div>'
,
);
);
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'or'
]
=
array
(
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'or'
]
=
array
(
'#type'
=>
'textfield'
,
'#type'
=>
'textfield'
,
'#title'
=>
t
(
'Containing any of the words'
),
'#title'
=>
t
(
'Containing any of the words'
),
'#size'
=>
30
,
'#size'
=>
30
,
'#maxlength'
=>
255
,
'#maxlength'
=>
255
,
'#default_value'
=>
isset
(
$defaults
[
'or'
])
?
$defaults
[
'or'
]
:
''
,
);
);
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'phrase'
]
=
array
(
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'phrase'
]
=
array
(
'#type'
=>
'textfield'
,
'#type'
=>
'textfield'
,
'#title'
=>
t
(
'Containing the phrase'
),
'#title'
=>
t
(
'Containing the phrase'
),
'#size'
=>
30
,
'#size'
=>
30
,
'#maxlength'
=>
255
,
'#maxlength'
=>
255
,
'#default_value'
=>
isset
(
$defaults
[
'phrase'
])
?
$defaults
[
'phrase'
]
:
''
,
);
);
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'negative'
]
=
array
(
$form
[
'advanced'
][
'keywords-fieldset'
][
'keywords'
][
'negative'
]
=
array
(
'#type'
=>
'textfield'
,
'#type'
=>
'textfield'
,
'#title'
=>
t
(
'Containing none of the words'
),
'#title'
=>
t
(
'Containing none of the words'
),
'#size'
=>
30
,
'#size'
=>
30
,
'#maxlength'
=>
255
,
'#maxlength'
=>
255
,
'#default_value'
=>
isset
(
$defaults
[
'negative'
])
?
$defaults
[
'negative'
]
:
''
,
);
);
// Add node types.
// Add node types.
...
@@ -536,7 +562,9 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) {
...
@@ -536,7 +562,9 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) {
'#prefix'
=>
'<div class="criterion">'
,
'#prefix'
=>
'<div class="criterion">'
,
'#suffix'
=>
'</div>'
,
'#suffix'
=>
'</div>'
,
'#options'
=>
$types
,
'#options'
=>
$types
,
'#default_value'
=>
isset
(
$defaults
[
'type'
])
?
$defaults
[
'type'
]
:
array
(),
);
);
$form
[
'advanced'
][
'submit'
]
=
array
(
$form
[
'advanced'
][
'submit'
]
=
array
(
'#type'
=>
'submit'
,
'#type'
=>
'submit'
,
'#value'
=>
t
(
'Advanced search'
),
'#value'
=>
t
(
'Advanced search'
),
...
@@ -563,6 +591,7 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) {
...
@@ -563,6 +591,7 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) {
'#prefix'
=>
'<div class="criterion">'
,
'#prefix'
=>
'<div class="criterion">'
,
'#suffix'
=>
'</div>'
,
'#suffix'
=>
'</div>'
,
'#options'
=>
$language_options
,
'#options'
=>
$language_options
,
'#default_value'
=>
isset
(
$defaults
[
'language'
])
?
$defaults
[
'language'
]
:
array
(),
);
);
}
}
}
}
...
@@ -574,6 +603,7 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
...
@@ -574,6 +603,7 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
// Read keyword and advanced search information from the form values,
// Read keyword and advanced search information from the form values,
// and put these into the GET parameters.
// and put these into the GET parameters.
$keys
=
trim
(
$form_state
->
getValue
(
'keys'
));
$keys
=
trim
(
$form_state
->
getValue
(
'keys'
));
$advanced
=
FALSE
;
// Collect extra filters.
// Collect extra filters.
$filters
=
array
();
$filters
=
array
();
...
@@ -582,6 +612,7 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
...
@@ -582,6 +612,7 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
// checkboxes to 0.
// checkboxes to 0.
foreach
(
$form_state
->
getValue
(
'type'
)
as
$type
)
{
foreach
(
$form_state
->
getValue
(
'type'
)
as
$type
)
{
if
(
$type
)
{
if
(
$type
)
{
$advanced
=
TRUE
;
$filters
[]
=
'type:'
.
$type
;
$filters
[]
=
'type:'
.
$type
;
}
}
}
}
...
@@ -590,11 +621,13 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
...
@@ -590,11 +621,13 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
if
(
$form_state
->
hasValue
(
'term'
)
&&
is_array
(
$form_state
->
getValue
(
'term'
)))
{
if
(
$form_state
->
hasValue
(
'term'
)
&&
is_array
(
$form_state
->
getValue
(
'term'
)))
{
foreach
(
$form_state
->
getValue
(
'term'
)
as
$term
)
{
foreach
(
$form_state
->
getValue
(
'term'
)
as
$term
)
{
$filters
[]
=
'term:'
.
$term
;
$filters
[]
=
'term:'
.
$term
;
$advanced
=
TRUE
;
}
}
}
}
if
(
$form_state
->
hasValue
(
'language'
)
&&
is_array
(
$form_state
->
getValue
(
'language'
)))
{
if
(
$form_state
->
hasValue
(
'language'
)
&&
is_array
(
$form_state
->
getValue
(
'language'
)))
{
foreach
(
$form_state
->
getValue
(
'language'
)
as
$language
)
{
foreach
(
$form_state
->
getValue
(
'language'
)
as
$language
)
{
if
(
$language
)
{
if
(
$language
)
{
$advanced
=
TRUE
;
$filters
[]
=
'language:'
.
$language
;
$filters
[]
=
'language:'
.
$language
;
}
}
}
}
...
@@ -602,15 +635,18 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
...
@@ -602,15 +635,18 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
if
(
$form_state
->
getValue
(
'or'
)
!=
''
)
{
if
(
$form_state
->
getValue
(
'or'
)
!=
''
)
{
if
(
preg_match_all
(
'/ ("[^"]+"|[^" ]+)/i'
,
' '
.
$form_state
->
getValue
(
'or'
),
$matches
))
{
if
(
preg_match_all
(
'/ ("[^"]+"|[^" ]+)/i'
,
' '
.
$form_state
->
getValue
(
'or'
),
$matches
))
{
$keys
.
=
' '
.
implode
(
' OR '
,
$matches
[
1
]);
$keys
.
=
' '
.
implode
(
' OR '
,
$matches
[
1
]);
$advanced
=
TRUE
;
}
}
}
}
if
(
$form_state
->
getValue
(
'negative'
)
!=
''
)
{
if
(
$form_state
->
getValue
(
'negative'
)
!=
''
)
{
if
(
preg_match_all
(
'/ ("[^"]+"|[^" ]+)/i'
,
' '
.
$form_state
->
getValue
(
'negative'
),
$matches
))
{
if
(
preg_match_all
(
'/ ("[^"]+"|[^" ]+)/i'
,
' '
.
$form_state
->
getValue
(
'negative'
),
$matches
))
{
$keys
.
=
' -'
.
implode
(
' -'
,
$matches
[
1
]);
$keys
.
=
' -'
.
implode
(
' -'
,
$matches
[
1
]);
$advanced
=
TRUE
;
}
}
}
}
if
(
$form_state
->
getValue
(
'phrase'
)
!=
''
)
{
if
(
$form_state
->
getValue
(
'phrase'
)
!=
''
)
{
$keys
.
=
' "'
.
str_replace
(
'"'
,
' '
,
$form_state
->
getValue
(
'phrase'
))
.
'"'
;
$keys
.
=
' "'
.
str_replace
(
'"'
,
' '
,
$form_state
->
getValue
(
'phrase'
))
.
'"'
;
$advanced
=
TRUE
;
}
}
$keys
=
trim
(
$keys
);
$keys
=
trim
(
$keys
);
...
@@ -621,10 +657,69 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
...
@@ -621,10 +657,69 @@ public function buildSearchUrlQuery(FormStateInterface $form_state) {
if
(
$filters
)
{
if
(
$filters
)
{
$query
[
'f'
]
=
$filters
;
$query
[
'f'
]
=
$filters
;
}
}
// Record that the person used the advanced search form, if they did.
if
(
$advanced
)
{
$query
[
self
::
ADVANCED_FORM
]
=
'1'
;
}
return
$query
;
return
$query
;
}
}
/**
* Parses the advanced search form default values.
*
* @param array $f
* The 'f' query parameter set up in self::buildUrlSearchQuery(), which
* contains the advanced query values.
* @param string $keys
* The search keywords string, which contains some information from the
* advanced search form.
*
* @return array
* Array of default form values for the advanced search form, including
* a modified 'keys' element for the bare search keywords.
*/
protected
function
parseAdvancedDefaults
(
$f
,
$keys
)
{
$defaults
=
array
();
// Split out the advanced search parameters.
foreach
(
$f
as
$advanced
)
{
list
(
$key
,
$value
)
=
explode
(
':'
,
$advanced
,
2
);
if
(
!
isset
(
$defaults
[
$key
]))
{
$defaults
[
$key
]
=
array
();
}
$defaults
[
$key
][]
=
$value
;
}
// Split out the negative, phrase, and OR parts of keywords.
// For phrases, the form only supports one phrase.
$matches
=
array
();
$keys
=
' '
.
$keys
.
' '
;
if
(
preg_match
(
'/ "([^"]+)" /'
,
$keys
,
$matches
))
{
$keys
=
str_replace
(
$matches
[
0
],
' '
,
$keys
);
$defaults
[
'phrase'
]
=
$matches
[
1
];
}
// Negative keywords: pull all of them out.
if
(
preg_match_all
(
'/ -([^ ]+)/'
,
$keys
,
$matches
))
{
$keys
=
str_replace
(
$matches
[
0
],
' '
,
$keys
);
$defaults
[
'negative'
]
=
implode
(
' '
,
$matches
[
1
]);
}
// OR keywords: pull up to one set of them out of the query.
if
(
preg_match
(
'/ [^ ]+( OR [^ ]+)+ /'
,
$keys
,
$matches
))
{
$keys
=
str_replace
(
$matches
[
0
],
' '
,
$keys
);
$words
=
explode
(
' OR '
,
trim
(
$matches
[
0
]));
$defaults
[
'or'
]
=
implode
(
' '
,
$words
);
}
// Put remaining keywords string back into keywords.
$defaults
[
'keys'
]
=
trim
(
$keys
);
return
$defaults
;
}
/**
/**
* Gathers ranking definitions from hook_ranking().
* Gathers ranking definitions from hook_ranking().
*
*
...
...
This diff is collapsed.
Click to expand it.
core/modules/search/src/Tests/SearchAdvancedSearchFormTest.php
+
48
−
5
View file @
0623c095
...
@@ -40,13 +40,11 @@ protected function setUp() {
...
@@ -40,13 +40,11 @@ protected function setUp() {
}
}
/**
/**
* Test using the search form with GET and POST queries.
* Tests advanced search by node type.
* Test using the advanced search form to limit search to nodes of type "Basic page".
*/
*/
function
testNodeType
()
{
function
testNodeType
()
{
// Verify some properties of the node that was created.
$this
->
assertTrue
(
$this
->
node
->
getType
()
==
'page'
,
'Node type is Basic page.'
);
$this
->
assertTrue
(
$this
->
node
->
getType
()
==
'page'
,
'Node type is Basic page.'
);
// Assert that the dummy title doesn't equal the real title.
$dummy_title
=
'Lorem ipsum'
;
$dummy_title
=
'Lorem ipsum'
;
$this
->
assertNotEqual
(
$dummy_title
,
$this
->
node
->
label
(),
"Dummy title doesn't equal node title."
);
$this
->
assertNotEqual
(
$dummy_title
,
$this
->
node
->
label
(),
"Dummy title doesn't equal node title."
);
...
@@ -63,11 +61,56 @@ function testNodeType() {
...
@@ -63,11 +61,56 @@ function testNodeType() {
$this
->
drupalPostForm
(
'search/node'
,
$edit
,
t
(
'Advanced search'
));
$this
->
drupalPostForm
(
'search/node'
,
$edit
,
t
(
'Advanced search'
));
$this
->
assertText
(
$this
->
node
->
label
(),
'Basic page node is found with POST query.'
);
$this
->
assertText
(
$this
->
node
->
label
(),
'Basic page node is found with POST query.'
);
//
Advanced search type option
.
//
Search by node type
.
$this
->
drupalPostForm
(
'search/node'
,
array_merge
(
$edit
,
array
(
'type[page]'
=>
'page'
)),
t
(
'Advanced search'
));
$this
->
drupalPostForm
(
'search/node'
,
array_merge
(
$edit
,
array
(
'type[page]'
=>
'page'
)),
t
(
'Advanced search'
));
$this
->
assertText
(
$this
->
node
->
label
(),
'Basic page node is found with POST query and type:page.'
);
$this
->
assertText
(
$this
->
node
->
label
(),
'Basic page node is found with POST query and type:page.'
);
$this
->
drupalPostForm
(
'search/node'
,
array_merge
(
$edit
,
array
(
'type[article]'
=>
'article'
)),
t
(
'Advanced search'
));
$this
->
drupalPostForm
(
'search/node'
,
array_merge
(
$edit
,
array
(
'type[article]'
=>
'article'
)),
t
(
'Advanced search'
));
$this
->
assertText
(
'search yielded no results'
,
'Article node is not found with POST query and type:article.'
);
$this
->
assertText
(
'search yielded no results'
,
'Article node is not found with POST query and type:article.'
);
}
}
/**
* Tests that after submitting the advanced search form, the form is refilled.
*/
function
testFormRefill
()
{
$edit
=
array
(
'keys'
=>
'cat'
,
'or'
=>
'dog gerbil'
,
'phrase'
=>
'pets are nice'
,
'negative'
=>
'fish snake'
,
'type[page]'
=>
'page'
,
);
$this
->
drupalPostForm
(
'search/node'
,
$edit
,
t
(
'Advanced search'
));
// Test that the encoded query appears in the page title. Only test the
// part not including the quote, because assertText() cannot seem to find
// the quote marks successfully.
$this
->
assertText
(
'Search for cat dog OR gerbil -fish -snake'
);
// Verify that all of the form fields are filled out.
foreach
(
$edit
as
$key
=>
$value
)
{
if
(
$key
!=
'type[page]'
)
{
$elements
=
$this
->
xpath
(
'//input[@name=:name]'
,
array
(
':name'
=>
$key
));
$this
->
assertTrue
(
isset
(
$elements
[
0
])
&&
$elements
[
0
][
'value'
]
==
$value
,
"Field
$key
is set to
$value
"
);
}
else
{
$elements
=
$this
->
xpath
(
'//input[@name=:name]'
,
array
(
':name'
=>
$key
));
$this
->
assertTrue
(
isset
(
$elements
[
0
])
&&
!
empty
(
$elements
[
0
][
'checked'
]),
"Field
$key
is checked"
);
}
}
// Now test by submitting the or/not part of the query in the main
// search box, and verify that the advanced form is not filled out.
// (It shouldn't be filled out unless you submit values in those fields.)
$edit2
=
array
(
'keys'
=>
'cat dog OR gerbil -fish -snake'
);
$this
->
drupalPostForm
(
'search/node'
,
$edit2
,
t
(
'Advanced search'
));
$this
->
assertText
(
'Search for cat dog OR gerbil -fish -snake'
);
foreach
(
$edit
as
$key
=>
$value
)
{
if
(
$key
!=
'type[page]'
)
{
$elements
=
$this
->
xpath
(
'//input[@name=:name]'
,
array
(
':name'
=>
$key
));
$this
->
assertFalse
(
isset
(
$elements
[
0
])
&&
$elements
[
0
][
'value'
]
==
$value
,
"Field
$key
is not set to
$value
"
);
}
}
}
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment