每次请求或提供URL时,我都要保留一个Log实体(ip,url,path,user,date ...)。我正在关闭" EntityManager已关闭"错误。 如果可能的话,我正在寻找一个简单的解决方案。 我的代码如下:
首先是YAML 服务:
kernelListener:
class: AppBundle\EventListener\KernelListener
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: AppBundle\Service\Logger
arguments: ['@doctrine.orm.entity_manager', '@security.token_storage' ]
scope: prototype
这是我的Logger服务:
namespace AppBundle\Service;
use AppBundle\Entity\Log;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
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 \AppBundle\Entity\User) {
$log->setUser($user);
}
}
$this->em->persist($log);
$this->em->flush();
}
}
和KernelListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use AppBundle\Service\Logger;
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(),则不会抛出任何错误,但逻辑上没有登录数据库。
答案 0 :(得分:1)
出现错误 EntityManager已关闭,因为存在一些数据库级异常。因此,实体管理器的逻辑如下:如果存在异常,EntityManager
将切换到“已关闭”状态,您将无法再使用它。
如果您想使用EntityManager
- 您需要创建一个新的。例如,如https://stackoverflow.com/a/19077050/6699227中所述:
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->entityManager->create(
$this->entityManager->getConnection(),
$this->entityManager->getConfiguration()
);
}
您的案例的另一个解决方案可能是create another entity manager,仅用于编写日志。应用程序本身不会使用它,因此它永远不会被关闭。
答案 1 :(得分:0)
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 \AppBundle\Entity\User) {
$user2 = $this->em->getReference('AppBundle:User', $user->getId());
$log->setUser($user2);
}
}
$this->em->persist($log);
$this->em->flush();
}