symfony2 migrations getrepository getdoctrine generate delete consultas php doctrine doctrine2

php - migrations - symfony 4 doctrine



¿Cómo comprobar si la entidad cambió en Doctrine 2? (8)

El problema es bastante antiguo, pero aún puede haber algún grupo de personas que puedan enfrentar este problema desde un punto de vista diferente. El UnitOfWork funciona muy bien pero solo devuelve la matriz de cambios. Puede ser una molestia cuando alguien realmente no sabe qué campos pueden haber cambiado y solo quiere que toda la entidad sea un objeto para comparar $oldEntity y $newEntity . A pesar de que el nombre del evento es anterior a la actualización, si alguien intentará obtener los datos de la base de datos de la siguiente manera:

$er->find($id);

La entidad devuelta contendrá todos los cambios. La solución es bastante simple pero tiene algunos ganchos:

public function preUpdate(Entity $entity, PreUpdateEventArgs $args) { $entity = clone $entity; //as Doctrine under the hood //uses reference to manage entities you might want //to work on the entity copy. Otherwise, //the below refresh($entity) will affect both //old and new entity. $em = $args->getEntityManager(); $currentEntity = $em->getRepository(''AppBundle:Entity'')->find($entity->getId()); $em->refresh($currentEntity); }

Para aquellos que están usando otro evento, como preFlush, lo he comprobado rápidamente y la solución no funcionó bien porque probablemente el método refresh() descarta los cambios de descarga, por lo que lo que hay que hacer es llamar a la descarga una vez más en $alreadyFlushed y cree un $alreadyFlushed estático $alreadyFlushed para evitar la referencia circular.

Necesito verificar si una entidad persistente ha cambiado y necesita actualizarse en la base de datos. Lo que hice (y no funcionó) fue lo siguiente:

$product = $entityManager->getRepository(''Product'')->find(3); $product->setName(''A different name''); var_export($entityManager->getUnitOfWork()->isScheduledForUpdate($product));

El código se imprime siempre como false . También intenté vaciar antes de verificar la unidad de trabajo, pero no funcionó.

¿Alguien tiene alguna sugerencia?


Estoy de acuerdo con @Andrew Atkinson cuando dijo:

También es posible que desee ver el evento PreUpdate , si necesita acceder a los campos de entidad con sus valores antiguos y nuevos.

Pero no estoy de acuerdo con el ejemplo que él propuso, según mi experiencia, hay una mejor manera de verificar si algo cambió o no.

<?php class Spock { public function preUpdate(PreUpdateEventArgs $eventArgs) { if (!empty($eventArgs->getEntityChangeSet())) { // fill this how you see fit } } }

De esta manera, el if solo se activará si realmente hay algún campo que haya cambiado o no.

En cuanto a cómo hacerlo si se cambiara este o aquel campo, entonces sí, recomiendo su solución.


Lo primero que verificaría es que su función setName esté haciendo algo ($ this-> name = $ name ...) Si ya está funcionando, entonces podría definir un detector de eventos en su services.yml que se activará cuando llamas al rubor

entity.listener: class: YourName/YourBundle/EventListener/EntityListener calls: - [setContainer, ["@service_container"]] tags: - { name: doctrine.event_listener, event: onFlush }

A continuación, se define el EntityListener

namespace YourName/YourBundle/EventListener; use Doctrine/ORM/Event; use Symfony/Component/DependencyInjection/ContainerAware; class EntityListener extends ContainerAware { /** * Gets all the entities to flush * * @param Event/OnFlushEventArgs $eventArgs Event args */ public function onFlush(Event/OnFlushEventArgs $eventArgs) { $em = $eventArgs->getEntityManager(); $uow = $em->getUnitOfWork(); //Insertions foreach ($uow->getScheduledEntityInsertions() as $entity) { # your code here for the inserted entities } //Updates foreach ($uow->getScheduledEntityUpdates() as $entity) { # your code here for the updated entities } //Deletions foreach ($uow->getScheduledEntityDeletions() as $entity) { # your code here for the deleted entities } } }

Si necesita saber qué entidades se están cambiando, pero haga algo con ellas después de haberlas guardado en la base de datos, simplemente almacene las entidades cambiadas en una matriz privada, y luego defina un evento onFlush que obtenga las entidades de la matriz.

Por cierto, para desencadenar este tipo de eventos, necesita agregar @ORM / HasLifecycleCallbacks en la entidad.


No necesitaba / quería crear Listeners para mi caso, así que terminé con

$product->setName(''A different name''); $uow = $entityManager->getUnitOfWork(); $uow->computeChangeSets(); if ($uow->isEntityScheduled($product)) { // My entity has changed }


Según mis necesidades, las respuestas aquí y los documentos , se me ocurrió la siguiente solución para una marca de tiempo modifiedAt en una entidad.

/** * @Doctrine/ORM/Mapping/PreUpdate() * * @param /Doctrine/ORM/Event/PreUpdateEventArgs $args * @return $this */ public function preUpdateModifiedAt(/Doctrine/ORM/Event/PreUpdateEventArgs $args) { $this->setModifiedAt(new /DateTime(''now'')); return $this; }

Esto se basa en PreUpdate sobre este Event en oposición a los otros disponibles, como PostPersist y PreFlush :

PreUpdate es el evento de uso más restrictivo, ya que se llama justo antes de llamar a una instrucción de actualización para una entidad dentro del método EntityManager # flush (). Tenga en cuenta que este evento no se activa cuando el conjunto de cambios calculado está vacío.

El uso de PreUpdate en contraposición a los demás le permite dejar todos los cálculos y funciones de cálculo intensivo al proceso ya definido por Doctrine. La activación manual del cálculo de los conjuntos de cambios, como en these answers anteriores, requiere una gran cantidad de CPU del servidor. El evento onFlush, tal como se usa en la respuesta aceptada es una opción (en la forma demostrada), pero no si confía en detectar un cambio en la Entidad, como puede preUpdateModifiedAt(PreUpdateEventArgs $args) con la función anterior ( preUpdateModifiedAt(PreUpdateEventArgs $args) ).


También es posible que desee ver el evento PreUpdate , si necesita acceder a los campos de entidad con sus valores antiguos y nuevos.

Un poco de un ejemplo tomado principalmente del enlace proporcionado:

<?php class NeverAliceOnlyBobListener { public function preUpdate(PreUpdateEventArgs $eventArgs) { if ($eventArgs->getEntity() instanceof User) { if ($eventArgs->hasChangedField(''name'') && $eventArgs->getNewValue(''name'') == ''Alice'') { $oldValue = $eventArgs->getOldValue(''name''); $eventArgs->setNewValue(''name'', ''Bob''); } } } }


Tengo curiosidad por Doctrine y todos los que documentan postFlush, ya que en algunos casos, usted tiene una transacción en curso. Me gustaría señalar que también hay postTransactionCommit, que podría ser más seguro dependiendo de lo que está tratando de lograr en el evento postFlush.


Doctrine2 docs. 17. Cambiar las políticas de seguimiento

Si usa la tercera forma (17.3. Notificar) como lo hago yo, puede probar si su entidad ha cambiado haciendo:

$uow = $entityManager->getUnitOfWork(); $uow->computeChangeSets(); $aChangeSet = $uow->getEntityChangeSet($oEntity);

Si nada cambia, regresará una matriz en blanco.