如何确保加载 Synfony 实体以触发 postLoad 事件?
How to make sure Synfony Entity is loaded to trigger postLoad event?
我是 Symfony 的新手,正在关注 the Jobeet tutorial. I'm trying to inject Container into Entity using service listener and postLoad
. The purpose is to use LiipImagineBundle 在 @ORM\PostPersist
中编写缩略图。问题是 Job 实体没有加载到某些路由上,然后 postLoad
没有被触发。因此,@ORM\PostPersist
中使用的容器不可用。
根据教程,有两条路线 PostPersist
运行:
job/create
job/update
我发现 Job 实体没有加载并且 postLoad
没有在 job/create
上触发。路由 job/update
没问题,注入了容器。我发布了
的一些代码片段
- services.yml
- JobListener.php
- Entity\Job.php
- JobController.php
src/Ibw/JobeetBundle/Resources/config/services.yml
services:
ibw.jobeet.entity.job.container_aware:
class: Ibw\JobeetBundle\Doctrine\Event\Listener\JobListener
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: doctrine.event_listener, event: postLoad }
src/Ibw/JobeetBundle/Doctrine/Event/Listener/JobListener.php
<?php
namespace Ibw\JobeetBundle\Doctrine\Event\Listener;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
class JobListener
{
/** @var ContainerInterface */
protected $container;
/**
* @param ContainerInterface @container
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @ORM\PostLoad
*/
public function postLoad(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if (method_exists($entity, 'setContainer')) {
$entity->setContainer($this->container);
}
}
}
src/Ibw/JobeetBundle/Entity/Job.php
// ....
/**
* @ORM\PostPersist
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
if ($this->getFile()->move($this->getUploadTmpRootDir(), $this->logo)) {
$this->moveAndResizeImage();
}
$this->file = null;
}
private function moveAndResizeImage($filter = 'primary')
{
$path = $this->getWebTmpPath();
$target = $this->getAbsolutePath();
if (file_exists($path)) {
$container = $this->container;
// got problem here. $container is null for /job/create
// but it is okay for /job/update
$dataManager = $container->get('liip_imagine.data.manager');
$filterManager = $container->get('liip_imagine.filter.manager');
$image = $dataManager->find($filter, $path);
$thumb = $filterManager->applyFilter($image, $filter);
file_put_contents($target, $thumb->getContent());
unlink($path); // remove the temp client original image
}
}
// ...
src/Ibw/JobeetBundle/Controller/JobController.php
// ...
public function createAction(Request $request)
{
$entity = new Job();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('ibw_job_preview', array(
'company' => $entity->getCompanySlug(),
'location' => $entity->getLocationSlug(),
'token' => $entity->getToken(),
'position' => $entity->getPositionSlug()
)));
}
return $this->render('IbwJobeetBundle:Job:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
// ....
有什么办法可以解决这个问题吗?
我通过在事件侦听器 class 中添加 prePersist
来解决这个问题,以确保容器在持久化之前可用。 LiipImagineBundle 服务在 postPersist
上调用。我将 JobListener
重命名为 MyListener
。这是我的工作代码:
src/Ibw/JobeetBundle/Resources/config/services.yml
ibw.jobeet.event.mylistener:
class: Ibw\JobeetBundle\Listener\Event\MyListener
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: doctrine.event_listener, event: postLoad }
- { name: doctrine.event_listener, event: prePersist }
src/Ibw/JobeetBundle/Listener/Event/MyListener.php
<?php
namespace Ibw\JobeetBundle\Listener\Event;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Ibw\JobeetBundle\Entity\Job;
class MyListener
{
/** @var ContainerInterface */
protected $container;
/**
* @param ContainerInterface @container
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @param LifecycleEventArgs $eventArgs
*/
public function postLoad(LifecycleEventArgs $eventArgs)
{
$this->injectContainer($eventArgs);
}
/**
* @param LifecycleEventArgs $eventArgs
*/
public function prePersist(LifecycleEventArgs $eventArgs)
{
$this->injectContainer($eventArgs);
}
protected function injectContainer(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof Job) {
$entity->setContainer($this->container);
}
$em = $eventArgs->getEntityManager();
$repository = $em->getRepository('IbwJobeetBundle:Job');
if ($entity instanceof Job) {
$repository->setContainer($this->container);
}
}
}
可能有更好的方法来处理这个问题。如果有,请 post 回答。我知道注入整个容器是一种不好的做法。我稍后会更新以注入所需的服务。
我是 Symfony 的新手,正在关注 the Jobeet tutorial. I'm trying to inject Container into Entity using service listener and postLoad
. The purpose is to use LiipImagineBundle 在 @ORM\PostPersist
中编写缩略图。问题是 Job 实体没有加载到某些路由上,然后 postLoad
没有被触发。因此,@ORM\PostPersist
中使用的容器不可用。
根据教程,有两条路线 PostPersist
运行:
job/create
job/update
我发现 Job 实体没有加载并且 postLoad
没有在 job/create
上触发。路由 job/update
没问题,注入了容器。我发布了
- services.yml
- JobListener.php
- Entity\Job.php
- JobController.php
src/Ibw/JobeetBundle/Resources/config/services.yml
services:
ibw.jobeet.entity.job.container_aware:
class: Ibw\JobeetBundle\Doctrine\Event\Listener\JobListener
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: doctrine.event_listener, event: postLoad }
src/Ibw/JobeetBundle/Doctrine/Event/Listener/JobListener.php
<?php
namespace Ibw\JobeetBundle\Doctrine\Event\Listener;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
class JobListener
{
/** @var ContainerInterface */
protected $container;
/**
* @param ContainerInterface @container
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @ORM\PostLoad
*/
public function postLoad(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if (method_exists($entity, 'setContainer')) {
$entity->setContainer($this->container);
}
}
}
src/Ibw/JobeetBundle/Entity/Job.php
// ....
/**
* @ORM\PostPersist
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
if ($this->getFile()->move($this->getUploadTmpRootDir(), $this->logo)) {
$this->moveAndResizeImage();
}
$this->file = null;
}
private function moveAndResizeImage($filter = 'primary')
{
$path = $this->getWebTmpPath();
$target = $this->getAbsolutePath();
if (file_exists($path)) {
$container = $this->container;
// got problem here. $container is null for /job/create
// but it is okay for /job/update
$dataManager = $container->get('liip_imagine.data.manager');
$filterManager = $container->get('liip_imagine.filter.manager');
$image = $dataManager->find($filter, $path);
$thumb = $filterManager->applyFilter($image, $filter);
file_put_contents($target, $thumb->getContent());
unlink($path); // remove the temp client original image
}
}
// ...
src/Ibw/JobeetBundle/Controller/JobController.php
// ...
public function createAction(Request $request)
{
$entity = new Job();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('ibw_job_preview', array(
'company' => $entity->getCompanySlug(),
'location' => $entity->getLocationSlug(),
'token' => $entity->getToken(),
'position' => $entity->getPositionSlug()
)));
}
return $this->render('IbwJobeetBundle:Job:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
// ....
有什么办法可以解决这个问题吗?
我通过在事件侦听器 class 中添加 prePersist
来解决这个问题,以确保容器在持久化之前可用。 LiipImagineBundle 服务在 postPersist
上调用。我将 JobListener
重命名为 MyListener
。这是我的工作代码:
src/Ibw/JobeetBundle/Resources/config/services.yml
ibw.jobeet.event.mylistener:
class: Ibw\JobeetBundle\Listener\Event\MyListener
calls:
- [setContainer, ["@service_container"]]
tags:
- { name: doctrine.event_listener, event: postLoad }
- { name: doctrine.event_listener, event: prePersist }
src/Ibw/JobeetBundle/Listener/Event/MyListener.php
<?php
namespace Ibw\JobeetBundle\Listener\Event;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Ibw\JobeetBundle\Entity\Job;
class MyListener
{
/** @var ContainerInterface */
protected $container;
/**
* @param ContainerInterface @container
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @param LifecycleEventArgs $eventArgs
*/
public function postLoad(LifecycleEventArgs $eventArgs)
{
$this->injectContainer($eventArgs);
}
/**
* @param LifecycleEventArgs $eventArgs
*/
public function prePersist(LifecycleEventArgs $eventArgs)
{
$this->injectContainer($eventArgs);
}
protected function injectContainer(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof Job) {
$entity->setContainer($this->container);
}
$em = $eventArgs->getEntityManager();
$repository = $em->getRepository('IbwJobeetBundle:Job');
if ($entity instanceof Job) {
$repository->setContainer($this->container);
}
}
}
可能有更好的方法来处理这个问题。如果有,请 post 回答。我知道注入整个容器是一种不好的做法。我稍后会更新以注入所需的服务。