Doctrine inserting in postPersist event
Chcę dodać nowy Feed na encji persist I update. Piszę ten listener zdarzeń (postUpdate jest taki sam):
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$em = $args->getEntityManager();
if ($entity instanceof FeedItemInterface) {
$feed = new FeedEntity();
$feed->setTitle($entity->getFeedTitle());
$feed->setEntity($entity->getFeedEntityId());
$feed->setType($entity->getFeedType());
if($entity->isFeedTranslatable()) {
$feed->getEnTranslation()->setTitle($entity->getFeedTitle('en'));
}
$em->persist($feed);
$em->flush();
}
}
Ale mam
Naruszenie ograniczenia integralności: 1062 zduplikowany wpis "30-2" dla klucza "PRIMARY"
I w logu a mają dwie Wstawki:
Wstaw do interview_scientificdirection (interview_id, scientificdirection_id) wartości (?, ?) ([30,2]) WSTAWIĆ DO interview_scientificdirection (interview_id, scientificdirection_id) Wartości (?, ?) ([30,2])
Scientificdirection to tabela relacji wielu do wielu dla podmiotu, który chcemy utrzymać. W aplikacji frontend wszystko działa dobrze, ale w Sonata Admin mam taki problem: (
5 answers
Od Doctrine 2.2 można dołączyć do zdarzenia postFlush:
function postFlush($args) {
$em = $args->getEntityManager();
foreach ($em->getUnitOfWork()->getScheduledEntityInsertions() as $entity) {
if ($entity instanceof FeedItemInterface) {
$feed = new FeedEntity;
...
$em->persist($feed);
}
}
$em->flush();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-27 17:24:05
ODPOWIEDŹ Francesc jest błędna, ponieważ zestawy zmian w zdarzeniu postFlush są już puste. Druga odpowiedź jhoffrichtera może zadziałać, ale jest przesadna. Właściwym sposobem jest zachowanie encji w zdarzeniu postPersist i ponowne wywołanie flush w zdarzeniu postFlush. Ale musisz to zrobić tylko wtedy, gdy zmieniłeś coś w zdarzeniu postPersist, w przeciwnym razie utworzysz nieskończoną pętlę.
public function postPersist(LifecycleEventArgs $args) {
$entity = $args->getEntity();
$em = $args->getEntityManager();
if($entity instanceof FeedItemInterface) {
$feed = new FeedEntity();
$feed->setTitle($entity->getFeedTitle());
$feed->setEntity($entity->getFeedEntityId());
$feed->setType($entity->getFeedType());
if($entity->isFeedTranslatable()) {
$feed->getEnTranslation()->setTitle($entity->getFeedTitle('en'));
}
$em->persist($feed);
$this->needsFlush = true;
}
}
public function postFlush(PostFlushEventArgs $eventArgs)
{
if ($this->needsFlush) {
$this->needsFlush = false;
$eventArgs->getEntityManager()->flush();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-21 01:53:54
Jeśli potrzebujesz utrzymywać dodatkowe obiekty, obsługa postpersist lub postUpdate w Doctrine nie jest, niestety, właściwym miejscem. Zmagałem się dzisiaj z tym samym problemem, ponieważ musiałem wygenerować kilka wpisów wiadomości w tym handlerze.
Problem w tym momencie polega na tym, że obsługa postPersist jest wywoływana Podczas zdarzenia flush, a nie po nim. Nie możesz więc utrzymywać tutaj dodatkowych obiektów, ponieważ nie są one później spłukiwane. Dodatkowo, nie możesz wywołać koloru podczas obsługi postpersyst, ponieważ może to prowadzić do ducplicate wpisy (jak doświadczyłeś).
Jednym ze sposobów jest użycie onflush handler z doctrine, udokumentowane tutaj: http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#onflush
Jest to po prostu problematyczne, jeśli potrzebujesz wstawionych identyfikatorów obiektu database, ponieważ encja nie została jeszcze zapisana do bazy danych w tej funkcji obsługi. Jeśli nie potrzebujesz tych identyfikatorów, jesteś w porządku z wydarzeniem ofFlush w doktrynie.
Dla mnie rozwiązanie było trochę inne. Obecnie pracuję nad projektem symfony2 i potrzebowałem ID wstawionych obiektów bazy danych(dla wywołań zwrotnych i aktualizacji później).Stworzyłem nową usługę w symfony2, która w zasadzie działa jak Kolejka dla moich wiadomości. Podczas aktualizacji postPersist, po prostu wypełniam wpisy w kolejce. Mam inny handler zarejestrowany na kernel.response
, który następnie pobiera te wpisy i utrzymuje je w bazie danych. (Coś wzdłuż linii tego: http://symfony.com/doc/current/cookbook/service_container/event_listener.html )
Mam nadzieję, że nie odbiegam zbytnio od tematu tutaj, ale ponieważ jest to coś, z czym naprawdę się borykałem, mam nadzieję, że niektórzy ludzie mogą uznać to za przydatne.
Wpisy do tego serwisu to:
amq_messages_chain:
class: Acme\StoreBundle\Listener\AmqMessagesChain
amqflush:
class: Acme\StoreBundle\Listener\AmqFlush
arguments: [ @doctrine.orm.entity_manager, @amq_messages_chain, @logger ]
tags:
- { name: kernel.event_listener, event: kernel.response, method: onResponse, priority: 5 }
doctrine.listener:
class: Acme\StoreBundle\Listener\AmqListener
arguments: [ @logger, @amq_messages_chain ]
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: prePersist }
Nie możesz używać doctrine.listener
do tego celu, ponieważ prowadzi to do okrągłej zależności (ponieważ potrzebujesz menedżera encji dla usługi, ale menedżer encji potrzebuje obsługa....)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 17:10:35
[[2]} cóż, oto jak zrobiłem w SF 2.0 i 2.2:
Klasa słuchacza:
<?php
namespace YourNamespace\EventListener;
use Doctrine\ORM\Mapping\PostPersist;
/*
* ORMListener class
*
* @author: Marco Aurélio Simão
* @description: Listener para realizar operações em qualquer objeto manipulado pelo Doctrine 2.2
*/
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\Mapping\PrePersist;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Mapping\PostUpdate;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Enova\EntitiesBundle\Entity\Entidades;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Enova\EntitiesBundle\Entity\Tagged;
use Enova\EntitiesBundle\Entity\Tags;
class ORMListener
{
protected $extra_update;
public function __construct($container)
{
$this->container = $container;
$this->extra_update = false;
}
public function onFlush(OnFlushEventArgs $args)
{
$securityContext = $this->container->get('security.context');
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
$cmf = $em->getMetadataFactory();
foreach ($uow->getScheduledEntityInsertions() AS $entity)
{
$meta = $cmf->getMetadataFor(get_class($entity));
$this->updateTagged($em, $entity);
}
foreach ($uow->getScheduledEntityUpdates() as $entity)
{
$meta = $cmf->getMetadataFor(get_class($entity));
$this->updateTagged($em, $entity);
}
}
public function updateTagged($em, $entity)
{
$entityTags = $entity->getTags();
$a = array_shift($entityTags);
//in my case, i have already sent the object from the form, but you could just replace this part for new Object() etc
$uow = $em->getUnitOfWork();
$cmf = $em->getMetadataFactory();
$meta = $cmf->getMetadataFor(get_class($a));
$em->persist($a);
$uow->computeChangeSet($meta, $a);
}
}
Config.yml:
services:
updated_by.listener:
class: YourNamespace\EventListener\ORMListener
arguments: [@service_container]
tags:
- { name: doctrine.event_listener, event: onFlush, method: onFlush }
Mam nadzieję, że pomoże;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-28 18:48:43
Rozwiązanie firmy jhoffrichter działa bardzo dobrze. Jeśli używasz poleceń konsoli, powinieneś dodać znacznik dla polecenia event.zakończyć. W przeciwnym razie nie działa ON wewnątrz poleceń konsoli. Zobacz https://stackoverflow.com/a/19737608/1526162
Config.yml
amq_messages_chain:
class: Acme\StoreBundle\Listener\AmqMessagesChain
amqflush:
class: Acme\StoreBundle\Listener\AmqFlush
arguments: [ @doctrine.orm.entity_manager, @amq_messages_chain, @logger ]
tags:
- { name: kernel.event_listener, event: kernel.response, method: onResponse, priority: 5 }
- { name: kernel.event_listener, event: command.terminate, method: onResponse }
doctrine.listener:
class: Acme\StoreBundle\Listener\AmqListener
arguments: [ @logger, @amq_messages_chain ]
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: prePersist }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:08