我想在每次请求或提供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();
}