Filtrando resultados usando LIKE

16

Considere estas três seqüências de "palheiro":

a) foo bar

b) welcome to foo bar industries

c) foo barer

E agora minha "agulha":

foo bar

(Heh)

Gostaria que meu filtro correspondesse à minha agulha com as cordas do palheiro a & b, mas não c. Eu tentei:

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

Mas o acima corresponde a c.

Eu também tentei:

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

O acima corresponde apenas a b.

Qualquer ajuda é muito apreciada.

beingalex
fonte

Respostas:

37

Faça uma tentativa e veja se ele se encaixa:

$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
));

Passar o segundo parâmetro como uma matriz de matrizes concatenará as condições usando OR

Marius
fonte
Isso funciona :) Não sabia sobre o truque da matriz, obrigado.
beingalex
Os modelos personalizados / não eav addAttributeToFilterdevem ser substituídos por addFieldToFilter.
jvalanen
Existe uma maneira de determinar qual matriz retornou um resultado? Estou usando esse método para pesquisar uma coleção de modelos personalizados (campos de nome, descrição, nome_ alternativo) e gostaria de saber se o resultado foi atingido devido à descrição (para incluir um elemento de interface do usuário adicional nos resultados da pesquisa).
Pspic
3
@pspahn Não é direto. Você pode percorrer os resultados após a seleção ser executada e verificar se a agulha está em algum dos campos que você deseja.
Marius
9

Uma solução possível é usar em REGEXPvez de LIKE:

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

Na documentação do MySQL :

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

Esses marcadores representam limites de palavras. Eles correspondem ao começo e ao fim das palavras, respectivamente. Uma palavra é uma sequência de caracteres da palavra que não é precedida ou seguida por caracteres da palavra. Um caractere de palavra é um caractere alfanumérico na classe alnum ou um sublinhado (_).

Observe que se $needlepuder conter caracteres que tenham significados especiais nas expressões regulares do POSIX, será necessário escapá-los. Consulte também: /programming/4024188/php-function-to-escape-mysql-regexp-syntax

Fabian Schmengler
fonte
3

A resposta aceita não funciona corretamente. Está verificando apenas o espaço antes e depois do texto.

Suponha que você tenha a seguinte lista

  • Jaqueta
  • Jaqueta de verão
  • Jaqueta de inverno

Agora, se você tentar pesquisar com jaqueta usando a resposta aceita, ele retornará apenas jaqueta de verão e jaqueta de inverno

Eu acho que a seguinte solução é melhor

$collection->addAttributeToFilter('name', array('like' => '%' . $needle. '%'));
Dinesh Yadav
fonte
Não cobriria o caso (c) da pergunta (ou seja, também corresponderia a "camisa"). Em vez disso, uma quarta condição ['eq' => $needle]poderia ser adicionado para encontrar correspondências exatas (ou melhor, use a solução regex que encontra todos os limites, não só espaços)
Fabian Schmengler
o código acima é capaz de encontrar as correspondências exatas. Eu verifiquei
Dinesh Yadav
Eu não duvidei disso. Mas encontra mais, o que não deveria. Pelo menos se você tem os mesmos requisitos que na pergunta original: não encontrar "barer foo" quando procurar "foo bar"
Fabian Schmengler
Sim você está certo. A resposta aceita não estava funcionando corretamente para mim, então sugeri o filtro de uma linha simples para obter os itens da mesma forma.
Dinesh Yadav