Filtrage des résultats à l'aide de LIKE

16

Considérez ces trois chaînes de "meule de foin":

une) foo bar

b) welcome to foo bar industries

c) foo barer

Et maintenant mon "aiguille":

foo bar

(Il h)

Je voudrais que mon filtre corresponde à mon aiguille avec des cordes de meule de foin a & b mais pas c. J'ai essayé:

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

Mais ce qui précède correspond à c.

J'ai aussi essayé:

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

Ce qui précède ne correspond qu'à b.

Toute aide est très appréciée.

beingalex
la source

Réponses:

37

Essayez ceci et voyez si cela convient:

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

Le passage du deuxième paramètre sous la forme d'un tableau de tableaux concaténera les conditions à l'aide de OR

Marius
la source
Cela fonctionne :) Je ne connaissais pas l'astuce du tableau, merci.
beingalex
Avec des modèles personnalisés / non eav addAttributeToFilterdoivent être remplacés par addFieldToFilter.
jvalanen
Existe-t-il un moyen de déterminer quel tableau a renvoyé un résultat? J'utilise cette méthode pour rechercher une collection de modèles personnalisés (nom, description, champs nom_alternative) et je voudrais savoir si le résultat a été atteint à cause de la description (pour inclure un élément d'interface utilisateur supplémentaire dans les résultats de la recherche).
pspahn
3
@pspahn Pas simple. Vous pouvez parcourir les résultats une fois la sélection exécutée et vérifier si l'aiguille se trouve dans l'un des champs souhaités.
Marius
9

Une solution possible consiste à utiliser à la REGEXPplace de LIKE:

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

De la documentation MySQL :

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

Ces marqueurs représentent les limites des mots. Ils correspondent respectivement au début et à la fin des mots. Un mot est une séquence de caractères de mot qui n'est pas précédée ou suivie de caractères de mot. Un caractère de mot est un caractère alphanumérique de la classe alnum ou un trait de soulignement (_).

Notez que si $needlepeut contenir des caractères ayant des significations spéciales dans les expressions régulières POSIX, vous devez les échapper. Voir aussi: /programming/4024188/php-function-to-escape-mysql-regexp-syntax

Fabian Schmengler
la source
3

La réponse acceptée ne fonctionne pas correctement. Il vérifie uniquement l'espace avant et après le texte.

Supposons que vous ayez la liste suivante

  • Veste
  • Veste d'été
  • Veste d'hiver

Maintenant, si vous essayez de rechercher avec une veste en utilisant la réponse acceptée, elle ne renverra que la veste d'été et la veste d'hiver

Je pense que la solution suivante est meilleure

$collection->addAttributeToFilter('name', array('like' => '%' . $needle. '%'));
Dinesh Yadav
la source
Il ne couvrirait pas le cas (c) de la question (c'est-à-dire qu'il correspondrait également à la "veste"). Au lieu de cela, une quatrième condition ['eq' => $needle]pourrait être ajoutée pour trouver des correspondances exactes (ou mieux, utiliser la solution d'expression régulière qui trouve toutes les frontières, pas seulement les espaces)
Fabian Schmengler
le code ci-dessus est capable de trouver les correspondances exactes. Je l'ai vérifié
Dinesh Yadav
Je n'en doutais pas. Mais il en trouve plus, ce qu'il ne devrait pas. Au moins si vous avez les mêmes exigences que dans la question d'origine: ne trouvez pas "foo barer" lors de la recherche "foo bar"
Fabian Schmengler
Oui, tu as raison. La réponse acceptée ne fonctionnait pas correctement pour moi, j'ai donc suggéré le simple filtre à une ligne pour obtenir les mêmes éléments.
Dinesh Yadav