Bonjour a tous!

Vous l'aurez deviné, j'ai du mal à traduire une requête (que je crois correcte) pour utiliser la manière de Cake.
Pour le contexte, il s'agit d'une requête pour une recherche à travers des articles.

Je veux donc une recherche de type OR (en gros, si on cherche plusieurs mots, la requête doit retourner les articles qui contiennent au moins un des mots).

$results = $this->Search->find('all', 
    array('conditions' => array(
        'Search.online' => 1,
        "Search.content LIKE" => "'% ".$sqlkws." %'"
    ));

pour le sqlkws :

$kw = $_GET'kw']; // où kw correspond a la chaine d'entrée pour la recherche.
$sqlkws = str_replace(" ", " %' OR Search.content LIKE '% ", $kw);

Pour le moment, pour une entrée : "la recherche du raton laveur", le code retourne :

$sqlkws = "la %' OR Search.content LIKE '% recherche %' OR Search.content LIKE '% du %' OR Search.content LIKE '% raton %' OR Search.content LIKE '% laveur'";

Et je crois que je suis a coté de la plaque dans mon délire parce qu'il n'y a aucun résultat.. donc je suppose que je m'y prend comme un pied ^^

Je vous remercie d'avance pour votre aide ;)

13 réponses


Passe Cake en mode debug et donne nous la requête SQL qui est générée quand tu réalises ta recherche. Cela te permettra et nous permettra aussi de voir ce qui ne va pas ;)

Canonier
Auteur

voili voulouuu.. (recherche : 'canard en sucre')

'query' => 'SELECT `Search`.`name`, `Search`.`slug`, `Search`.`content`, `Search`.`online` FROM `database`.`contents` AS `Search` WHERE `Search`.`online` = 1 AND `Search`.`content` LIKE '\'% canard %\' OR Search.content LIKE \'% en %\' OR Search.content LIKE \'% sucre %\'''

je crois que ce sont les guillemets qui posent probleme, non ? ^^

En fait quand je te demandais la requête, je demandais le SQL dump que l'on a quand on passe Cake en mode debug. Sans les caractères d'échappement ni tout le reste.

Mais là en l'état, il semble qu'il y ait des soucis oui. Il semble que tes guillemets aient été échappés. C'est pour ça qu'avec la string de la requête sans qu'elles vienne d'une variable PHP nous aiderait.

Canonier
Auteur

j'ai tapé

<?php echo $this->element('sql_dump');?>

à la fin de mon layout. C'est ca ? ^^

SELECT `Search`.`id`, `Search`.`name`, `Search`.`slug`, `Search`.`content`, `Search`.`online` FROM `database`.`contents` AS `Search` WHERE `Search`.`online` = 1 AND `Search`.`content` LIKE '\'% bilbo %\' OR Search.content LIKE \'% le %\' OR Search.content LIKE \'% hobbit %\''

EDIT : J'y vois que cakephp ne permet tout simplement pas de fermer et de rouvrire les guillemets.. pour les injections bien sur..
Du coup je pense tout betement que la structure ci-apres n'est pas la bonne pour ma requete.

$results = $this->Search->find('all', 
    array('conditions' => array(
        'Search.online' => 1,
        "Search.content LIKE" => "'% ".$sqlkws." %'"
    ));

Pour palier à ca, est-il possible d'utiliser un foreach dans les Controllers ?
Ainsi je peux générer une nouvelle ligne pour chaque mot avec un

"OR" => array(
    'Search.content LIKE' => 'mot1'
    , 'Search.content LIKE' => 'mot2' //code generé a chaque nouveau mot par le foreach
)

ca fonctionnerait tu penses ? ^^

Tu as aussi la possibilité d'utiliser les regexp de mysql pour le coup la fonction RLIKE

$results = $this->Search->find('all', 
    array('conditions' => array(
        'Search.online' => 1,
        "Search.content RLIKE" => str_replace(' ', '|', $sqlkws)
    ));

Après j'ai pas tester mais ca devrait work normalement

Canonier
Auteur

Merci pour cette découverte ^^

Malheureusement le problème persiste..

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version for the right syntax to use near 
'= 'le|raton|laveur'' at line 1

la requete :

SELECT `Search`.`id`, `Search`.`name`, `Search`.`slug`, `Search`.`content`, `Search`.`online` 
FROM `database`.`contents` AS `Search` WHERE `Search`.`online` = 1 AND `Search`.`content` 
RLIKE = 'le|raton|laveur'

ca semble grave, mais je vois pas où..

Canonier
Auteur

DOUBLE POST

J'ai finalement trouvé la solution !!
..en tout cas un code qui fonctionne..

Je le partage et attend vos commentaires pour l'améliorer, où.. je ne sais quoi.. si vous avez de meilleures idées quoi ^^

le bout de code :

$kw_table = explode(" ", $kw); 
    $i = 0;
    foreach ($kw_table as $mot) {
    if($i==0){
        $sql = "(`Search`.`content` LIKE '%$mot%'";
    }else{
        $sql .= " OR `Search`.`content` LIKE '%$mot%'";
    }
    $i++;
    }
    $sql .= ")";
    $results = $this->Search->find('all', 
        array('conditions' => array(
            'Search.online' => 1,
            'OR' => array( $sql )
        )));

et la tête de la requête sql pour une recherche type : 'le raton laveur'.

SELECT `Search`.`id`, `Search`.`name`, `Search`.`slug`, `Search`.`content`, `Search`.`online` 
FROM `database`.`contents` AS `Search` WHERE `Search`.`online` = 1 AND 
(`Search`.`content` LIKE '%le%' OR `Search`.`content` LIKE '%raton%' OR 
`Search`.`content` LIKE '%laveur%')

Merci ;)

Change ta requete condition:

en par exemple:

$results = $this->Search->find('all', 
    array('conditions' => array(
        "Search.online = 1", // <== différence ici
        "Search.content LIKE '%$sqlkws%'" // <<== différence ici
    ));

peut etre que cela pourra palier a ton soucis de guillemet.

Non, s'il fait ça, Cake va échapper les caractères et va sortir une requête qui cherche LIKE '%$sqlQWS%'.

Par contre, en y repensant à tête reposée, un truc du genre pourrait fonctionner :

$results = $this->Search->find('all', 
    array('conditions' => array(
        'Search.online' => 1,
        "Search.content LIKE" => '% '.$sqlkws.' %'
    ));
Canonier
Auteur

Ne manque t-il pas un jeu de guillemet autour des % ?

la requête risque de comprendre

Search.content LIKE %mot%

au lieu de

Search.content LIKE '%mot%'

EDIT: voici le résultat de la requete !..

...] AND `Search`.`content` = '% le %\' OR Search.content LIKE \'% raton %\' OR Search.content LIKE \'% laveur %'
$results = $this->Search->find('all', 
    array('conditions' => array(
        'Search.online' => 1,
        "Search.content RLIKE ".str_replace(' ', '|', $sqlkws)
    ));

Et comme ceci ?

Canonier
Auteur

non plus.. la requete ne se forme meme pas :

...] WHERE `Search`.`online` = 1 AND `Search`.`content` RLIKE // et la requete se stop

je pense que je vais me contenter de mon code plus haut qui fonctionne plutot bien ^^

ok si ca fonctionne c'est le principal, après perso je sais que j'avais déja utiliser les regexp dans mes requetes, je trouver ca plus flexible

$search = str_replace(' ', '|', $search)
$conditions = array('OR' => array(
                        'User.firstname REGEXP ' => $search,
                        'User.lastname REGEXP ' => $search
                    ));

Perso j'ai fait comme ca chez moi et ca fonctionne, mais bon comme je disais si ca fonctionne chez toi pas forcement la peine d'aller chercher plus loin ;)