filterByKeywords cannot search against multiple keywords

Permalink
I'm using the function filterByKeywords, and it seems to only do exact string matches.

This seems to be the case when filtering a PageList object as well as FileList objects.

I need to be able to take a string of keywords, and filter the list per word, rather than against the whole string.

For example, both of the below searches should ideally return the same result:

"example search"

"search example"

I've seen solutions elsewhere that suggest exploding the keywords string into an array using space as a delimiter. Then loop through the array and call filterByKeywords per keyword.

However, that doesn't work. The search just ends up using the last word in the array and none of the others.

This also seems to be the way that the search block is currently working.

I'm working on 5.7.5.13.

 
hutman replied on at Permalink Reply
hutman
You should be able to do something like this

if ($query !== '') {
    $words = explode(' ', $query);
    $queryParsed = implode('%', $words);
    $ipl->filterByKeywords($queryParsed);
}
hutman replied on at Permalink Reply
hutman
Sorry, just re-read what you asked for and this will not do it, this will only search the words in order (with other stuff in between).
MichaelFD replied on at Permalink Reply
I found a way of doing it.

Rather than make an array and call the function per word, I changed the function itself to create and use an exploded array.

I made the following changes:

In \concrete\src\File\FileList.php, I changed this:

public function filterByKeywords($keywords)
    {
        $expressions = array(
            $this->query->expr()->like('fv.fvFilename', ':keywords'),
            $this->query->expr()->like('fv.fvDescription', ':keywords'),
            $this->query->expr()->like('fv.fvTitle', ':keywords'),
            $this->query->expr()->like('fv.fvTags', ':keywords'),
            $this->query->expr()->eq('uName', ':keywords')
        );
        $keys = FileAttributeKey::getSearchableIndexedList();
        foreach ($keys as $ak) {
            $cnt = $ak->getController();
            $expressions[] = $cnt->searchKeywords($keywords, $this->query);
        }
        $expr = $this->query->expr();


To this:

public function filterByKeywords($keywords)
    {
        $keywords = explode(' ', $keywords);
        foreach($keywords as $key => $word) {
            $expressions = array(
                $this->query->expr()->like('fv.fvFilename', ':keywords_'.$key),
                $this->query->expr()->like('fv.fvDescription', ':keywords_'.$key),
                $this->query->expr()->like('fv.fvTitle', ':keywords_'.$key),
                $this->query->expr()->like('fv.fvTags', ':keywords_'.$key),
                $this->query->expr()->eq('uName', ':keywords_'.$key)
            );
            $keys = FileAttributeKey::getSearchableIndexedList();
            foreach ($keys as $ak) {
                $cnt = $ak->getController();
                $expressions[] = $cnt->searchKeywords($word, $this->query, ':keywords_'.$key);


Then in \concrete\src\Attribute\Controller.php, I changed this:

public function searchKeywords($keywords, $queryBuilder)
    {
        return $queryBuilder->expr()->like('ak_' . $this->attributeKey->getAttributeKeyHandle(), ':keywords');
    }


To this:

public function searchKeywords($keywords, $queryBuilder, $keywords = ':keywords')
    {
        return $queryBuilder->expr()->like('ak_' . $this->attributeKey->getAttributeKeyHandle(), $keywords);
    }
Gondwana replied on at Permalink Reply
Gondwana
Another way to do this is to subclass PageList to provide a new function (say, filterByKeywordsBoolean) that uses MySql's 'IN BOOLEAN MODE' modifier.
Gondwana replied on at Permalink Reply 1 Attachment
Gondwana
If anyone wants to test or dissect a rough search block that can search for multiple keywords, try the attached.