从内核侦听器抛出实体管理器的持久已关闭



我想在每次请求或提供URL时保留一个日志实体(ip,url,path,user,date...(。我收到"实体管理器已关闭"错误。如果可能的话,我正在寻找一个简单的解决方案。我的代码如下:

首先是 YAML 服务业:

kernelListener:
    class: AppBundleEventListenerKernelListener
    arguments: [ '@my_logger']
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
        - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
        - { name: kernel.event_listener, event: kernel.terminate, method: onKernelTerminate }
        - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
my_logger:
    class:        AppBundleServiceLogger
    arguments: ['@doctrine.orm.entity_manager', '@security.token_storage' ]
    scope: prototype  

这是我的记录器服务:

 namespace AppBundleService;
use AppBundleEntityLog;
use DoctrineORMEntityManager;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorage;
class Logger {
private $em, $token;
public function __construct(EntityManager $em, TokenStorage $token) {
    $this->em = $em;
    $this->token_storage = $token;
}
public function persist($r) {
    $log = new Log();
    $log->setAjax($r->isXmlHttpRequest());
    $log->setIp($r->getClientIp());
    $log->setMethod($r->getMethod());
    $log->setPath($path);
    $log->setUrl($r->getUri());
    if ($this->token_storage->getToken()) {
        $user = $this->token_storage->getToken()->getUser();
        if ($user instanceof AppBundleEntityUser) {
            $log->setUser($user);
        }
    }
    $this->em->persist($log);
    $this->em->flush();
}
}

和内核监听器.php

 namespace AppBundleEventListener;
use SymfonyComponentHttpKernelEventGetResponseEvent;
use SymfonyComponentHttpKernelEventFilterResponseEvent;
use SymfonyComponentHttpKernelEventPostResponseEvent;
use SymfonyComponentHttpKernelEventFilterControllerEvent;
use AppBundleServiceLogger;
class KernelListener {
protected $logger;
public function __construct(Logger $logger) {
    $this->logger = $logger;
}
public function onKernelRequest(GetResponseEvent $event) {
}
public function onKernelResponse(FilterResponseEvent $event) {
}
 public function onKernelController(FilterControllerEvent $event) {
    $r = $event->getRequest();
    $this->logger->persist($r);
}
public function onKernelTerminate(PostResponseEvent $event) {        
}
}

如果我删除 flush(( 不会抛出错误,但逻辑上没有登录数据库。

出现错误 EntityManager 已关闭,因为存在一些数据库级异常。因此,实体管理器的逻辑如下:如果出现异常,EntityManager切换到"关闭"状态,您将无法再使用它。

如果要使用EntityManager - 则需要创建一个新。例如,如 https://stackoverflow.com/a/19077050/6699227 中所述:

if (!$this->entityManager->isOpen()) {
    $this->entityManager = $this->entityManager->create(
        $this->entityManager->getConnection(),
        $this->entityManager->getConfiguration()
    );
}

适用于您的案例的另一种解决方案可能是创建另一个实体管理器,仅用于写入日志。它不会被应用程序本身使用,因此永远不会关闭。

Maksym是对的。谢谢!事实上,我几个月前使用过这种技术来记录服务错误,但是内存很弱,特别是当您运行许多任务时:-(

所以我的工作记录器是:

    public function persist($r) {
    if (!$this->em->isOpen()) {
        $this->em = $this->em->create(
                $this->em->getConnection(), $this->em->getConfiguration()
        );
    }
    $path = $r->get('_route');
    if (!$path || in_array($path, $this->paths)) {
        return null;
    }
    $log = new Log();
    $log->setAjax($r->isXmlHttpRequest());
    $log->setIp($r->getClientIp());
    $log->setMethod($r->getMethod());
    $log->setPath($path);
    $log->setUrl($r->getUri());
    if ($this->token_storage->getToken()) {
        $user = $this->token_storage->getToken()->getUser();
        if ($user instanceof AppBundleEntityUser) {
            $user2 = $this->em->getReference('AppBundle:User', $user->getId());
            $log->setUser($user2);
        }
    }
    $this->em->persist($log);
    $this->em->flush();
}

相关内容

  • 没有找到相关文章

最新更新