我们已经设置了一个事件监听器,可以在实体更新,删除或保留时触发Flash消息,但我们无法管理的是如何处理错误。
以下是services.yml
flash_messages:
class: Acme\AcmeBundle\EventListener\FlashMessages
tags:
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: postRemove }
- { name: doctrine.event_listener, event: postPersist }
arguments: [ @session, @translator ]
这是Acme/AcmeBundle/EventListener/FlashMessages.php
namespace Acme\AcmeBundle\EventListener;
use
Doctrine\ORM\Event\LifecycleEventArgs,
Symfony\Component\HttpFoundation\Session\Session,
Symfony\Component\Translation\TranslatorInterface
;
class FlashMessages
{
private $session;
protected $translator;
public function __construct(Session $session, TranslatorInterface $translator)
{
$this->session = $session;
$this->translator = $translator;
}
public function postUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.write.success',
array('%name%' => $entity->getClassName())
)
);
}
public function postRemove(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.delete.success',
array('%name%' => $entity->getClassName())
)
);
}
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.create.success',
array('%name%' => $entity->getClassName())
)
);
}
}
我们要做的是清理控制器并将所有错误消息移动到事件监听器中。例如,这是我们的DeliveryController.php
:
/**
* Finds and displays a Delivery entity.
*
* @Route("/{id}", name="delivery_show")
* @Method("GET")
* @Template()
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AcmeBundle:Delivery')->find($id);
if (!$entity) {
/**
* @todo move this code to eventListener
*/
$entity = new Delivery();
$this->get('session')->getFlashBag()->add(
'danger',
$this->get('translator')->trans(
'%name% entity.find.fail',
array('%name%' => $entity->getClassName())
)
);
// end @todo
return new RedirectResponse($this->generateUrl('delivery'));
}
return array(
'entity' => $entity,
'menu_tree' => $this->menu_tree,
);
}
就像那样,理想情况下,当实体无法创建,保留和删除时,我们也希望处理错误。
供参考,翻译由Acme/AcmeBundle/Resources/translations/messages.en.yml
%name% entity.create.fail: There wes an error creating the %name%. Please try again later.
%name% entity.create.success: %name% created successfully.
%name% entity.write.fail: There wes an error saving the %name%. Please try again later.
%name% entity.write.success: %name% saved successfully.
%name% entity.delete.fail: There wes an error deleting the %name%. Please try again later.
%name% entity.delete.success: %name% deleted successfully.
%name% entity.find.fail: %name% not found.
$entity->getClassName()
位于每个实体中:
private $className;
/**
* Get class name
* @return string
*/
public function getClassName()
{
$entity = explode('\\', get_class($this));
return end($entity);
}
答案 0 :(得分:2)
我们最终改变了我们的FlashMessages的工作方式,因为我们遇到了实体链更新和显示太多Flash消息的问题。以下列方式执行int允许我们停止链效应。我们从postUpdate()
,postUpdate()
和postPersist()
转到使用单onFlush()
。请参阅下面的代码:
AcmeBundle /资源/配置/ services.yml
flash_messages:
class: Acme\AcmeBundle\EventListener\FlashMessages
tags:
- { name: doctrine.event_listener, event: onFlush }
arguments: [ @session, @translator, @service_container ]
AcmeBundle /事件监听/ FlashMessages.php
<?php
namespace Acme\AcmeBundle\EventListener;
use
Symfony\Component\HttpFoundation\Session\Session,
Symfony\Component\Translation\TranslatorInterface,
Doctrine\ORM\Event\OnFlushEventArgs,
Acme\AcmeBundle\Entity\DeliveryItem
;
class FlashMessages
{
private $session;
protected $translator;
public function __construct(Session $session, TranslatorInterface $translator)
{
$this->session = $session;
$this->translator = $translator;
}
public function onFlush(OnFlushEventArgs $args)
{
$this->em = $args->getEntityManager();
$uow = $this->em->getUnitOfWork();
$insert = current($uow->getScheduledEntityInsertions());
$update = current($uow->getScheduledEntityUpdates());
$delete = current($uow->getScheduledEntityDeletions());
// Don't show messages when updating individual DeliveryItem and StockHistory
if ($insert instanceof DeliveryItem ||
$update instanceof DeliveryItem ||
$delete instanceof DeliveryItem) {
return false;
}
// Flash message on insert
if ($uow->getScheduledEntityInsertions()) {
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.create.success',
array('%name%' => $insert->getClassName())
)
);
}
// Flash message on update
if ($uow->getScheduledEntityUpdates()) {
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.write.success',
array('%name%' => $update->getClassName())
)
);
}
// Flash message on delete
if ($uow->getScheduledEntityDeletions()) {
$this->session->getFlashBag()->add(
'success',
$this->translator->trans(
'%name% entity.delete.success',
array('%name%' => $delete->getClassName())
)
);
}
}
}
我们尝试设置onKernelException(GetResponseForExceptionEvent $event)
函数来处理未找到的实体上的消息,但是为了使其工作,我们仍然必须从控制器抛出异常,传递已翻译的消息...基本上我们仍然需要重复一大堆代码,所以我们只回到最初的解决方案;也就是说,直接从控制器的操作管理Flash消息:
...
if (!$entity) {
$entity = new Delivery();
$this->get('session')->getFlashBag()->add(
'danger',
$this->get('translator')->trans(
'%name% entity.find.fail',
array('%name%' => $entity->getClassName())
)
);
return new RedirectResponse($this->generateUrl('delivery'));
}
...