PHP PDO Rollback does not work

2

Hi, I am trying to execute a PDO Rollback in a function where I involve several tables and there are several insert and updates.

I am working with MVC and POO.

Maybe I have something wrong with my structure, if so, could you tell me where the problem is, please?

This is my "Connection Model" where I run the Query's and make the connection to the DB

<?php   

class conexion{
    public $conexion;
    function __construct(){
        require "./config/param_conexion.php";
        $this->conexion = new PDO("mysql:host=$host;dbname=$db;port=$port",$user,$pw);          
    }
    public function beginTransaction(){         
        try{                
            $begin = $this->conexion->beginTransaction();
        }catch(PDOException $e){
            print $e->getMessage();
        }
    }
    public function Commit(){           
        try{
            $this->conexion->commit();
        }catch(PDOException $e){
            print $e->getMessage();
        }
    }
    public function Rollback(){         
        try{
            $this->conexion->rollback();
        }catch(PDOException $e){
            print $e->getMessage();
        }
    }
    public function Query($query){          
        try{
            if($this->conexion){

                $resultado = $this->conexion->query($query);                    
                return $resultado;                  

            }else{                  
                return false;
                return $this->conexion->errorInfo();
            }
        }catch(PDOException $e){
            return $e->getMessage();
        }           

    }           
    function __destruct(){
        $this->conexion = null;
    }   
}

This is my Controller who calls his model:

<?php

define('PATH_JSON_CARGO_DESCARGO',"./json/cargo_descargo_mv.json");

class con_cargo_descargo extends mod_cargo_descargo{
    public function UltimoConsecutivo(){

        $resultado = parent::Select_LastDoc();
        $datos = $resultado->fetch(PDO::FETCH_ASSOC);
        $datos['documento'] = $datos['documento'] + 1;
        $datos['documento'] = str_pad($datos['documento'],10, '0' ,STR_PAD_LEFT);           

        print json_encode($datos);

    }
    public function Guardar(){

        if( !empty($_POST['tipo_documento']) ){

            if( !empty($_POST['concepto']) ){

                if( !empty( $_POST['tipo_cargo_descargo']) ){

                    //Optengo los productos adicionados en el archivo json
                    $array = array();
                    if(file_exists(PATH_JSON_CARGO_DESCARGO)){
                        $array = file_get_contents(PATH_JSON_CARGO_DESCARGO);
                        $array = json_decode($array,true);
                    }

                    $total = count($array);

                    if($total > 0){

                        //Obtengo el ID y el CONSECUTIVO del ultimo documento
                        $query_LastDoc = $this->Select_LastDoc();
                        $datos_LastDoc = $query_LastDoc->fetch(PDO::FETCH_ASSOC);

                        //Obtengo la Serie del tipo de documento
                        Require_Controller('tipo_documentos');
                        $obj_tipo_doc = new con_tipo_documentos();
                        $datos_tipo_doc = $obj_tipo_doc->ConsultarJson($_POST['tipo_documento']);
                        $GLOBALS['serie'] = $datos_tipo_doc->serie;

                        if(empty($datos_LastDoc['documento'] )){
                            $datos_LastDoc['documento'] = 0;
                            $datos_LastDoc['id_cargo_descargo'] = 1;
                        }else{
                            $datos_LastDoc['id_cargo_descargo'] = $datos_LastDoc['id_cargo_descargo']+1;
                        }

                        $consecutivo = $datos_LastDoc['documento'] + 1;
                        $consecutivo = str_pad($consecutivo,10,'0',STR_PAD_LEFT);

                        $GLOBALS['id_cargo_descargo'] = $datos_LastDoc['id_cargo_descargo'];
                        $GLOBALS['documento'] = $consecutivo;

                        parent::beginTransaction();

                        $resultado_ti = parent::Insert_ti();
                        if($resultado_ti){

                            $resultado_mv = parent::Insert_mv($array);
                            if($resultado_mv){

                                //Registramos las existencias
                                Require_Controller('existencias');
                                $obj_existencias = new con_existencias();
                                $resultado_exist = $obj_existencias->Guardar($array);

                                if($resultado_exist){

                                    //Registramos los datos en el KARDEX
                                    Require_Controller('kardex');
                                    $obj_kardex = new con_kardex();
                                    $resultado_kardex = $obj_kardex->Guardar($array);               

                                    if($resultado_kardex){
                                        parent::Rollback();
                                        //$file = file_put_contents(PATH_JSON_CARGO_DESCARGO,'');
                                        print $GLOBALS['msj_successDatProc'];
                                    }else{
                                        parent::Rollback();
                                        print "error|Error al registrar kardex";
                                    }

                                }else{
                                    parent::Rollback();
                                    print "error|Error al registrar existencias";
                                }

                            }else{
                                parent::Rollback();
                                print "error|Error al registrar detalles del documento";
                            }

                        }else{
                            parent::Rollback();
                            print "error|Error al registrar documento";
                        }

                    }else{
                        print "info|Indique los productos a Cargar o Descargar";
                    }

                }else{
                    print "info|Indique un tipo de Cargo/Descargo";
                }

            }else{
                print "info|Indique un concepto";
            }

        }else{
            print "info|Indique el tipo de documento y el concepto del mismo";
        }

    }


}

and finally this is their respective Model which has as its parent the Connection model.

<?php   

class mod_cargo_descargo extends conexion{
    public $table_ti = 'cargo_descargo_ti';
    public $table_mv = 'cargo_descargo_mv';
    public function Select_LastDoc(){

        $query = "
            SELECT 
            id_cargo_descargo,
            documento 
            FROM ".$this->table_ti."
            ORDER BY documento DESC
            LIMIT 1
        ";

        $resultado = parent::Query($query);

        return $resultado;

    }
    public function Insert_ti(){

        @session_start();

        $query = "
            INSERT INTO ".$this->table_ti."
            (
                id_cargo_descargo,
                id_tipo_documento,
                serie,
                documento,
                registrado_por,
                concepto,
                fecha_registro,
                id_tipo_cargo_descargo,
                id_usuario
            )
            VALUES
            (
                '".$GLOBALS['id_cargo_descargo']."',
                '".$_POST['tipo_documento']."',
                '".$GLOBALS['serie']."',
                '".$GLOBALS['documento']."',
                '".$_POST['responsable_cargo_descargo']."',
                '".$_POST['concepto']."',
                '".$_POST['fecha_cargo_descargo']."',
                '".$_POST['tipo_cargo_descargo']."',
                '".$_SESSION['id_usuario']."'
            )
        ";

        $resultado = parent::Query($query);
        return $resultado;

    }
    public function Insert_mv($array){

        $query = "
            INSERT INTO ".$this->table_mv."
            (
                id_cargo_descargo,
                id_articulo,
                id_almacen,
                cargo_descargo,
                cantidad,
                costo_nuevo,
                ubicacion,
                fechayhora
            )
            VALUES
        ";

        $x=0;
        $total = count($array);         

        while($x < $total){
            $query .= "
                (
                    '".$GLOBALS['id_cargo_descargo']."',
                    '".$array[$x]['id_articulo']."',
                    '".$array[$x]['almacen']."',
                    '".$array[$x]['sumaresta']."',
                    '".$array[$x]['cantidad']."',
                    '".$array[$x]['costo_nuevo']."',
                    '".$array[$x]['ubicacion']."',
                    '".$array[$x]['fechayhora']."'
                )
            ";

            $x++;

            if($x < $total){
                $query .= ",";
            }

        }

        $resultado = parent::Query($query);         
        return $resultado;

    }
}

The problem that I am having is that if they see the SAVE Method in my controller, I am making a Requirement of 2 other controllers, all my controllers have the same structure, they have their model and each model has as its parent the Connection file.

The ROLLBACK is effective only with the INSERT and UPDATES that I execute with the methods that belong to the same controller, but the INSERT and UPDATES of those 2 controllers of which I am doing REQUIRE does not work the ROLLBACK.

That is to say that the ROLLBACK is not working with functions that are external to the controller where I am.

I hope you explained ...

    
asked by StevePHP 31.08.2016 в 23:24
source

1 answer

3

Let's start with some concept.

In principle, database transactions generally work at the connection level.

A server can handle multiple connections and successfully perform, in isolation, operations in each of them. This includes, as expected, the typical operations insert , update , delete and also the transaction control instructions and the transactions themselves.

An application can establish multiple database connections and for each connection, the operations performed will be made in isolation to other connections that the same application maintains.

Now yes, let's go to your problem.

The drawback is that each model, by extending the class conexion is establishing a new connection to the server, and it is in this connection where it performs its operations.

If you want the operations of the models, as a whole, to be atomic (that is, to do everything or nothing regardless of which model they come from, my recommendation is that you share a single connection between all the models.

In other words, do not extend to each class conexion , but in each model you can store a reference to a common connection between all the models.

Thus, all the operations that you carry out will be actually contained in a single transaction and you will be able to make a commit / rollback that covers them all.

    
answered by 01.09.2016 / 04:01
source