In my project i have entities table, where all entities should exist (to support complex foreign keys), so i need to insert additional row in special table (in this entities list) before inserting a row to my model table, and i wanted to ask what is the best way to do this.
So, for following code i need to insert two rows: in entity table, then pick up id for just inserted row, save it in current model and insert in accounts table:
$account = new Account();
$account->name = 'John';
$account->save(); // performs two inserts while creating model
As i understood, i can use beforeCreate() method to insert row in entity table and to pick up id for newly created row, smth like this:
class Account
{
public function beforeSave()
{
$entity = new \Entity();
$entity->type = get_class($this);
$entity->save();
$this->id = $entity->id;
}
}
But this way, if somehow account row will be not inserted, row in entity table will exist.
Then i thought to use transactions as shown in docs here http://docs.phalconphp.com/en/latest/reference/models.html#transactions
But i don’t unserstand, if i have small transactions for every model::create() method, how it will work when i will need transactions for complex operations?
e.g.
// controller action context
use Phalcon\Mvc\Model\Transaction\Manager as TxManager,
Phalcon\Mvc\Model\Transaction\Failed as TxFailed;
try {
//Create a transaction manager
$manager = new TxManager();
// Request a transaction
$transaction = $manager->get();
$account = new Account();
$account->setTransaction($transaction);
$account->name = "WALL·E";
$account->created_at = date("Y-m-d");
if ($account->save() == false) { // sub-transaction inside account::create() method
$transaction->rollback("Cannot save account");
}
$accountPart = new AccountPart();
$accountPart->setTransaction($transaction);
$accountPart->type = "head";
if ($accountPart->save() == false) { // sub-transaction inside accountPart::create() method
$transaction->rollback("Cannot save account part");
}
//Everything goes fine, let's commit the transaction
$transaction->commit();
} catch(TxFailed $e) {
echo "Failed, reason: ", $e->getMessage();
}
It’s hard to imagine how it will work in big project.. nested transactions it’s not very good for database perfomance
Also i thought about 3d method of implementation, i’ve added it’s code below, but it looks like a hack and i also don’t want to use it:
public function create($data = null)
{
// Create abstract entity instance
$entity = new \Entity();
$entity->type = get_class($this);
// Save abstract entity
if (!$entity->save()) {
return false;
}
// Save current entity
$this->id = $entity->id;
$result = parent::create($data);
// Remove abstract entity if current row was not saved
if (!$result) {
$entity->delete();
}
return $result;
}
What is the best and easy way to support such complex entities?
The easiest way to implement transactions is using 0.9.0:
On the other hand, the transaction manager creates an isolated connection that allow you to query the records modified in the current transaction snapshot, as well see the not isolated records.
Here, there is an explanation of different transaction scenarios in the new docs: http://docs.phalconphp.com/en/0.9.0/reference/models.html#transactions