. */ namespace SP\Infrastructure\Common\Repositories; use Aura\SqlQuery\QueryFactory; use Closure; use Exception; use SP\Core\Context\ContextInterface; use SP\Core\Events\Event; use SP\Core\Events\EventDispatcherInterface; use SP\Core\Events\EventMessage; use SP\Core\Exceptions\SPException; use SP\Domain\Common\Ports\RepositoryInterface; use SP\Domain\Common\Services\ServiceException; use SP\Infrastructure\Database\DatabaseInterface; use function SP\__u; use function SP\logger; /** * Class Repository * * @package SP\Infrastructure\Common\Repositories */ abstract class Repository implements RepositoryInterface { public function __construct( protected DatabaseInterface $db, protected ContextInterface $context, protected EventDispatcherInterface $eventDispatcher, protected QueryFactory $queryFactory ) { if (method_exists($this, 'initialize')) { $this->initialize(); } } /** * Bubbles a Closure in a database transaction * * @param \Closure $closure * @param object $newThis * * @return mixed * @throws \SP\Domain\Common\Services\ServiceException */ final public function transactionAware(Closure $closure, object $newThis): mixed { if ($this->db->beginTransaction()) { try { $result = $closure->call($newThis); $this->db->endTransaction(); return $result; } catch (Exception $e) { $this->db->rollbackTransaction(); logger('Transaction:Rollback'); $this->eventDispatcher->notifyEvent( 'database.rollback', new Event($this, EventMessage::factory()->addDescription(__u('Rollback'))) ); $this->eventDispatcher->notifyEvent('exception', new Event($e)); throw new ServiceException(__u('Rollback'), SPException::ERROR, null, $e->getCode(), $e); } } else { throw new ServiceException(__u('Unable to start a transaction')); } } }