/**
  * @return EntityManagerInterface
  */
 public function getEm()
 {
     return $this->context->getEm();
 }
 /**
  * @inheritdoc
  */
 public function intercept(MethodInvocation $invocation)
 {
     $metadata = $this->findMethodMetadata(get_class($invocation->object), $invocation->reflection->name);
     $em = $this->doctrine->getManager($metadata->getEm());
     if (!$em instanceof EntityManagerInterface) {
         throw new \Exception('Wrong object manager class');
     }
     $context = new TransactionalInvocationContext($em);
     $arguments = [];
     foreach ($invocation->reflection->getParameters() as $i => $param) {
         $arguments[$param->name] = $invocation->arguments[$i];
     }
     try {
         $em->beginTransaction();
         /** @see https://www.percona.com/blog/2012/08/28/differences-between-read-committed-and-repeatable-read-transaction-isolation-levels/ */
         /** @see http://www.ovaistariq.net/597/understanding-innodb-transaction-isolation-levels/ */
         $em->getConnection()->setTransactionIsolation(Connection::TRANSACTION_READ_COMMITTED);
         array_push($invocation->arguments, $context);
         $ret = $invocation->proceed();
         $em->flush();
         if (!$em->isOpen() || $em->getConnection()->isRollbackOnly()) {
             throw new \Exception('Rollback invoked');
         }
         $em->commit();
         if ($metadata->getOnSuccess() && !$context->isPreventSuccess()) {
             $this->invokeEvent($invocation->object, $metadata->getOnSuccess(), new TransactionalSuccessEvent($arguments, $context, $ret));
         }
         return $ret;
     } catch (\Exception $e) {
         if ($em->getConnection()->isTransactionActive()) {
             // TODO: postgresql, savepoints
             if (!$e instanceof DBALException && !$e instanceof \PDOException && $em->isOpen() && !$em->getConnection()->isRollbackOnly()) {
                 try {
                     $em->flush();
                 } catch (\Exception $e) {
                     // TODO: log? stop catching?
                 }
             }
             $em->rollback();
         }
         if (!$em->isOpen()) {
             $this->doctrine->resetManager($metadata->getEm());
             $contextOld = $context;
             /** @var EntityManagerInterface $em */
             $em = $this->doctrine->getManager($metadata->getEm());
             $context = new TransactionalInvocationContext($em);
             $context->setData($contextOld->getData());
         }
         if ($metadata->getOnError()) {
             return $this->invokeEvent($invocation->object, $metadata->getOnError(), new TransactionalErrorEvent($arguments, $context, $e));
         }
         throw $e;
     }
 }