We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Transactions within ORM context

Hi

I'm trying to understand your transaction model within ORM context. Let's assume the following pseudo-code example:

$trx = new Phalcon\Mvc\Model\Transaction\Manager();
$handle = $trx->get();
try {
    $model1 = new Model1();
    $model1->email = $email;
    if($model1->save()===false) {
        // HOW DO I DETECT DUPLICATE KEY ?
        if($reason == 'dupe') {
           $handle->rollback();
           throw new DupeException();
        } else {
           throw new DBException();
        }           

    }

} catch(DupeException $e) {
    // FALLBACK 
    $model1::findFirst(array('email' => $email));
}

$model2 = new Model2();
$model2->model1_id = $model1->id;
$model2->save(); 

$handle->commit();
  1. How do I specifically extract the "save" failure reason ?

  2. Is there a way to execute $model1::findFirst within the same trasaction ?

  3. Why have not you used the standard patter of:
begin
try 
   query1
   query2
   queryn
   commit
catch Exception
    rollback

I find it so much more elegant and flexible than the if($model1->save() === false)

Thanks in advance....



5.1k
edited Oct '14

I went through the same issue and I agree with your 3rd point. Here is how I did to catch duplicate entries :

$this->db->begin();
try {
    if($account->create()){
        // Continue
        $th->db->commit();
    } else {
        foreach($account->getMessages() as $msg){
        // Store messages
        }
    }
} catch(PdoException $e){
    $this->db->rollback();
    switch($e->getCode()){
        case 23505: // Duplicate entry code for PostGreSql
        break;
    }
}

Hi,

I see that you're bypassing the Transaction Manager all together. I would want to avoid that, but if it's the only way I have few questions:

  1. Where do you get $this->db ? I assume you're using "$model->getWriteConnection()" which in turn uses DI to get the appropriate connection. However there is no way to insure that this connection does not have another transaction already open on it ? Could you elaborate ?
  2. By using the driver level objects you're forced to deal with PdoExceptions, and specific PDO error code (23505) which in turn makes the code non functional on other RDBs.

I'm evaluating if this is a show stopper or not for my project.

edited Oct '14

Also in the documentation, https://docs.phalcon.io/en/latest/api/Phalcon_Mvc_Model_Transaction_Manager.html

I see the following:

$transaction->rollback("Can't save robot");

This is inconsistent with how rollback is defined:

        /**
         * Rollbacks active transactions within the manager
         * Collect will remove transaction from the manager
         *
         * @param boolean $collect
         */
        public function rollback($collect=null){ }

And what "collect" means anyways ?