Bonjour a tous,

Je viens sollicité votre aide après plusieurs échec de ma part.
J'essaie de mettre en place un système de recherche dans mon site cependant je n'arrive pas a avoir le résultat que je souhaite.

Ma recherche dois s'effectue sur plusieur table :
* articles => contient les produits et la categorie( category_id)
* users => contient les emplacements geographique ( state_id, province_id et city_id)
* categories => contient la liste des categories

J'effectue une requete GET depuis mon formulaire et debug($this->request->query) me retourne :

array(
    'name' => '',
    'state_id' => '',
    'province_id' => '',
    'city_id' => '',
    'category_id' => '',
    'price_min' => '',
    'price_max' => ''
)

Pour avoir la pagination sur le site, j'utilise Paginator.

Ma methode recherche ressemble a cela pour l'instant :

public function search(){
        $this->set('title_for_layout','Ewant - Recherche');
        if(!empty($this->request->query) && $this->request->is('get')){
            debug($this->request->query);
            $this->paginate = array(
                "ArticlesShopsUser" => array(
                    'limit' => 15,
                    'order' => array(
                        'Article.created' => 'desc'
                    ),
                    'conditions' => array(
                        'Article.online' => 1,
                        'Article.isValid'   => 1,
                        'OR' => array(
                            'Article.name LIKE' => '%'.trim($this->request->query'name']).'%'
                        )
                    )
            )
            );
            $articles = $this->Paginator->paginate('ArticlesShopsUser');
            debug($articles);
        }
    }

Je n'arrive pas a ajoute d'autre conditions, lorsque les différentes requêtes GET tel que state_id, province_id et city_id sont defini.

Un utilisateur a une region, un departement et une ville.
Les articles appartiennent seulement a une boutique.
Une boutique appartient a un et un seul utilisateur.

Du coup pour faire un système de recherche, je me demandais si il ne suffirait pas de rajouter dans articles le user_id ?

ArticlesShopsUser est une table qui comprend les trois tables (articles, shops et users).
Je souhaite éviter une récursivité à 2 pour les performances.

Si vous avez une petite idée de comment pourrais je sortir de ce petit blocage, je vous remercie d'avance :)

Cordialement AcidBrun.

19 réponses


antho07
Réponse acceptée

Bon c'est un peu dégueulasse mais le principe est là

public function search($get) {

    $prixMax = 99999999;
    $prixMin = 0;

    if(!empty($get'price_max'])){
        $prixMax = h($get'price_max']);
    }

    if(!empty($get'price_min'])){
        $prixMin = h($get'price_min']);
    }
    $a = array(
        'AND' = > array(
            'Article.price BETWEEN ? AND ?' = > array($prixMin, $prixMax)
        )
    );

    foreach($get as $k => $v){
        if($k != 'name' && $k != 'price_max' && $k != 'price_min' && !empty($v)){
            if($k != 'category_id'){
                $a'AND']'User.'.$k] = h($v);
            }else{
                $a'AND']'Article.category_id'] = h($get'category_id']),
            }
        }
    }
   }
    if(getNameConditions($get)){
        $a'AND']'OR'] = getNameConditions($get);
    }
}

private function getNameConditions($get){
    if(empty($get'name'])){
    return false;
    }else{
        return array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            );
    }
}
Airday
Auteur

J'ai fait mes tests a cote et j'ai le résultat attendu, cependant le code est assez répétitif :

$get = $this - > request - > query;
if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']) && !empty($get'price_min']) && !empty($get'price_max'])) {
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array(h($get'price_min']), h($get'price_max']))
        )
    );
} else if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']) && !empty($get'price_min']) &&
    empty($get'price_max'])
) {
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array(h($get'price_min']), 99999999)
        )
    );
}
.....
.....
.....

Ca test pour different cas, si le category_id est vide ou non, si tout est vide sauf la recherche par prix etc....

Si vous avez une methode qui pourrais me faire passer de 500 lignes à 100, je vous serai tres reconnaissant ;)

Cordialement AcidBrun

Airday
Auteur

:'(

Bonjour, pourrais-tu repréciser les tables , leur champs et les liaisons à faire entre elles? je m'y perds dans ton premier post..

cordialement

Airday
Auteur
array(
    'Article.name' => '',
    'Article.category_id' => '',
    'User.state_id' => '',
    'User.province_id' => '',
    'User.city_id' => '',
     // BETWEEN de Article.price
    'price_min' => '',
    'price_max' => ''
)

T'avais pas une histoire de boutiques aussi ?

Airday
Auteur

Ouais mais au final ça ne sert a rien la boutique.

Avec mes tonnes de conditions, je suis parvenu a 600 - 700 lignes juste pour faire une recherche avec les champs recuperer via $this->request->query.
Je trouve mon code assez repetitif et aussi lourd, car je ne m'y retrouve plus trop, en tout cas cela renvoi bien le resultats de la recherce.

Sauf que maintenant

if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']) && !empty($get'price_min']) && !empty($get'price_max'])) {
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array(h($get'price_min']), h($get'price_max']))
        )
    );
}

Ce code la a du être répété une dizaine de fois. Mais maintenant je ne sais pas comment l'alleger.
Il dois surement exister une astuce que j'ai pas encore acquise pour passer de 600 - 700 lignes a 50 - 100 lignes, :p

J'ai du mal à visualiser ce que tu veux faire..

Quels sont les champs de recherche obligatoires et ceux qui ne le sont pas?

Airday
Auteur

Tu vois le site "Leboncoin", ils ont un formulaire de recherche qui cherche seulement lorsque certain champs ne sont pas vides.
Hey bien sur mon projet je dois faire un formulaire de recherche dans le même style.

'name' => '', //Obligatoire ou Non?
'state_id' => '',//Obligatoire ou Non?
'province_id' => '',//Obligatoire ou Non?
'city_id' => '',//Obligatoire ou Non?
'category_id' => '',//Obligatoire ou Non?
'price_min' => '',//Obligatoire ou Non?
'price_max' => ''//Obligatoire ou Non?

Airday
Auteur

Pour moi, ils sont tous obligatoires dans certaines conditions.

Donc ils ne le sont pas tous le temps.. Quels sont ceux obligatoire (je veux dire sans conditions, ils doivent être remplies) et ceux qui sont optionnels?

Airday
Auteur

Juste avec ton intervention, je viens d'enlever pas mal de lignes :p

Premiere recherche cela peut donner :
'name' => '', //Obligatoire
'state_id' => '',//Obligatoire
'province_id' => '',//Obligatoire
'city_id' => '',//Obligatoire
'category_id' => '',//Obligatoire
'price_min' => '',//Obligatoire
'price_max' => ''//Obligatoire

Deuxieme recherche cela peut donner :
'name' => '', //Non Obligatoire
'state_id' => '',//Obligatoire
'province_id' => '',//Non Obligatoire
'city_id' => '',//Non Obligatoire
'category_id' => '',//Obligatoire
'price_min' => '',//Obligatoire
'price_max' => ''//Non Obligatoire

Merci :)

Première recherche et deuxième recherche??
Tu gardes en mémoire la première recherche lors de l'exécution de la 2eme?

Airday
Auteur

Je ne garde rien en mémoire c’était un exemple, pour dire que si certains champs sont obligatoires c'est qu'ils étaient pas vides et contenait des informations. Et ainsi il fait la recherche dans la base de donnée pour me renvoyer le résultat avec les informations qu'il a reçu.

Un autre exemple de gain de place (sous réserves des réponses aux questions précédentes)

ICI: il n'a que la valeur prix qui est soit vide soit rempli

if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']) && !empty($get'price_min']) && !empty($get'price_max'])) {
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array(h($get'price_min']), h($get'price_max']))
        )
    );
} else if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']) && !empty($get'price_min']) &&
    empty($get'price_max'])
) {
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array(h($get'price_min']), 99999999)
        )
    );
}

DEVIENT (je ne sais pas ce qu'est la fonction h mais peu importe , même soyons fou on fait prixmin)

if (!empty($get'name']) && !empty($get'state_id']) && !empty($get'province_id']) && !empty($get'city_id']) && !empty($get'category_id']))) {
$prixMax = 99999999;
$prixMin = 0;
if(!empty($get'price_max'])){
$prixMax = h($get'price_max']);
}
if(!empty($get'price_min'])){
$prixMin = h($get'price_min']);
}
    $a = array(
        'AND' = > array(
            'OR' = > array(
                'Article.name LIKE' = > "%".h($get'name']).
                "%",
                'Article.content LIKE' = > "%".h($get'name']).
                "%",
            ),
            'User.state_id' = > h($get'state_id']),
            'User.province_id' = > h($get'province_id']),
            'User.city_id' = > h($get'city_id']),
            'Article.category_id' = > h($get'category_id']),
            'Article.price BETWEEN ? AND ?' = > array($prixMin, $prixMax)
        )
    );
}

Oui mais dans tes paramètres, quels sont ceux obligatoire pour la requête en base.. ceux que le client est obligé de remplir?

je sais pas, par exemple vu le morceau de requête que tu as écris, on voit que le prix est un élément de recherche optionnel pour l'utilisateur.

Obligatoire: si non rempli => pas de recherche possible

Optionnel: rempli =>prix en compte, non rempli => pas bloquant, la recherche ne comprendra pas ces précisions voilà tout.

Airday
Auteur

Là, je comprend mieux, alors ils sont tous optionnel, desole j'ai ete confu xD

h() => Raccourci pour htmlspecialchars();

Airday
Auteur

Merci de ton aide Antho, ta technique est plutot pas mal et prend pas beaucoup de place, je vais l'optimiser pour le rendre plus performant ;)