IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

Composition de requête avec PDO


Sujet :

PHP & Base de données

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut Composition de requête avec PDO
    Bonjour,

    J'ai une fonction de requête avec PDO. Les critères de requêtes proviennent d'un formulaire. Je n'ai pas voulu alourdir en mettant le code du formulaire mais si vous en avez besoin, je vous le donnerai.

    J'ai deux soucis:
    • La valeur 0 lorsqu'elle est toute seule n'est pas prise en compte dans le code postal ce qui est gênant pour les pays où les codes postaux sont affectés géographiquement.
    • Les critères de sélection de plage (min et max) ne fonctionnent pas. Si l'un des deux critères est renseigné le résultat de la requête est vide.

    Voici la fonction de traitement du formulaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function thisFilter() {
    	$_POST = array_map('strip_tags', $_POST);
    	$criteria = empty($_POST) ? []: $_POST;
     
    	// Elimination des champs qui ne sont pas des critères de sélection
    	foreach ($criteria as $key=>$value) {
    		if (in_array($key, ['filter', 'home'])) unset($criteria[$key]);
    	}
    	unset($key, $value);
     
    	// Suppression des critères vides
    	foreach ($criteria as $key=>&$value) {
    		if ( empty($criteria[$key]) ) { unset($criteria[$key]); }
    	}
     
    	return getAddresses($criteria);
    }
    Et la composition de la requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    function getAddresses($criteria = []) {
    	global $db, $language;
    	$countryCol	= $language.'_name';
    	$select = "
    		SELECT a.id, nom, prenom, $countryCol AS pays, cp, ville,
    			courriel, tel_domicile, tel_portable
    		FROM dat_addresses a
    			LEFT JOIN lst_countries c
    				ON a.pays=c.id
    		";
     
    	// Composition de la clause WHERE et du tableau des paramètres
    	print_r($criteria); echo '<br/>';
    	$addClauses[0]		= "id_user=:id_user";
    	$params['id_user']	= $_SESSION['user']['id_user'];
    	if ($criteria) {
    		if ( !empty($criteria['min']) and empty($criteria['max']) ) {
    			$criteria['max'] = '%';
    		}
    		if ( !empty($criteria['max']) and empty($criteria['min']) ) {
    			$criteria['min'] = '_';
    		}
    		if ( isset($criteria['min'], $criteria['max']) ) {
    			$addClauses[] = "nom BETWEEN :min AND :max";
    			$params['min'] = $criteria['min'];
    			$params['max'] = $criteria['max'];
    		}
    		if ( !empty($criteria['pays']) ) {
    			$addClauses[] = "pays=:pays";
    			$params['pays']= $criteria['pays'];
    		}
    		if ( !empty($criteria['cp']) ) {
    			$addClauses[] = "cp LIKE :cp";
    			$params['cp']= $criteria['cp'].'%';
    		}
    		if ( !empty($criteria['ville']) ) {
    			$addClauses[] = "ville LIKE :ville";
    			$params['ville']= $criteria['ville'].'%';
    		}
    		print_r($addClauses); echo '<br/>';
    	}
    	$strWhere = "WHERE " . implode(' AND ', $addClauses);
    	// Requête globale
    	$query = $select . $strWhere . " ORDER BY nom, prenom";
    	echo $query, '<br/>';
    	print_r($params); echo '<br/>';
    	// Traitement
    	$result = $db->prepare($query);
    	$result->execute($params);
    	return $result->fetchAll();
    }

  2. #2
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut,

    n'oublie pas que empty() renvoie true quand la valeur testée est égale à zéro. Regarde ici. Donc si ta valeur peut être zéro alors ce n'est pas empty() qu'il faut utiliser
    Ce code est inutile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $_POST = array_map('strip_tags', $_POST);
    $criteria = empty($_POST) ? []: $_POST;
    $_POST est toujours défini (vide ou pas) et strip_tags est non compatible avec l'encodage unicode.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Le minimum est de MONTRER les éléments du code du formulaire HTML, en rapport avec la(les) problématique(s).

    Tu parles de min/max (par exemple) : on ne sait pas comment c'est appliqué.


    Citation Envoyé par rawsrc Voir le message
    strip_tags est non compatible avec l'encodage unicode.
    @rawsrc
    Ah bon ? (strip_tags)

    Tu as un exemple ?

  4. #4
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut jreaux62

    effectivement, si la chaîne est encodée correctement en UTF-8 (pas UTF-16 ou UTF-32), strip_tags() est compatible UTF-8 dans la mesure ou aucun autre caractère UTF-8 ne contient la séquence encodant le < et le >.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Merci pour votre aide.
    n'oublie pas que empty() renvoie true quand la valeur testée est égale à zéro
    Je le savais mais je me suis laissé surprendre, d'autant qu'ailleurs c'était bien empty qu'il fallait que j'utilise (pas de chaîne vide, pas de 0).
    Le problème du code postal est donc réglé et fonctionne.
    Par contre, il me reste le fonctionnement entre les bornes min et max. Le résultat est vide si:
    • L'une des bornes n'est pas renseignée,
    • La borne de fin ('max') commence par la même lettre que celle de début ('min'). Exemple min='b', max='bi'.

    Je suppose que ce sont les jokers qui sont mal utilisés mais je ne vois pas comment faire.
    Je n'ai trouvé aucune explications sur la compatibilité de strip_tags avec l'encodage UTF-8.
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	<form method="post" action="">
    		<fieldset><legend>Filtre</legend>
    			<label for="min" class="short">De</label><input type="text" name="min" id="min" placeholder="a" />
    			&nbsp;<label for="max" class="short">à</label><input type="text" name="max" id="max" placeholder="z" /><br/>
    			<label for="pays">Pays</label><select name="pays" id="pays"><option></option><option value="AL">Albanie</option><option value="FR" selected="selected">France</option><option value="CZ">Tchèque, République </option></select><br/>
    			<label for="cp">Code postal</label><input type="text" name="cp" id="cp" /><br/>
    			<label for="ville">Ville</label><input type="text" name="ville" id="ville" /><br/>
    			<p><input type="submit" name="filter" value="Filtrer" /> <input type="submit" name="home" value="Accueil" formaction="home.php" /></p>
    		</fieldset>		
    	</form>

  6. #6
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    On parle bien de ce code pour les bornes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if ( isset($criteria['min'], $criteria['max']) ) {
    	$addClauses[] = "nom BETWEEN :min AND :max";
    	$params['min'] = $criteria['min'];
    	$params['max'] = $criteria['max'];
    }
    J'ignorais qu'on pouvait utiliser BETWEEN pour des chaines.
    Cela dit, le fait que tes 2 bornes commencent par la même lettre n'a a priori pas d'impact, tant que le texte est effectivement entre les deux mots
    Par exemple : "bi" est entre "b" et "bu", mais pas "bien".
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Je suis content de t'avoir appris quelque chose, c'est tellement souvent l'inverse
    Oui tu parles bien du bon code auquel il faut ajouter le précédent qui définit les jokers (1) lorsqu'une des bornes n'est pas renseignée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    		if ( !empty($criteria['min']) and empty($criteria['max']) ) {
    			$criteria['max'] = '%';
    		}
    		if ( !empty($criteria['max']) and empty($criteria['min']) ) {
    			$criteria['min'] = '_';
    		}
    (1) C'est bien pour pouvoir accepter 'bien' entre 'b' et 'bu' que j'utilise des caractères jokers mais cela ne marche pas.

    EDIT: J'ai aussi penser à remplacer, lorsqu'ils ne sont pas définis, le minimum par la première entrée de la table triée et le maximum par la dernière mais ça me paraît très lourd et je ne suis pas sûr du résultat.

  8. #8
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut,

    sauf erreur, ton code peut se résumer à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    function getAddresses() {
        $criteria = array_diff_key($_POST, ['filter' => true, 'home' => true]);
        $criteria = array_filter($criteria, function($p) { return (bool)mb_strlen($p); });
     
        $where              = ['id_user = :id_user'];
        $values[':id_user'] = $_SESSION['user']['id_user'];
     
        if (isset($criteria['min'])) {
            $where[]        = 'nom >= :min';
            $values[':min'] = $criteria['min'];        
        }
        if (isset($criteria['max'])) {
            $where[]        = 'nom <= :max';
            $values[':max'] = $criteria['max'];
        }
        if (isset($criteria['pays'])) {
            $where[]         = 'pays = :pays';
            $values[':pays'] = $criteria['pays'];
        }
        if (isset($criteria['cp'])) {
            $where[]       = 'cp LIKE :cp';
            $values[':cp'] = $criteria['cp'].'%';
        }
        if (isset($criteria['ville'])) {
            $where[]          = 'ville LIKE :ville';
            $values[':ville'] = $criteria['ville'].'%';
        }
     
        global $db, $language;
     
        $sql = <<<sql
    SELECT a.id, nom, prenom, {$language}_name AS pays, cp, ville, courriel, tel_domicile, tel_portable
      FROM dat_addresses a
           LEFT JOIN lst_countries c ON a.pays = c.id
    sql;
     
        $sql .= ' WHERE '.implode(' AND ', $where).' ORDER BY nom, prenom';
     
        $stmt = $db->prepare($sql);
        $exec = $stmt->execute($values);
        return $exec->fetchAll();
    }
    comme toujours ça sort du four, rien n'est testé...

  9. #9
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par rawsrc Voir le message
    Salut jreaux62

    effectivement, si la chaîne est encodée correctement en UTF-8 (pas UTF-16 ou UTF-32), strip_tags() est compatible UTF-8 dans la mesure ou aucun autre caractère UTF-8 ne contient la séquence encodant le < et le >.
    @rawsrc
    Merci pour la précision (je n'ai jamais employé UTF-16 ou UTF-32)

  10. #10
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Pour l'instant, je n'ai pas tout testé. J'ai juste remplacé la clause BETWEEN par les comparaisons <= et >=.
    Le fonctionnement est bon pour le minimum. Pour le maximum, la borne est exclue (par exemple 'to' prend les tr... mais rejette les 'to...'. J'ai essayé de remplacer la clause par 'nom <= LIKE :max' ce qui provoque une erreur de syntaxe.

  11. #11
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut Bilan provisoire de cette discussion
    Je fais un bilan de cette discussion depuis #8.

    Tout d'abord merci pour l'aide que vous m'avez apportée. J'ai testé entièrement le code proposé par rawsrc.

    Ma question est résolue à 80% (4 critères sur 5) puisque j'ai toujours un problème avec la borne de fin (champ 'max'). Voir aussi #10. La valeur saisie dans ce champ n'est pas prise en compte dans la plage de résultats malgré le '=' de '<='.
    J'ai appris à utiliser les fonctions array_diff et array_filter même si j'ai encore des difficultés avec les fonctions de rappel. Si j'ai bien compris, le paramètre de la fonction de rappel, représente tour à tour chacun des éléments du tableau. Est-ce bien cela?
    Ton code comporte une erreur à la dernière ligne ($exec est un booléen).

    Si quelqu'un pouvait m'aider à résoudre le point restant ce serait super.

    EDIT: J'ai provisoirement résolu ce dernier point en ajoutant le dernier caractère de la table ASCII (254) à la variable $values['max'] mais c'est du bricolage et je ne sais pas ce que cela peut donner avec l'encodage UTF-8.

  12. #12
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    Citation Envoyé par moimp Voir le message
    j'ai toujours un problème avec la borne de fin (champ 'max'). Voir aussi #10. La valeur saisie dans ce champ n'est pas prise en compte dans la plage de résultats malgré le '=' de '<='.
    Tu parles du fait que "bien" n'est pas remonté avec "bi" comme borne max ? C'est normal parce que "bien" est après "bi" dans l'ordre alphabétique.
    Tu peux contourner en utilisant un substr (ou équivalent) pour comparer uniquement les 1eres lettres du mot. Quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (isset($criteria['max'])) {
            $l = strlen($criteria['max'])
            $where[]        = " SUBSTR(nom, 0, $l) <= :max";
            $values[':max'] = $criteria['max'];
    }
    NB : à noter que selon l'encodage, il faudrait peut-être utiliser mb_strlen à la place que strlen
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  13. #13
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Pour une raison que je ne m'explique pas ta solution ne fonctionne pas. Les lignes sélectionnées commencent bien à 'min' mais ne s'arrêtent pas à 'max' mais à la fin de la table.
    Voir aussi le EDIT de #11.
    Un détail: Il n'y a pas d'espace devant SUBSTR car il fait double emploi avec celui de ' AND ' dans le implode de la fin.

Discussions similaires

  1. Incompréhension sur retour requête avec PDO
    Par flavors dans le forum Langage
    Réponses: 3
    Dernier message: 11/07/2016, 18h17
  2. [PDO] Création de requêtes génériques avec PDO
    Par beegees dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 01/02/2012, 13h49
  3. [PDO] Problème de requête avec PDO
    Par methos1435 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 25/10/2010, 02h39
  4. [MySQL] Mettre des conditions dans une requête mysql avec pdo
    Par shima5 dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 07/10/2010, 21h11
  5. [PDO] requête sql avec PDO impossible
    Par HALOMOTO dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 22/03/2009, 00h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo