opalepatrick Posted February 3, 2016 Share Posted February 3, 2016 In this thread https://processwire.com/talk/topic/11754-search-not-working-as-intended/ there is a really nice solution for dealing with 3 letter words in search. However I am having a problem with selectors. $selector .= ", title|body|collection.title|hue.title|pattern.title|pattern_type.title|usage.title~=" . $sanitizer->selectorValue(implode(' ', $parts)); The problem is that if I have, for example, a search that is looking for myfabric (in title or title.collection) yellow (in hue.title) I get zero results. If I do either separately then I get results. So the search is myfabric yellow. It seems to me as if the query is saying IF EITHER OF THESE WORDS are in EITHER title OR title.collection OR hue.title then show results but not if they are in separate fields. I need it to be IF EITHER WORD is in any field. If both words are in one field then I get results as well. Baffled or dense. Any help appreciated. Link to comment Share on other sites More sharing options...
gebeer Posted February 4, 2016 Share Posted February 4, 2016 The manual for selector operators states for ~= "Contains all the words". So your search returns only fields that have all of the $parts, e.g. "myfabric yellow". I think you need to use the OR operator for your selector values, too (see here). So your code would read $selector .= ", title|body|collection.title|hue.title|pattern.title|pattern_type.title|usage.title~=" . $sanitizer->selectorValue(implode('|', $parts)); | pipe instead of blank space in the implode. Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 Thanks for the reply gebeer. That was my first thought, but that widens the search so that we get ANY field with myfabric OR yellow in it. What I would like is myfabric AND yellow in a concatenation of all the fields content. I tried a concat field but that doesn't work on runtime. Link to comment Share on other sites More sharing options...
LostKobrakai Posted February 4, 2016 Share Posted February 4, 2016 The sanitizer is not meant to sanitize groups of values, but only single ones. It's job is to mask out characters like the pipe just because it does have a special meaning in an selector string. Suppose I'd search for "My | Friend". You most likely wouldn't want this pipe to end up in your selector. In your case you'd want to implode the parts after sanitizing each part. Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 Sorry LostKobrai. I edited my reply to make more sense. You were too fast for me. As you can see I am happy enough not using OR in the selector string as I would prefer for the search to narrow. It is the fields being searched that are my problem. Essentially I need to search ALL the contents of the page for BOTH words. Link to comment Share on other sites More sharing options...
LostKobrakai Posted February 4, 2016 Share Posted February 4, 2016 The concat fieldtype is not the thing your looking for, but rather the cache fieldtype. It's generating a json representation of all selected fields which you can then search over in one go. Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 Thanks once again LostKobrakai. That is another thing that I tried but it produced zero results for the above. combo is a cache field. $selector .= ", combo~=" . $sanitizer->selectorValue(implode(' ', $parts)); I know there should be 3 results for this one Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 I thought at the time that the cache field might not be picking up content that came from a Page fieldtype (like hue.title) that allows PageArray? edit: Actually running that query for just the word yellow, I don't get the pages with the word yellow only in hue.title Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 Hmmm... might be to do with Autojoin? https://processwire.com/talk/topic/10496-autojoin-in-complex-setups-page-field-with-multiple-pages/ Link to comment Share on other sites More sharing options...
opalepatrick Posted February 4, 2016 Author Share Posted February 4, 2016 Not Autojoin afaik. I still have the same problem with this query. Any help would be appreciated. I am sure that it seems I am meandering on, but I am just trying to show what I am doing. If I appear to be missing the point or off the beaten track, then please say. Link to comment Share on other sites More sharing options...
Macrura Posted February 5, 2016 Share Posted February 5, 2016 i would first try running the query once for each of the $parts, and then add the results to a final Pagearray() Link to comment Share on other sites More sharing options...
opalepatrick Posted February 9, 2016 Author Share Posted February 9, 2016 Honestly Macrura and everyone else, I am just banging my head against a brick wall due to my lack of knowledge. So say my search is 'green vinyl', I have: $selector = ''; $parts = explode(' ', $search); $p = new PageArray(); $fs = array('hue.title','pattern.title','pattern_type.title','usage.title','title','collection.keywords'); if(count($parts)) { foreach ($parts as $pt) { foreach ($fs as $f) { $selector = ", collection.title!=Clearance, " . $f . "~=" . $pt; // echo $selector . "<br />"; $ps = wire("pages")->find("template=fabric" . $selector); // echo "Page ids are: " . $ps . "<br />"; $p->import($ps); } } } I get every page id if any word is available in any field. What I actually need is to get both words from a concatenation of content from all of the specified fields. I need to narrow the results so that for instance, I only get results when both 'green' and 'vinyl' appear in any field but not necessarily the same field. 'green' maybe from hue.title and 'vinyl' from collection.keywords? As mentioned previously the concat fieldtype would let me specify things like hue.title for page fieldtypes (single) but is not available at runtime. Cache fieldtype does not allow page fieldtypes. I am just getting tangled in my head and going down rabbit holes. Any help or questions to help me explain more clearly would be appreciated. I do find it hard to believe that I cannot query all fields on a page even if they are page fieldtypes (single). Link to comment Share on other sites More sharing options...
LostKobrakai Posted February 9, 2016 Share Posted February 9, 2016 As Macrura proposed: Run the query for each $part in isolation and in the end merge the results. $results = array(); foreach($parts as $part){ // Might be optimized to only retrieve IDs in the first place $result = $pages->find("something=$part"); $results[] = $result->explode("id"); } // Get all the id's present in all results $intersect = array_reduce($results, function($carry, $item){ if(is_null($carry)) return $item; return array_intersect($carry, $item); }); // Get the real search results $search_result = $pages->get("id=" . implode("|", $intersect)); Link to comment Share on other sites More sharing options...
BitPoet Posted February 9, 2016 Share Posted February 9, 2016 I can't see any reason (though I don't rule out that I'm missing the obvious) why running the same selector for each word inside a single query shouldn't work as expected. $sel = array(); $parts = explode(' ', $parts); $selfields = "title|body|collection.title|hue.title|pattern.title|pattern_type.title|usage.title"; foreach($parts as $part) { $sel[] = $selfields . "*=" . $sanitizer->selectorValue($part); } $found = $pages->find(implode(', ', $sel)); Link to comment Share on other sites More sharing options...
opalepatrick Posted February 9, 2016 Author Share Posted February 9, 2016 Thanks to you both for your replies. Just working on LostKobrakai's one first. Could you explain the logic particularly around the function with array_reduce as I am only getting a single result regardless of search? I would expect many id's in this case. edit: Actually, the one result is because of this line $search_result = $pages->get("id=" . implode("|", $intersect)); And it worked perfectly with $pages->find ! Thank you once again LostKobrakai and everyone who helped. Link to comment Share on other sites More sharing options...
opalepatrick Posted February 10, 2016 Author Share Posted February 10, 2016 Following up on this. I was so focussed on getting a result on multiple word search as above that I did not realise I was getting an error on single words: Call to a member function last() on a non-object I have checked and there is a dump that appears to be exactly the same format as the multi word search. The line above is the last piece of code before this call. $intersect = array_reduce($results, function($carry, $item){ if(is_null($carry)) return $item; return array_intersect($carry, $item); }); $search_result = $pages->get("id=" . implode("|", $intersect)); foreach($search_results as $m) { if($m->images->last()){ $img = $m->images->last()->width(300); } } As I say, this works for more than one word but not for one. Link to comment Share on other sites More sharing options...
opalepatrick Posted February 10, 2016 Author Share Posted February 10, 2016 As soon as I posted I realised that I was checking the foreach for last() images and there are some items being pulled in that don't have an image and this caused the error. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now