The name module's views filters are inherited from the field API, which is The Way Things Should Be Done. However, because names are collections of subfields it means it's impossible to make an exposed filter in a view that searches the fullname of an entity.
This might take a little work, as in a perfect world a filter like this would explode out all words in a search and partial match against all parts of a name. For example, searching "Smith" would search given, middle, and family name for "Smith," but "J Smith" would search all three for names starting with "J" and "Smith" and only return results where both were the case.
Will try to write a patch later today.
Comments
Comment #1
Anonymous (not verified) commentedAttached is a view filter that searches given, middle, and family name for the start of any word. There's a few UI options that should be added to give more options to a form builder.
Comment #2
Anonymous (not verified) commentedMissed query placeholders. Fixed.
Comment #3
Anonymous (not verified) commentedWhoops, there we go.
Comment #4
dealancer commented+1
Comment #5
alan d. commentedAnybody reviewed this patch?
Comment #6
dealancer commentedGoing to do this right now.
Comment #7
dealancer commentedVery nice start! The patch looks almost complete, a few thing needs to be done. Here is my review:
I've got wrong queries is being generated. E.g. When searching for 'Vadim S' following conditions are added, which aren't looking right:
This issue cause we are using same placeholder for different words, so it is better to use unique placeholder. Or we need to call it inside the loop.
Space at empty line
Why do we need to make this check? I've got both parameters are equal to 'views', hence nothing is returned. Just need to return version here.
Space at the end of line.
Space at empty line.
Also I am experiencing weird behavior, which is brought by the Views module, I guess. Labels of the filter are named as one the field label for one of the bundle, however I have 3 different bundles, which have different labels for this field. May be it is caused by how the views work, not sure, it is something to check. May be we need to programmatically rename label to be more generic.
Comment #8
dealancer commentedAlso show all, show none is not working.
Comment #9
dealancer commentedI have updated following things in a patch:
1. Replaced operator to one which allows to use these options: contains, has any word has all words.
2. Updated how query() works, now it concats all fields into one sting and then performs search depending on the operator. I am not sure which way is more good for performance, though.
3. Renamed name of the filter and cleaned up some code.
Comment #10
dealancer commentedThe same patch as above with spaces at the end of line removed.
Comment #11
ygerasimov commentedPlease replace "node" with "entity" word as we can add field not only to nodes.
Should be:
$where->where("$fulltext_field LIKE $placeholder", array($placeholder => '%' . db_like($word) . '%'));Truly to say, I was not able to test this patch properly.
What I have done:
1. Added Name field to article with default settings.
2. Created several articles with Name field submitted.
3. Created a view, table display, title and name fields
Now as I understand I should create a filter for Fulltext search in name, but can't find an option. Could you please point me a place in settings where I can do that.
In the code I see that we replace handlers for standard fields to make them to search in fulltext field, but I can't make this functionality work.
Comment #12
dealancer commentedThanks for review. This filter will appear when you will clear the cache.
Actually we do not replace handler, cause there is not any filter handler for the name field, so we add the filter. But there are a filters for the it's component.
This filter is called as a name field label.
Comment #13
ygerasimov commented@dealancer yes, you are right. My bad. Clearing caches helps :)
Why do we need exposed_validate() method? Looks like its code doesn't do anything.
Needs doxygen comments. Formatting problem. Missing spaces after "if" and "foreach".
Comment #14
dealancer commentedActually we need to add check to exposed_validate if operator is selected. Or to set default operator.
Comment #15
dealancer commentedHere is a new patch iteration with fixed issues described in comments above.
Comment #16
ygerasimov commentedCan we extend this comment and add "Add new views name fulltext handler for every name field."
Formatting issue space after "if"
Everything else I am happy with! Great work!
Please reroll the patch so I will mark it RTBC.
Comment #17
pingers commentedRemove the extra lines.
Add period at end of comment.
Could remove this extra line.
Add period at end of comment.
I'd use single quotes - not essential.
I think Yuriy covered my other issues :)
Comment #18
alan d. commentedI'm just having a look for the first time.
False matches (from a human perspective)
I have not tested the patch, but looking at these two lines, suggest that partial matches will occur within a string:
So searching for the name "cdefg" using "cd", there would be a hit on "abcd" too.
Normally I would use a conditional OR, IE:
But I think that this can be simplified to just "% :placeholder%%" if we change the CONCAT to:
And modify the condition to:
PostgreSQL
Don't use this much, and I haven't even got this installed, but I know that LIKE is case sensitive.
So pushing the above changes one step further:
The search terms are already converted:
Really nice work everyone!
Comment #19
dealancer commentedThanks for review guys, here is new iteration of patch. How it is ok ;)
Comment #20
dealancer commentedThe same patch with space at the end of line fixed.
Comment #21
dealancer commented@Alan D. thanks for a nice notice re LIKE in postgres. We can fix it fast as you suggested.
Regarding the human search, it was exactly as in first iteration of patch, which @kevee made, but I forgot to do same thing when was updating patch with a new operators. I think it will be easy to update. Thanks for a comment!
Comment #22
ygerasimov commentedI think @Alan D. has very good point about converting words to lowercase. In the meanwhile I would suggest to take native views as example i.e. no conversion at all. See http://drupalcode.org/project/views.git/blob/refs/heads/7.x-3.x:/handler...
So lets not do strtolower() but also trim words:
In this way even for PostgreSQL behavior will be the same for usual strings and our name field fulltext field. Search will be case sensitive.
Comment #23
dealancer commentedWell, they used case transformation in 6.x-3.x (http://drupalcode.org/project/views.git/blob/refs/heads/6.x-3.x:/handler...) but no it 7.x-3.x.
What about making all concat string lower, I could not find how to do this actually, cause there is no such commands in this list: http://drupal.org/node/773090. It means that it could work for couple databases but not all, so it is better don't use strtolower.
Comment #24
dealancer commented@ygerasimov, agreed with you, that we don't need to transform sting to lower, however trimming " ,!?" is not very helpful, cause it is a name, which is typically does not contain such characters, but let's use. Actually trimming from commas is good idea :) Also following change will be helpful:
@Alan D. and @ygerasimov, please, reviewnew generation of patch. It contains human search and trimming improvements.
Comment #25
dealancer commentedComment #26
ygerasimov commented$phrase is undefined. Please keep it simple:
Comment #27
alan d. commentedCase insensitive searches
Right, a small step in my D7 learning curve:
@see DatabaseConnection_pgsql::mapConditionOperator()
http://api.drupal.org/api/drupal/includes--database--pgsql--database.inc...
I think that we should do this, as every string search in core modules use condition($a, $b, 'LIKE') and is the expected behavior.
Special characters
We can not trim these off. This module has been used in many non-name based usages, such as a container for course information that can have special codes.
Explode
I think that we can keep this simple for the moment, we can add a quote aware split latter if required.
Comment #28
dealancer commented> I think that we should do this, as every string search in core modules use condition($a, $b, 'LIKE') and is the expected behavior.
Unfortunately condition works for the fields only, but we are having expression. Also using $where variable we can control if we want to add condition with AND or OR operator. This is very similar to how default string filter works.
> We can not trim these off. This module has been used in many non-name based usages, such as a container for course information that can have special codes.
Really, so it is not a problem. Reverted.
> I think that we can keep this simple for the moment, we can add a quote aware split latter if required.
Well, the reason I used it is automatically timing the words with a spaces. The code actually was taken from the string filter in views 7.x-3.x so will work fine.
Here is a patch, and I think it is ready for commit now!
Comment #29
dealancer commentedNow it is. Updated the way of spiting words.
Comment #30
alan d. commentedNew issue, I have not enabled a couple of the components and these are NULL values in the database. So CONCAT() fails on MySQL unless every field is populated.
Going back to SQL-92, it should be save using the COALESCE() function. Note that CONCAT() is not from these old standards.
Comment #31
alan d. commentedSorry, drop the lower:
Comment #32
alan d. commentedCan you expand one this? I tried a simple un-grouped filter and it worked. An AND group with inner OR then tested with an inner AND and they all worked. (As far as I can tell, they both end up in the same DB object parameter, it is just that the condition() one just has more fields and is rendered slightly differently)
How do you trigger an error with this? And yes, the part that is being overridden here follows views, but as per a change last year, the others do not:
Comment #33
alan d. commentedAs from the views issue #1425184: views_handler_filter_string and case sensitivity: any word or all words search, it looks like that was a bug that was not addressed in #1029534: PostgreSQL case sensitivity in filter.
Comment #34
dealancer commented@Allan D.
Right, COALESCE is from old ANSI SQL, so we need to use it.
According to http://drupal.org/node/1029534 we need to fix following part of code to allow cross db work, replace add_where_expression with add_where:
And yeah we need to deal with this. We could replace where to condition, so LIKE should be processed the same way in different DBs:
Comment #35
dealancer commentedLooks like I have excpected issue with add_where, but not condition. Let me try it.
Comment #36
dealancer commentedWell no, I am still having issues with both condition and add_where.
So following code
Generates query like this
@Allan D. Can you provide the working code of what you described in comment #32 please.
Comment #37
alan d. commentedNot sure if this was it or not, I was playing around with querying individual components rather than the entire concat(), but the performance was really really bad:
IE: Best results but terrible performance:
Looking back into my local history, I think that this was the last working example, or at least this was the last time that I saved on that day. It still had the LOWER(), but I can not see that this would save the query from being stripped of the brackets as per your example. Note that I was only testing different word / allwords combo.
Comment #38
dealancer commentedChecked once again, adding complex field to condition() or add_where() is not working.
This is how add_where_expression works:
http://drupalcontrib.org/api/drupal/contributions!views!plugins!views_pl...
This is how add_where works:
http://drupalcontrib.org/api/drupal/contributions%21views%21plugins%21vi...
Here follows to magic functions which, are executed after add_where or add_where_expression to build a query. We need to investigate them to find a correct solution:
http://drupalcontrib.org/api/drupal/contributions%21views%21plugins%21vi...
http://drupalcontrib.org/api/drupal/drupal%21includes%21database%21query...
http://drupalcontrib.org/api/drupal/drupal%21includes%21database%21query...
Comment #39
dealancer commentedAs we can see from DatabaseCondition::compile (http://drupalcontrib.org/api/drupal/drupal%21includes%21database%21query...) if operator is null (e.g. we added it via where(), which was cause we called add_where_expression()) then there is no operator replacement happens:
otherwise if we set operator manually then it processed depending on a database version
The reason is of we have modified version of field if we add complex field is in following code:
escapeField() does this job, see http://drupalcontrib.org/api/drupal/drupal%21includes%21database%21datab...
The only possible way how we can do is to map LIKE operator manually.
Comment #40
alan d. commentedWhich bit did you try again? Did you modify the code at all?
The following would need changing: (untested)
Comment #41
dealancer commentedCorrect, the code you have mentioned is not working. The fulletext filed is parsed to CONCATCOALESCEfield_data_contact_name.contact_name_titleCOALESCEfield_data_contact_name.contact_name_givenCOALESCEfield_data_contact_name.contact_name_middleCOALESCEfield_data_contact_name.contact_name_familyCOALESCEfield_data_contact_name.contact_name_generationalCOALESCEfield_data_contact_name.contact_name_credentials by escapeField() function.
Comment #42
dealancer commentedHence we need to use add_where_expression and lower both fulltext field and search terms.
Here is a new patch!
Comment #43
dealancer commented@Alan D., could you review the patch, please? Also please see my reply here http://drupal.org/node/1425184#comment-5615552
Comment #44
alan d. commentedLost my test setup. If someone reviews I'll commit this :)
Comment #45
xcf33 commentedHi,
I have reviewed dealancer's code. The search filter works with name components (phrase) when choosing operator of contains or contains any for full name search, i.e. John Smith
Comment #46
alan d. commentedThanks for all the hard work guys. This has been committed to 7.x-1.x.
Reopen if there are issues with the existing code, or create a new thread for additional features / bugs (Like lower thingee, but I'm ignoring this for the moment).
Comment #48
alan d. commentedReopened for back-porting to D6.
Marked #1518158: Fullname views' filter for Drupal6 as a duplicate.
Patches welcome.
Comment #49
dealancer commentedActually our query construction with COALESCE is not working so good. It could not find both names and surnames like "Barack Obama". because there is no middle name, so "Barack Obama" != "Barack Obama". If middle name is skipped extra space is added.
The solution is to use CASE function.
Comment #50
casper83 commentedI think there is additional space in line 92 of the patch #42 in '% '
array($placeholder => '% ' . db_like($value) . '%'));
array($placeholder => '%' . db_like($value) . '%'));
Comment #51
dieuweThe issue with regards to not being able to search both first and last names is crippling and makes this filter unusable.
Should a new issue be opened for that or can this be addressed here?
Comment #52
dieuweOkay, so I have fiddled about a little bit more, and it does work if you change the operator to "Contains any word" or "Contains all words".
This isn't exactly obvious when first using the filter, especially when it is a "full name" filter, but it only works out of the box when using only part of a full name.
Comment #53
alan d. commentedFlagging as a duplicate of #2090789: Fulltext Filter does not match surname which seems to be the same and I can't replicate.
Also Views Global combine filter is an option here, add the given, middle and family components to that and expose it.