我们已经设置了一个事件监听器,当实体更新、删除或持久化时,它会触发闪现消息,但我们无法完全管理的是如何处理错误。
这是来自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())
)
);
}
}
我们正在尝试做的是清理 Controller 并将所有错误消息移至事件监听器中。例如,这是我们的 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);
}
最佳答案
我们最终改变了 FlashMessages 的工作方式,因为我们遇到了实体链更新和显示太多 Flash 消息的问题。通过以下方式执行 int 可以让我们停止链式效应。我们从 postUpdate()
、postUpdate()
和 postPersist()
转变为使用单个 onFlush()
。请参阅下面的代码:
AcmeBundle/Resources/config/services.yml
flash_messages:
class: Acme\AcmeBundle\EventListener\FlashMessages
tags:
- { name: doctrine.event_listener, event: onFlush }
arguments: [ @session, @translator, @service_container ]
AcmeBundle/EventListener/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)
函数来处理未找到的实体上的消息,但为了使其正常工作,我们仍然必须从 Controller 抛出异常,传递翻译后的消息...基本上我们仍然需要重复一大块代码,所以我们只是回滚到原始解决方案;也就是说,直接从 Controller 的操作中管理闪存消息:
...
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'));
}
...
关于php - symfony2 flash 消息作为事件监听器来处理错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25284069/