ZF2 - База данных транзакций с обновлением нескольких таблиц
Я хочу использовать транзакцию БД ZF2 для обновления нескольких таблиц. Обычно я делаю транзакцию примерно так для одной таблицы:
$connection = null;
try {
$connection = $this->tableGateway->getAdapter()->getDriver()->getConnection();
$connection->beginTransaction();
$this->tableGateway->insert($data);
$connection->commit();
}
catch (Exception $e) {
if ($connection instanceof \Zend\Db\Adapter\Driver\ConnectionInterface) {
$connection->rollback();
}
}
Теперь я хочу обновить две таблицы внутри одной транзакции. В ZF1 я сделал это, создав экземпляр класса table2 и вызвав соответствующий метод внутри той же транзакции. Но так как я не знаю метод для вызова другого класса модели внутри модели, я не могу сделать как ZF1. Мне это нужно для такой простой задачи, как добавление новых строк в таблицу tbl_invoice и обновление рабочего номера таблицы tbl_runno для счетов при вводе нового счета (счета).
2 ответа
В вашем контроллере вы можете сделать:
$db = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$con = $db->getDriver()->getConnection();
$con->beginTransaction();
try {
//get tables and do sth
$con->commit();
} catch (Exception $e) {
$con->rollback();
}
Используйте шаблон проектирования DataMapper. Pattern TableGateway служит для проецирования данных в одну таблицу.
- http://akrabat.com/development/objects-in-the-model-layer
- http://akrabat.com/php/objects-in-the-model-layer-part-2
- http://www.slideshare.net/aaronsaray/midwest-php-2013
https://leanpub.com/zendframework2-en Вы можете использовать что-то вроде этого:
namespace ScContent\Mapper; use Zend\Db\Sql\Sql; use Zend\Db\Sql\Select; use Zend\Db\Sql\SqlInterface; use Zend\Db\Sql\PreparableSqlInterface; use Zend\Db\Adapter\AdapterInterface; use Zend\Db\Adapter\Driver\ResultInterface; use Zend\Stdlib\Hydrator\ClassMethods; use Zend\StdLib\Hydrator\HydratorInterface; abstract class AbstractDbMapper { /** * @var string */ const JoinInner = Select::JOIN_INNER; /** * @var string */ const JoinLeft = Select::JOIN_LEFT; /** * @var string */ const JoinRight = Select::JOIN_RIGHT; /** * @var Zend\Db\Adapter\AdapterInterface */ protected $_adapter; /** * @var Zend\Db\Sql\SqlInterface */ protected $_sql; /** * @var Zend\Stdlib\HydratorInterface */ protected $_hydrator; /** * @var array */ protected $_tables = array(); /** * @param Zend\Db\Adapter\AdapterInterface $adapter */ public function setAdapter(AdapterInterface $adapter) { $this->_adapter = $adapter; } /** * @return Zend\Db\Adapter\AdapterInterface */ public function getAdapter() { if(!$this->_adapter instanceof AdapterInterface) { throw new Exception('Adapter is not installed.'); } return $this->_adapter; } /** * @param Zend\Db\Sql\SqlInterface $sql */ public function setSql(SqlInterface $sql) { $this->_sql = $sql; } /** * @return Zend\Db\Sql\SqlInterface */ public function getSql() { if(!$this->_sql instanceof SqlInterface) { $this->_sql = new Sql($this->getAdapter()); } return $this->_sql; } /** * @param Zend\Stdlib\HydratorInterface $hydrator */ public function setHydrator(HydratorInterface $hydrator) { $this->_hydrator = $hydrator; } /** * @return Zend\Stdlib\HydratorInterface */ public function getHydrator() { if(!$this->_hydrator instanceof HydratorInterface) { $this->_hydrator = new ClassMethods(); } return $this->_hydrator; } /** * @param string $alias * @param string $name */ public function setTable($alias, $name) { $this->_tables[$alias] = $name; } /** * @param string $alias * @throws Exception * @return string */ public function getTable($alias) { if(!array_key_exists($alias, $this->_tables)) { throw new Exception(sprintf("Unknown table alias '%s'.", $alias)); } return $this->_tables[$alias]; } /** * @return int|null|false */ protected function lastInsertId() { return $this->adapter->getDriver()->getConnection()->getLastGeneratedValue(); } /** * @param void * @return void */ protected function beginTransaction() { $this->getAdapter()->getDriver()->getConnection()->beginTransaction(); } /** * @param void * @return void */ protected function commit() { $this->getAdapter()->getDriver()->getConnection()->commit(); } /** * @return bool */ protected function inTransaction() { return $this->getAdapter()->getDriver() ->getConnection()->getResource()->inTransaction(); } /** * @param void * @return void */ protected function rollBack() { $this->getAdapter()->getDriver()->getConnection()->rollBack(); } /** * @param Zend\Db\Sql\PreparableSqlInterface $sqlObject * @return Zend\Db\Adapter\ResultInterface */ protected function execute(PreparableSqlInterface $sqlObject) { return $this->getSql()->prepareStatementForSqlObject($sqlObject)->execute(); } /** * @param Zend\Db\Adapter\ResultInterface $source * @return array */ protected function toArray(ResultInterface $source) { $result = array(); foreach($source as $item) { $result[] = $item; } return $result; } /** * */ protected function toString(SqlInterface $sqlObject) { return $this->getSql()->getSqlStringForSqlObject($sqlObject); } }
Пример использования:
<?php namespace ScContent\Mapper; use Zend\Db\Adapter\AdapterInterface; class ContentMapper extends AbstractDbMapper { /** * @var string */ const ContentTableAlias = 'contentalias'; /** * @var string */ const UsersTableAlias = 'usersalias'; /** * @param AdapterInterface $adapter */ public function __construct(AdapterInterface $adapter) { $this->setAdapter($adapter); } /** * @var array */ protected $_tables = array( self::ContentTableAlias => 'sc_content', self::UsersTableAlias => 'sc_users' ); /** * @param integer $id * @return null | array */ public function findById($id) { $select = $this->getSql()->select() ->from(array('content' => $this->getTable(self::ContentTableAlias))) ->join( array('users' => $this->getTable(self::UsersTableAlias)), 'content.author = users.user_id', array('username'), self::JoinInner ) ->where(array('`content`.`id` = ?' => $id)); return $this->execute($select)->current(); } }