Fonction de filtrage sur carte PHP

Résolu/Fermé
Nobody - 9 févr. 2023 à 15:49
 Nobody - 13 févr. 2023 à 16:40

Bonjour, Je suis en train de faire une fonction qui va permettre de filtrer et d'ajouter des points sur une carte (plugin Leaflet).

Les filtres sont 3 select html(à choix multiple). Ça marche donc presque bien mais j'ai un problème évidemment je voudrais pouvoir utiliser ces filtres aussi bien indépendamment ou ensemble.

Je m'explique la variable $filtrefinal est une concaténation de $etat, $type_alerte et $departement qui représente mes 3select html donc si une de ces variables n'est pas renseigné ce n'est pas grave tant qu'il y en a au moins une sur les 3 $filtrefinal existe sinon $filtrefinal est vide et donc ne changera pas ma requête de base.

Et mon problème c'est que pour que les filtres $departement et $type_alerte fonctionne il faut que $etat soit renseigné alors que $etat lui n'a pas besoin de $departement ou $type_alerte.

Jsp si je suis clair mais en gros un filtre dynamique.

Ma fonction php :

public function mapFilter($etat, $departement, $type_alerte) {

        if (!empty($etat)) {
            for ($i = 0; $i < count($etat); $i++) {
                if($i >= 1 ) {
                    $etat2 .= " OR ";
                    $etat2 .= "clos = " . htmlentities($etat[$i]);

                } else {
                    $etat2 = "clos = " . htmlentities($etat[$i]);
                }
            }

        } else {
            $etat2 = htmlentities($etat);
        }

        if ($departement == '') {
            $departement2 = '';
        } else {
            if(isset($etat)) {
                $departement2 = ' AND (';
            }
            else {
                $departement2 = ' (';
            }
            
            for ($i = 0; $i < count($departement); $i++) {
                $departement2 .= "nom_d = '" . htmlentities($departement[$i]) . "' OR ";
            }
            $departement2 = substr($departement2, 0, -4);
            $departement2 .= ')';
        }

        if (!empty($type_alerte)) {
            if(isset($etat) || isset($departement)) {
                $type_alerte2 = ' AND (';
            }
            else {
                $type_alerte2 = ' (';
            }
            for ($i = 0; $i < count($type_alerte); $i++) {
                $type_alerte2 .= " type_alerte = '" . htmlentities($type_alerte[$i]) . "' OR ";
            }
            $type_alerte2 = substr($type_alerte2, 0, -4);
            $type_alerte2 .= ')';
        } else {
            $type_alerte2 = htmlentities($type_alerte);
        }

        var_dump($type_alerte);
        var_dump($departement);

        $filtrefinal = $etat2. $departement2. $type_alerte2;

        var_dump($filtrefinal);

        if($filtrefinal != "" ) {
            $filtrefinal .= " AND ";
        }

        $req = $this->getBdd()->prepare(
            "SELECT nom, latitude, longitude, dates_heures_alarme, type_alerte, reference_derco, clos
            FROM problemecity as pc
            LEFT JOIN city as c
            ON pc.city_id_id = c.id
            LEFT JOIN probleme as p
            ON pc.pb3_id = p.id
            LEFT JOIN dep as d 
            ON c.dep_id = d.id
            WHERE ". $filtrefinal."latitude IS NOT NULL"
            );
            var_dump($req);
            $req->execute();
            $allVilleEtat = $req->fetchAll(PDO::FETCH_ASSOC);
            $req->closeCursor();
            return $allVilleEtat; 
            
    }

Exemple d'utilisation :

Quand je sélectionne le département ici le Calvados et un état, ici "En cours", ça fonctionne bien et mon affichage sur la carte est bon et ma requête aussi, var_dump($req) :

 object(PDOStatement)#12764 (1) { ["queryString"]=> string(424) "SELECT nom, latitude, longitude, dates_heures, type_alerte, ref, clos FROM problemecity as pc LEFT JOIN city as c ON pc.city_id = c.id LEFT JOIN probleme as p ON pc.pb3_id = p.id LEFT JOIN dep as d ON c.departement_id = d.id WHERE clos = 0 AND (nom_d = 'calvados') AND latitude IS NOT NULL" } 

var_dump($filtrefinal) :  string(33) "clos = 0 AND (nom_d = 'calvados')"

Maintenant quand je sélectionne uniquement le département toujours calvados mon affichage sur ma crate et ma requête de base sans le $filtrefinal, le var_dump($req) : 

object(PDOStatement)#12764 (1) { ["queryString"]=> string(386) "SELECT nom, latitude, longitude, dates_heures_alarme, type_alerte, reference_derco, clos FROM problemecity as pc LEFT JOIN city as c ON pc.city_id = c.id LEFT JOIN probleme as p ON pc.pb3_id = p.id LEFT JOIN dep as d ON c.departement_id = d.id  WHERE latitude IS NOT NULL" } 

var_dump($filtrefinal) : string(0) ""

Voilà on voit bien que dans la deuxième requête il ignore $filtrefinal et je ne sais pas pourquoi la concaténation ne se fait c'est la même chose avec le type d'alerte ça ne fonctionne pas non plus.

Si quelqu'un sait je suis preneur, merci d'avance !

A voir également:

7 réponses

yg_be Messages postés 22732 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 28 avril 2024 1 477
9 févr. 2023 à 16:19

bonjour,

Si je comprends bien, tu souhaites que, pour ta seconde requête, $filtrefinal contienne du texte.  Quel texte?

0
yg_be Messages postés 22732 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 28 avril 2024 1 477
9 févr. 2023 à 16:28

Ta ligne 15 me semble suspecte.
A ta place, je ferais, après la ligne 54, des var_dump des variables $etat2, $departement2, $type_alerte2.

0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650
Modifié le 9 févr. 2023 à 16:35

Bonjour,

Pour commencer,  je pense que tu peux remplacer

 if (!empty($etat)) {
            for ($i = 0; $i < count($etat); $i++) {
                if($i >= 1 ) {
                    $etat2 .= " OR ";
                    $etat2 .= "clos = " . htmlentities($etat[$i]);

                } else {
                    $etat2 = "clos = " . htmlentities($etat[$i]);
                }
            }

        } else {
            $etat2 = htmlentities($etat);
        }

par simplement une écriture ternaire et du join ..

$etat2 = !empty($etat) ? " clos IN ('" . join("','",$etat) . "') " : "";

Puis, en te basant sur cet exemple .. faire pareil avec tes deux autres conditions

/!\ htlmentities , htmlspacialchars .. sont des fonctions à utiliser UNIQUEMENT pour de l'affichage ... pas pour du "pré-traitement" des variables pour une requête sql;...


0

Merci de vos retours,

je vais essayer vos deux propositions et je vous fait un retour demain 

0

Re j'i capté d'où venait le problème en fait c'était un niveau de l'appel de ma fonction tout simplement j'avais oublié un truc : 

de base : 

if (isset($_POST['etat'])) {
            $donneesEtat = $this->Manager->mapFilter($_POST['etat'], $_POST['departement'], $_POST['type_alerte']);
        } else {
            $donneesEtat = $this->Manager->mapFilter(null, null, null);
        }

correction : 

if (isset($_POST['etat']) || isset($_POST['departement']) || isset($_POST['type_alerte'])) {
            $donneesEtat = $this->Manager->mapFilter($_POST['etat'], $_POST['departement'], $_POST['type_alerte']);
        } else {
            $donneesEtat = $this->Manager->mapFilter(null, null, null);
        }

Mais j'ai un autre problème de requête que je ne sais comprendre : 

"SELECT nom, latitude, longitude, dates_heures_alarme, type_alerte, reference_derco, clos FROM problemecity as pc LEFT JOIN city as c ON pc.city_id = c.id LEFT JOIN probleme as p ON pc.pb3_id = p.id LEFT JOIN dep as d ON c.departement_id = d.id  WHERE  clos = 0 OR clos = 1 AND (nom_d ='orne') latitude IS NOT NULL"

Et sur ma carte ça met des points sur les départements qui ne sont pas dans l'Orne (c'est le var_dump($req) au dessus) je teste aussi sur phpMyAdmin c'est donc ma requête qui n'est pas bonne une idée de pourquoi ma requête me ressort des villes qui sont dans un autre département que celui que j'ai dans mon select ?

0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650 > Nobody
10 févr. 2023 à 15:48

Visiblement tu n'as pas tenu compte de ma précédente remarque et il semble qu'il manque une condition and devant le mot latitude

0
yg_be Messages postés 22732 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 28 avril 2024 1 477 > Nobody
10 févr. 2023 à 15:48

Je suppose qu'il manque une partie de ta clause WHERE.

clos = 0 OR clos = 1 AND (nom_d ='orne') latitude IS NOT NULL

Quand tu écris 

A OR B AND C

C'est équivalent à

A OR (B and C)

Alors que tu veux probablement obtenir

(A OR B) AND C

En cas de doute sur la priorité des opérateurs, n'hésite pas à mettre des parenthèses.

0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650 > yg_be Messages postés 22732 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 28 avril 2024
10 févr. 2023 à 15:51

En utilisant, comme je lui ai déjà suggéré ,  des  IN()  au lieu de multiplier les OR  il limitera ce genre de soucis..

0
Nobody > jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024
10 févr. 2023 à 16:11

J'ai pas compris ton code la ternaire ok mais le join je ne connais pas de plus IN pour mon champ clos qui est un entier ne va pas fonctionné non ? Il faut un = ?

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question

En effet ça à l'air pas mal avec la solution de jordane45 :

$etat2 = !empty($etat) ? " clos IN ('" . join("','",$etat) . "') " : "";

        if(!empty($departement)) {
            if(isset($etat)) {
                $departement2 = ' AND ';
            }
            else {
                $departement2 = '';
            }
            $departement2 .= !empty($departement) ? " nom_d IN ('" . join("','",$departement) . "') " : "";
        }
        else {
            $departement2 ="";
        }
        

        if (!empty($type_alerte)) {
            if(isset($etat) || isset($departement)) {
                $type_alerte2 = ' AND ';
            }
            else {
                $type_alerte2 = '';
            }
            $type_alerte2 .= !empty($type_alerte) ? " type_alerte IN ('" . join("','",$type_alerte) . "') " : "";
        }
        else {
            $type_alerte2 = "";
        }

$filtrefinal = $etat2. $departement2. $type_alerte2;
...
0
yg_be Messages postés 22732 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 28 avril 2024 1 477
13 févr. 2023 à 12:24

Je ne suis pas surpris, il est en général de bon conseil.

0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650
Modifié le 13 févr. 2023 à 12:26

remplace ton code par ça

$filtres = [];

$filtres[] = !empty($etat) ? " clos IN ('" . join("','",$etat) . "') " : "";
$filtres[] = !empty($departement) ? " nom_d IN ('" . join("','",$departement) . "') " : "";
$filtres[] = !empty($type_alerte) ? " type_alerte IN ('" . join("','",$type_alerte) . "') " : "";


$filtrefinal = !empty($filtres) ? join (" AND " , $filtres ) : "";
0
Nobody > jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024
13 févr. 2023 à 13:41

J'ai essayé et ça me met un AND en trop : 

 $filtres = [];

        $filtres[] = !empty($etat) ? " clos IN ('" . join("','",$etat) . "') " : "";
        $filtres[] = !empty($departement) ? " nom_d IN ('" . join("','",$departement) . "') " : "";
        $filtres[] = !empty($type_alerte) ? " type_alerte IN ('" . join("','",$type_alerte) . "') " : "";


        $filtrefinal = !empty($filtres) ? join (" AND " , $filtres ) : "";


$req = $this->getBdd()->prepare(
            "SELECT nom, latitude, longitude, dates_heures_alarme, type_alerte, reference_derco, clos
            FROM [...]
            WHERE ". $filtrefinal."(latitude IS NOT NULL)"
            );
            var_dump($req);
            $req->execute();
            $allVilleEtat = $req->fetchAll(PDO::FETCH_ASSOC);
            $req->closeCursor();
            return $allVilleEtat; 
            

var_dump de $req et l'erreur pdo : 

Quand je sélectionne uniquement $etat et que je sélectionne en cours et clos :

SELECT nom, latitude, longitude, dates_heures_alarme, type_alerte, reference_derco, clos FROM [...] WHERE clos IN ('0','1') AND AND (latitude IS NOT NULL)" }

Warning: PDOStatement::execute(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'AND (latitude IS NOT NULL)' at line 9 in C:\Applications\wamp64\www\portail\models\Manager.class.php on line 1500
0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650 > Nobody
13 févr. 2023 à 14:43

oui, désolé,

plutôt 

$filtres = [];

if(!empty($etat)){
  $filtres[] =  " clos IN ('" . join("','",$etat) . "') " ;
}

if(!empty($departement)){
  $filtres[] =  " nom_d IN ('" . join("','",$departement) . "') " ;
}

if(!empty($type_alerte)){
  $filtres[] =  " type_alerte IN ('" . join("','",$type_alerte) . "') ";
}

$filtrefinal = !empty($filtres) ? join (" AND " , $filtres ) : "";
0

Ouais la ça marche beaucoup mieux, merci 

Dernière question j'ai toujours cette erreur "undefined index" quand je ne renseigne pas un des select qui vient de mon controller où j'appel ma fonction : 

 if (isset($_POST['etat']) || isset($_POST['departement']) || isset($_POST['type_alerte'])) {
            $donneesEtat = $this->Manager->mapFilter($_POST['etat'], $_POST['departement'], $_POST['type_alerte']);
        } else {
            $donneesEtat = $this->Manager->mapFilter("", "", "");
        }

Au début j'avais mis (null, null, null) et la avec les guillemets vide je pensait que ça marcherait mais non

0
jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650
13 févr. 2023 à 15:36
//on récupère PROPREMENT les variables AVANT de les utiliser
$etat = !empty($_POST['etat']) ? $_POST['etat']: "";
$departement = !empty($_POST['departement']) ? $_POST['departement']: "";
$type_alerte = !empty($_POST['type_alerte']) ? $_POST['type_alerte']: "";

$donneesEtat = $this->Manager->mapFilter($etat, $departement, $type_alerte);
0

Super, merci bcp !

0