Bonjour,

j'ai mis en place le tuto MVC de grafikart. Tout fonctionne très bien. Toutefois, j'aimerais implémenter des Trasactions car j'ai besoin que plusieurs requêtes s'exécutent sans erreurs. J'ai donc fait ceci:

function saveTabPartie() {
$this->loadModel('Parties');
$this->loadModel('reglements');
$this->loadModel('cheques');
$this->loadModel('taches');
$this->loadModel('joueur');

    // Prévoire de récupérer ette valeur par les parametres de l'appli
    $IdModePaiementCheque = '2';

    $p = $this->recuperationDonnneesFormulairePartie();

        header('Content-type: application/json');
      try
        {
            // Démarrage de la transaction avec la variable de connexion du model.php
            $this->joueur->callTransaction();

            $retourIdPartie = $this->Parties->addPartie($p);
            $retourIdReglement = $this->reglements->addReglement($p, $retourIdPartie);
            if($p['idModePaiement'] == $IdModePaiementCheque)
            {
                if($this->cheques->addCheque($p, $retourIdReglement))
                {
                    //echo "ok cheque ajouté";
                }
                else
                {
                    throw new Exception('Erreur durant l\'ajout du cheque.');
                }
            }

            if($p['absent'] == 1 && $p['tache'] != '')
            {
                if($retourIdTache = $this->taches->addTache($p))
                {
                    $update = "idTache='".$retourIdTache."'";
                    if(!$this->Parties->updatePartie($retourIdPartie, $update))
                    {
                        throw new Exception('Erreur en mettant à jour la Partie avec la tache associée.');
                    }                        
                }
                else
                {
                    throw new Exception('Erreur en ajoutant la tâche.');
                }
            }

            if($this->joueur->callCommit())
            {
                echo json_encode(array('success'=>'true', 'LastInsertId' => $retourIdReglement, 'retour' => $p));
                return true;
            }
            else
            {
                echo json_encode(array('error'=>'true','message'=>'Le commit de la fonction saveTabPartie du controller Partie n\'a pas fonctionné.'));
                return false;
            }
        }
        catch(Exception $e)
        {
            $this->joueur->callRollback();
            echo json_encode(array('error'=>'true', 'message'=> $e->getMessage().'La ligne: '.$e->getLine()));
            return false;
        }
  }

Je crois savoir d'où vient l'erreur mais je n'arrive pas à l'expliquer et surtout à trouver une solution. Je pense que j'appelle le "beginTrasaction()" dans un contexte d'objet "utilisateur" et que j'exécute les requête dans une autre contexte. Si bien que dans les autres contexte le beginTransaction() n'a pas d'effet.

Auriez vous une idée pour que j'implémente ceci?

Je vous remercie.

10 réponses


Il faudrait que ton instance de pdo soit unique et soit utilisée par l'ensemble de tes objets "model" pour que cela fonctionne, il faut donc que tu mettes en place un singleton ;)

Merci pour ta réponse. C'est bien ce que je pensais, mais le problème c'est que je ne sais absolument pas par quel bout commencer et surtout comment m'y prendre pour que le MVC proposé par Grafikart puisse intégrer cette fonctionnalité.
Des pistes à me proposer? Me conseiller?

Tu dois avoir quelque part dans ton code l'instanciation de PDO, un truc du genre

$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);

Il faudrait que cette instance soit unique, pour ça il faut mettre en place un singleton comme dit au-dessus, et pour ce faire, il faut créer une fonction statique qui se charge de te fournir cette fameuse instance, soit elle la crée, soit elle te la retourne.

Un peu de code en exemple :

private $_instance_pdo = null;

public static function getInstance()
{
    if(is_null($_instance_pdo){
        $this->_instance_pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
    }

    return $this->_instance_pdo;
}

Merci pour ces informations et désolé pour le délai de réponse. Je vais regarder tout ça et je me permettrai de revenir si je ne m'en sors pas.
Merci encore ;)

Merci pour le lien j'y suis allé, j'ai regardé, j'ai bien tout compris. MAIS je ne vois toujours pas comment l'intégrer dans le MVC de grafikart.
En fait le controller.php a une fonction nommée loadModel($name) qui charge l'objet (Le M Modele du MVC) passé en paramètre. La classe du modèle est un extend de la classe Modele.php dans laquelle la connexion à la bdd se fait. Dans la fonction __contruct de Modele.php il y a la connexio à la bdd. Donc à chaque fois que je vais instancier une classe du Model, je vais aussi instancier un objet de connexion.
A moins que tous les Model ne soient plus extend de la classe Model et je fais tous mes appels en static dans ces fichiers.
Ca irait vous pensez?

Ou alors!......................... dans la fonction __contruct de Model.php, je fais un test pour vérifier si l'instance existe.

Non ça ne marche pas. Je m'emmêle les pinceaux! Un peu d'aide svp?

Je pense avoir trouvé la solution, mais je ne suis pas satisfait il y a un truc qui me chagrine.
J'ai créé un classe PDO2:

<?php

class PDO2 extends PDO {
private static $_instance = NULL;

function __construct(){     
}

public static function getInstance(){
    if(!isset(self::$_instance)){
        try{
            self::$_instance = new PDO('mysql:host='.HOTE.';dbname='.BDD, USER, PASS);
            self::$_instance->exec('SET NAMES utf8');
        }catch(PDOException $e) {
            echo $e;
        }
    }
    return self::$_instance;
}

}

Mon fichier Model.php ressemble à ça maintenant:

class Model {

var $connexion;

function __construct(){
    //$this->pdo = PDO2::getInstance();
}

//Lance une transaction
public static function callTransaction(){
    $pdo = PDO2::getInstance();
    $pdo->beginTransaction();
}

// Lance un commit
public static function callCommit(){
    $pdo = PDO2::getInstance();
    if($pdo->commit())
    {
        return true;
    }
    else
    {
        return false;
    }
}

// Lance un rollback
public static function callRollback(){
    $pdo = PDO2::getInstance();
    $pdo->rollback();
}

function requeteCount($requete) {
    $pdo = PDO2::getInstance();
    $resultat = $pdo->query($requete);
    $resultat->setFetchMode(PDO::FETCH_ASSOC);
    $ligne = $resultat->fetch();
    return $ligne;
}

Je n'utilise plus $connexion du coup.

Et ça marche, le problème c'est que dans chaque fonction je fais un $pdo = PDO2::getInstance(); pour récupérer l'instance en cours. Est ce que je fais bien?

Merci.

Personnellement, j'utiliserais l'injection de dépendance (toujours partie designs patterns simples), et en paramètre tu lui passe la connexion via PDO2::getInstance();.