Bonjour,
J'ai un problème d'insertion dans une base de données mysql en PDO.
Une insertion basique se faisant ainsi :
Bonjour,
Cette question a été posée sur StackOverflow, et apparemment le code doit être plus compliqué, et utiliser Coalesce() et Default(). Le code est facilement lisible :
https://stackoverflow.com/questions/2464535/preparing-a-mysql-insert-update-statement-with-default-values
@+JP
@hellomorld : hélas, non... It doesn't work. J'espérais une solution du style et j'en ai essayé plein, mais on dirait qu'on ne peut pas faire aussi simple avec PDO+prepare
@jaypee : Je suis tombé sur cette page aussi de stackoverflow... Le souci est le même : c'est qu'il faut connaître les colonnes à l'avance et...
En fait, je n'ai pas précisé... il faut que j'explique que c'est pour une classe : J'essayais de faire mon propre ORM (pour apprendre) et que j'utiliserais aussi en Ajax. Et je voulais pouvoir insérer des lignes complètement vides avec les valeurs par défaut de la base, le tout sans connaître au préalable les champs. (Donc seulement avec le nom de la table)
pour l'utiliser par ex. ainsi : $object->insert();
Le mieux que j'ai trouvé, c'est de préalablement extraire toutes les valeurs par défaut des colonnes de la table avec une première requête comme : $query = $this->db->prepare("SHOW COLUMNS FROM `$table`"), puis une requête pour trouver le prochain id de la table, puis d'extraire des listes des champs et de chaque valeur par défaut avec une dernière requête ($sql = "INSERT INTO `$this->table` ($fields) VALUES ($values)"; $this->db->prepare($sql)->execute();)
..Mais c'est vraiment batard de faire 3 requêtes pour insérer une ligne vide !
D'une manière ou d'une autre, si on veut se protéger contre l'injection SQL, il faut pouvoir accepter ou rejeter un couple (nom de colonne, valeur), et donc connaître les noms de colonne valides.
https://phpdelusions.net/pdo/sql_injection_example
Dans les premières versions de MS SQL Server, on pouvait attaquer la db à travers le champ "Username" de la page de login, il ne faut jamais négliger la sécurité.
C'est un peu la responsabilité de l'ORM de faire le "sale boulot" pour faciliter le travail du développeur final, alors une ou trois requêtes, où est le problème ?
Ensuite dans ton approche, il faut penser aussi aux implications de l'intégrité provisoire de la db, puisque la rangée vide peut être lue avant d'être complétée avec des valeurs, sauf si l'ORM. gère sa propre colonne "ready", et fait un "AND" implicite dessus.
Il y a un exemple unique de ce genre de "découverte" de la structure de la db par le code client, il s'agit des « Type Providers » de F# de Microsoft, repris plus tard par Scala. C'est une technologie de niche, peu connue. L'intérêt est qu'on peut "exposer" juste quelques colonnes au client et construire un service dessus sans besoin que le client en sache plus sur le reste de la db. La même db peut être vue comme une source de "Personne" pour une application, ou source de "Produit" pour une autre.
https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/
@+JP
Bon... Effectivement, après avoir fait un tout petit script en dehors de ma classe, ça fonctionne effectivement...
Je vais devoir creuser la raison du problème dans ma classe. Merci !
Le pattern qui est implémenté ici est l'ActiveRecord (popularisé par Ruby On Rails) et il existe déjà plusieurs bibliothèques PHP qui apportent ce pattern aux objets d'une appli. Même si le but est de ne pas les utiliser, on peut quand même s'en inspirer.
Dans le cas présent, ça veut dire que la compétence d'accès à la db peut être héritée d'une classe comme celle-là.
Ou alors, si la simplicité est une priorité, il faudrait initialiser l'objet PDO au niveau global (hors de la classe) en tant que singleton (pas d'autre instance permise), puis l'injecter dans le constructeur de l'objet de l'appli.
On peut en effet se heurter sans le savoir à un problème de licence qui ne permet qu'un seul accès à la bd, et toujours sans le vouloir, créer deux accès distincts par deux objets différents. C'est le but du singleton, que de s'assurer que tous les accès soient centralisés par un seul connecteur.
Une autre piste : En mode développement on peut essayer une requête, qui échoue, le code s'arrête immédiatement sans restituer les ressources systèmes allouées pour le test (des connexions). Il est important de l'enrober dans un try except, et s'assurer que la connexion de db est bien refermée après l'erreur.
@+JP
Propulsé par Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)