Bonjour à tous,
Je viens de commencer en local une petite webapplication de gestion.
j'utilise PDO et j'aimerai informer proprement et clairement l'utilisateur
(c'est à dire moi ou mon collègue) du pourquoi du non fonctionnement
de telle ou telle action.
En clair, comment récupérer l'erreur et afficher un message dans les
cas suivants :

  • Doublon du nom du fournisseur dans la base,
  • Suppression fournisseur impossible car possède un lien avec la tables factures
    (déjà une facture pour ce fournisseur),
  • Vente produit impossible car quantité suppérieure au stock existant, etc...
try {
    // Préparation de la requete :
    $requete = $bdd->prepare('INSERT INTO fournisseurs(nom_fournisseur, rue_fournisseur, cp_fournisseur, ville_fournisseur) VALUES(:nom_fournisseur, :rue_fournisseur, :cp_fournisseur,:ville_fournisseur)');
        $requete->execute(array(
            'nom_fournisseur' => $nom_fournisseur,
            'rue_fournisseur' => $rue_fournisseur,                    
            'cp_fournisseur' => $cp_fournisseur,
            'ville_fournisseur' => $ville_fournisseur
        ));
}
catch (PDOException $e){
    echo 'L\'ajout du fournisseur a échoué !' . '<br />';
    echo 'Erreur : '.$e->getMessage();
}

Et éviter ce genre de message :
L'ajout du fournisseur a échoué !
Erreur : SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'SARL MACHIN TRUC' for key 'nom_fournisseur'

Merci d'avance pour votre aide...

6 réponses


Salut,

La solution est assez simple, il te suffit de filtrer les messages d'erreur venant de MySQL et d'afficher ton propre message dans les cas qui t'interesse.

Regarde du coté des codes d'erreur de MySQL, ce sera plus simple pour trouver les erreurs via un regexp qui checkera $e->getMessage() ou simplement récupérer le code via $e->getCode().

Un exemple ici: http://stackoverflow.com/a/5441494

Je dit pas que c'est la meilleur méthode, mais s'en est une, à toi de voir et de réfléchir à comment tu veux implementer ça.

Merci pour ton tuyau elhebert...
J'ai placé une contrainte de clé étrangère sur mon champ id_fournisseur dans ma table factures.
J'empèche la suppression du fournisseur (dans la table fournisseurs) qui possède encore des factures de cette manière :

if (isset($_GET['id'])) {
    $id = $_GET['id'];
    try {
        // Préparation de la requète : 
        $req = "DELETE FROM fournisseurs WHERE id_fournisseur='$id'";
        $req = $bdd->query($req);
        $message='Le fournisseur a bien été supprimé...';
    }
    catch (PDOException $e){
        $erreur = explode(':', $e->getMessage());
        if($erreur[2]==1451){
            echo 'Ce fournisseur possède encore des factures dans la base de données, il ne peut etre supprimé !';
        }
        else {
            echo $e -> getMessage();
        }
    }
}

Est-ce propre ?

Sachant que l'erreur retournée est :
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (gescom.factures, CONSTRAINT factures_ibfk_1 FOREIGN KEY (id_fournisseur) REFERENCES fournisseurs (id_fournisseur))

est-ce juste d'écrire cela : if($erreur[2]==1451)
Je veux dire ma commande récupère t-elle uniquement 1451 dans le message complet d'erreur ?

Tu devrais essayer avec le $e->getCode() ce sera plus propre et demandera moins de ressource qu'un explode ;)

je te suggère de regarder ici pour plus d'infos: http://php.net/manual/fr/class.pdoexception.php

catch(Exception $e) {
        echo "Le code de l'exception est : " . $e->getMessage();
    }

Le problème c'est que je n'ai aucune idée du code php à créer pour récupérer le code exact de l'erreur.
Je récupère bien un 23000 pour une impossibilité à supprimer des données pour cause de contrainte
d'une clé étrangère mais également un 23000 pour une violation de clé unique ! J'ai l'impression que
quelque soit l'erreur , je tombe sur un 23000 ! Je ne peux donc pas personnaliser mon message
d'erreur !
Je pense qu'il faudrait plutôt utiliser un regexp (que je ne connais que de nom) comme tu le conseillais
pour récupérer un 1062 en cas de doublon ou un 1451 en cas de liaison avec une clé étrangère !
Ces codes ne sont ils pas stockés quelque part directement ailleurs que dans $e->getMessage() et donc
directement récupérables ?

Merci d'avance !

Bonsoir,

Je sais que je déterre un vieux topic, mais votre échange m'a aidé et voici moi ce que j'ai fait :

    catch (PDOException $e)
    {        
        $ErrorExplode = explode(': ', $e->getMessage());
        //$Error = $ErrorExplode[0]; //inutile correspond à getCode();
        $ErrorCode = $e -> getCode();
        $Error = $ErrorExplode[1];
        unset($ErrorExplode[0]);
        unset($ErrorExplode[1]);
        $ErrorEnd = implode(" : ",$ErrorExplode);
        $ErrorExplode = explode(' ',$ErrorEnd);        
        $ErrorSQLCode = $ErrorExplode[0];
        unset($ErrorExplode[0]);
        $ErrorDescription = implode(" ",$ErrorExplode);
    }
  • Je récupère le code SQLState vu dans getMessage() proprement avec getCode()
  • J'explose la chaîne obtenu par getMessage(), caractère séparateur : le ":" avec un espace après
  • Je récupère l'erreur SQL contenu dans le 2e élément du tableau
  • Je retire le SQLState et l'erreur SQL de mon tableau et je le re-transforme en chaîne séparé par ":" avec un espace avant et après (pour ne pas abîmer la syntaxe de la description d'erreur de SQL)
  • J'explose la chaîne régénérée, caractère séparateur : " " un espace
  • Je récupère le code erreur SQL.
  • Je retire le code erreur SQL de mon tableau et je le re-transforme en chaîne séparé par " " un espace.
  • Je stocke cette nouvelle chaîne dans une variable pour la description de l'erreur SQL

J'obtiens donc 4 variables :

$ErrorCode // contient le code erreur SQLState
$Error     // contient la description de l'erreur SQLState
$ErrorSQLCode  // contient le code erreur SQL
$ErrorDescription // contient la description de l'erreur SQL

!! Attention pour que le catch fonctionne, il faut ajouter une information sur la connexion PDO :

    try 
    {   
        $DSN = 'mysql:host='.$dbserver.';port=3306;dbname='.$dbname.'';         
        $Connection = new PDO($DSN, $dbuser, $dbpass, array (PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''));
        $Connection->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 
        $Connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

       # print "Connection it's ok !";
    } 
    catch ( PDOException $e )
    {
        print "Erreur !: " . $e->getMessage() . "<br/>";
        die();
    } 

J'ai ajouté :

        $Connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Bye

Pour info, on peut maintenant se passer du SET NAME 'UTF8' en rajoutant ;charset=utf8 dans la chaine de connexion