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 :

PDO avec JSON_INSERT pour insérer un nouvel élement


Sujet :

PHP & Base de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Juillet 2009
    Messages
    171
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 171
    Par défaut PDO avec JSON_INSERT pour insérer un nouvel élement
    Bonjour,

    J'ai une class pour les opérations insert, update, delete, quand j'utilise la méthode JSON_INSERT, la requête génère une erreur:

    Fatal error: Uncaught PDOException: SQLSTATE[22032]: <>: 3140 Invalid JSON text: "Missing a name for object member."
    at position 1 in value for column 'products.p_description'. in /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php:182 Stack trace:
    #0 /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php(182): PDOStatement->execute()
    #1 /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/json_update.php(30): Database->execute()
    #2 {main} thrown in /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php on line 182
    Le code du fichier CRUD.php:

    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
    public function update($table, $fields = [], $where = null)
    {
        $args    = [];
        foreach ($fields as $fk => $fv) :
            $fk = $this->strSafe($fk);
            $args[] .= $fk . ' = :' . $fk;
        endforeach;
     
        $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $args);
     
        if ($where != null) {
            $sql .= ' WHERE ' . $where;
        }
     
        $this->sql    = $sql;
    }
     
    public function execute()
    {
        return $this->stmt->execute(); // LIGNE 182
    }
    Pour insérer un nouvel élément "chipset" dans le champs "p_description" avec la valeur "Qualcomm" dans le fichier json_update.php:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    require_once 'CRUD.php';
     
    $upMemList = [
        'p_description' => "JSON_INSERT(`p_description` , '$.chipset' , 'Qualcomm')"
    ];
    $upOn = $dbh->update('products', $upMemList, 'id = :id');
    $dbh->prepare($upOn);
     
    foreach ($upMemList as $fk => $fv) :
        $dbh->bind($fk, $fv);
    endforeach;
    $dbh->bind('id', 2);
    $dbh->execute(); // LIGNE 30
    Structure de la table:

    Code SQL : 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
    --
    -- Table structure for table `products`
    --
     
    CREATE TABLE `products` (
      `id` int UNSIGNED NOT NULL,
      `p_name` varchar(50) DEFAULT NULL,
      `p_description` json DEFAULT NULL,
      `p_cat` int NOT NULL,
      `p_price` int NOT NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
     
    --
    -- Dumping data for table `products`
    --
     
    INSERT INTO `products` (`id`, `p_name`, `p_description`, `p_cat`, `p_price`) VALUES
    (1, 'TV1', '{\"p_usb\": \"2\", \"p_hdmi\": \"3\", \"chipset\": \"Qualcomm\", \"p_screen\": \"21\", \"resolution\": null}', 1, 3400),
    (2, 'TV2', '{\"p_usb\": \"3\", \"p_hdmi\": \"3\", \"p_screen\": \"43\", \"resolution\": null}', 1, 4500),
    (3, 'Computer1', '{\"p_usb\": \"2\", \"p_hdmi\": \"0\", \"chipset\": \"Qualcomm\", \"p_screen\": \"15\", \"resolution\": null}', 4, 7350),
    (4, 'TV3', '{\"ports\": {\"p_usb\": \"3\", \"p_hdmi\": \"2\"}, \"p_screen\": \"65\", \"resolution\": null}', 1, 9900),
    (5, 'TV4', '{\"ports\": {\"p_usb\": \"2\", \"p_hdmi\": \"2\"}, \"p_screen\": \"42\", \"resolution\": null}', 1, 3300);

  2. #2
    Expert confirmé
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 322
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 322
    Billets dans le blog
    17
    Par défaut
    Si j'ai bien compris, tu construis tes placeholders en vue de la préparation SQL.

    Mais dans ce cas tu ne peux pas ensuite passer en argument JSON_INSERT(...) car la fonction va être considérée comme une chaîne, et sera délimitée/échappée.

  3. #3
    Membre confirmé
    Inscrit en
    Juillet 2009
    Messages
    171
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 171
    Par défaut
    @Séb. Toutes les requêtes marchent bien, sauf les requêtes qui contiennent des fonctions comme JSON_INSERT, JSON_REPLACE,..

    Si je change:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    $upMemList = [
        'p_description' => "JSON_INSERT(`p_description` , '$.chipset' , 'Qualcomm')"
    ];
    Par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $upMemList = ['p_description' => '{"chipset": "SN"}'];
    Le champs est mis à jours par les nouvelles informations.

    Je ne sais pas comment remédier ce problème

  4. #4
    Expert confirmé
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 322
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 322
    Billets dans le blog
    17
    Par défaut
    @Séb. Toutes les requêtes marchent bien, sauf les requêtes qui contiennent des fonctions comme JSON_INSERT, JSON_REPLACE,..
    Oui, c'est ce que je te dis, tes fonctions vont être considérées comme de simples chaînes et ne seront pas exécutées.

    C'est comme si tu faisais :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    UPDATE table
    SET column = 'JSON_INSERT(...)'
    WHERE ...

    Et pas :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    UPDATE table
    SET column = JSON_INSERT(...)
    WHERE ...

    Il faut donc que tu envoies directement ton JSON final (pas top, et pas sûr que la préparation échappe correctement le JSON)
    ou que tu trouves le moyen de débrayer la préparation / l'échappement de tes paramètres

  5. #5
    Membre confirmé
    Inscrit en
    Juillet 2009
    Messages
    171
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 171
    Par défaut
    Merci Séb. Alors j'ai pensé créer une nouvelle fonction, qui a ce rôle de JSON_INSERT:

    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
    public function jsonInsert($table, $item, $values, $where = null)
        {
            foreach($values as $kf => $vf):
                $arg    = '"'.$kf.'", "'.$vf.'"';
            endforeach;
     
    // J'ai mis JSON_SET au lieu de INSERT pour tester plusieurs méthodes (JSON_INSERT, JSON_SET, JSON_MODIFY, JSON_REPLACE..)
            $sql = 'UPDATE '.$table.' SET '.$item.' = JSON_SET('.$item.', '.$arg.')';
     
            if ($where != null) {
                $sql .= ' WHERE ' . $where;
            }
     
            $this->sql    = $sql;
            echo $this->sql.'<br>';
            return $this->sql;
        }
    La requête marche bien, sauf quand j'ajoute un WHERE:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $upMemList = [
            '$.chipset' => 'Essai3'
        ];
     
        //$upOn   = $dbh->jsonInsert('products', 'p_description', $upMemList); ==> Celle-ci marche bien
        $upOn   = $dbh->jsonInsert('products', 'p_description', $upMemList, 'id = :id'); ==> avec "WHERE id = :id" ne marche pas
        $dbh->prepare($upOn);
     
        foreach ($upMemList as $fk => $fv) :
            $dbh->bind($fk, $fv);
        endforeach;
        $dbh->bind(':id', 2);
        $dbh->execute();
    La fonction bind:

    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
    public function bind($param, $value, $type = null)
        {
     
            if (is_null($type)) :
                switch (true):
                    case is_int($value):
                        $type = PDO::PARAM_INT;
                        break;
                    case is_bool($value):
                        $type = PDO::PARAM_BOOL;
                        break;
                    case is_null($value):
                        $type = PDO::PARAM_NULL;
                        break;
                    default:
                        $type = PDO::PARAM_STR;
                endswitch; // end switch (true):
            endif; // end if (is_null($type)):
     
            $value  = $this->strSafe($value); // protect value against XSS
            $this->stmt->bindParam($param, $value, $type);
        }
    L'erreur:

    Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
    in /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php:186 Stack trace:
    #0 /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php(186): PDOStatement->bindParam('$.chipset', 'Essai3', 2)
    #1 /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/json_update.php(31): Database->bind('$.chipset', 'Essai3')
    #2 {main} thrown in /Library/WebServer/Documents/Tests/PHP/MySQL-JSON/CRUD.php on line 186
    Sachant que les fonctions marchent bien avec les autres requêtes

Discussions similaires

  1. Réponses: 6
    Dernier message: 05/10/2017, 14h45
  2. Réponses: 0
    Dernier message: 28/09/2009, 22h16
  3. Réponses: 0
    Dernier message: 28/09/2009, 22h16
  4. Réponses: 2
    Dernier message: 07/07/2007, 16h22
  5. [MySQL] problème avec if pour insérer des champs
    Par nerazzurri dans le forum PHP & Base de données
    Réponses: 16
    Dernier message: 23/05/2007, 12h59

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