Filtrowanie wyników za pomocą LIKE

16

Rozważ te trzy ciągi „stogu siana”:

za) foo bar

b) welcome to foo bar industries

do) foo barer

A teraz moja „igła”:

foo bar

(Heh)

Chciałbym, aby mój filtr pasował do mojej igły z ciągami stogu siana a & b, ale nie c. Próbowałem:

$collection->addAttributeToFilter('name', array('like' => '%'.$needle.'%'));

Ale powyższe pasuje do c.

Próbowałem także:

$collection->addAttributeToFilter('name', array('like' => '% '.$needle.' %')); // Note the spaces

Powyższe pasuje tylko do b.

Każda pomoc jest mile widziana.

beingalex
źródło

Odpowiedzi:

37

Spróbuj i sprawdź, czy pasuje:

$collection->addAttributeToFilter('name', array(
    array('like' => '% '.$needle.' %'), //spaces on each side
    array('like' => '% '.$needle), //space before and ends with $needle
    array('like' => $needle.' %') // starts with needle and space after
));

Przekazanie drugiego parametru jako tablicy tablic połączy warunki przy użyciu OR

Marius
źródło
To działa :) Nie wiedziałem o sztuczce tablicowej, dzięki.
beingalex
Modele niestandardowe / inne niż eav addAttributeToFilterpowinny zostać zastąpione przez addFieldToFilter.
jvalanen
Czy istnieje sposób ustalenia, która tablica zwróciła wynik? Używam tej metody do wyszukiwania kolekcji modelu niestandardowego (nazwa, opis, nazwa alternatywna) i chciałbym wiedzieć, czy wynik został trafiony z powodu opisu (aby uwzględnić dodatkowy element interfejsu użytkownika w wynikach wyszukiwania).
pspahn
3
@pspahn Nie jest to proste. Możesz wykonać pętlę wyników po wykonaniu zaznaczenia i sprawdzić, czy igła znajduje się w dowolnym polu, które chcesz.
Marius
9

Możliwym rozwiązaniem jest użycie REGEXPzamiast LIKE:

$collection->addAttributeToFilter('name', array('regexp' => '[[:<:]]'.$needle.'[[:>:]]'));

Z dokumentacji MySQL :

[[: <:]], [[:>:]]

Te znaczniki oznaczają granice słów. Dopasowują odpowiednio początek i koniec słów. Słowo jest ciągiem znaków słownych, które nie są poprzedzane znakami słownymi ani po nich nie występują. Znak słowny to znak alfanumeryczny w klasie alnum lub znak podkreślenia (_).

Zauważ, że jeśli $needlemogą zawierać znaki, które mają specjalne znaczenie w wyrażeniach regularnych POSIX, musisz je uciec. Zobacz także: /programming/4024188/php-function-to-escape-mysql-regexp-syntax

Fabian Schmengler
źródło
3

Akceptowana odpowiedź nie działa poprawnie. Sprawdza tylko miejsce przed i po tekście.

Załóżmy, że masz następującą listę

  • Kurtka
  • Letnia kurtka
  • Kurtka zimowa

Teraz, jeśli spróbujesz wyszukać kurtkę przy użyciu zaakceptowanej odpowiedzi, zwróci tylko letnią kurtkę i zimową kurtkę

Myślę, że następujące rozwiązanie jest lepsze

$collection->addAttributeToFilter('name', array('like' => '%' . $needle. '%'));
Dinesh Yadav
źródło
Nie obejmuje przypadku (c) z pytania (tj. Również pasuje do „kurtki”). Zamiast tego można dodać czwarty warunek, ['eq' => $needle]aby znaleźć dokładne dopasowania (lub lepiej, użyj rozwiązania wyrażenia regularnego, które znajduje wszystkie granice, nie tylko spacje)
Fabian Schmengler
powyższy kod jest w stanie znaleźć dokładne dopasowania. Sprawdziłem to
Dinesh Yadav
Nie wątpiłem w to. Ale znajduje więcej, czego nie powinien. Przynajmniej jeśli masz takie same wymagania jak w pierwotnym pytaniu: nie znajdź „foo barer” podczas wyszukiwania „foo bar”
Fabian Schmengler
Tak masz rację. Przyjęta odpowiedź nie działała dla mnie poprawnie, więc zasugerowałem prosty filtr jednowierszowy, aby uzyskać podobne pozycje.
Dinesh Yadav