registrando comportamiento de doctrine como servicio

71 views
Skip to first unread message

Marcelo Prizmic

unread,
Nov 5, 2012, 2:10:53 PM11/5/12
to symfo...@googlegroups.com, symfony-2...@googlegroups.com
hola
Estoy tratando de generar un comportamiento de doctrine de manera que en una entidad actualice siempre el campo updatedAt.
Para eso creo un servicio y un listener

<?php

namespace Fd\EstablecimientoBundle\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;

class GrabaFechaComportamiento {

    public function prePersist(LifecycleEventArgs $args) {
        $entity = $args->getEntity();

        $entity->setUpdate();
    }
}

services:
    fd.graba_fecha_comportamiento:
        class: Fd\EstablecimientoBundle\Listener\GrabaFechaComportamiento
        tags:
            - { name: doctrine.event_listener, event: prePersist, method: prePersist } 


En la entidad tengo

    /**
     * @ORM\Column(type="datetime")
     * @var type
     */
    private $updatedAt;

    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;
    }

    public function setUpdate(){
        $this->setUpdatedAt(new \DateTime());
    }

El supuesto es que al grabar el servicio debe actualizar siempre el campo updatedAt pero no lo hace
Alguien ve algún error o sabe que me falta'
gracias!!
marcelo

Jakala

unread,
Nov 5, 2012, 2:39:31 PM11/5/12
to symfo...@googlegroups.com, symfony-2...@googlegroups.com
buenas:

tengo entendido que el metodo prePersist se lanza en la creación de un elemento. No seria mejor que el servicio se ejecute en el evento preupdate???
Por lo que entiendo del codigo, lo que haces es ejecutarlo solo al evento de prepersist. Podrias probar si te crea correctamente la fecha cuando creas un item.

Creo que hay que cambiar el metodo prePersist y el evento correspondiente por el preUpdate. Pruebalo y nos cuentas, ok?

Fran Moreno

unread,
Nov 6, 2012, 4:38:04 PM11/6/12
to symfo...@googlegroups.com, symfony-2...@googlegroups.com
Buenas,

Como comenta Jakala deberías ejecutarlo tanto en el prePersist como en el preUpdate, de todas formas yo usaría eventos a nivel de Entity, así como lo tienes se va a ejecutar ese código cuando persistas cualquier entidad y si la entidad no tiene el método setUpdate fallará se supone, entonces como comentaba, yo lo haría a nivel de Entity:


Saludos


El lunes, 5 de noviembre de 2012 20:11:17 UTC+1, mepk escribió:

Marcelo Prizmic

unread,
Nov 6, 2012, 6:26:41 PM11/6/12
to symfo...@googlegroups.com
Fran
Lo que decís lo probé y anda perfecto. Pero hay que codificar cada entidad. La solución que estoy tratando de hacer andar sirve para todas las entidades.
Probé lo que me mencionan Diego y Jakala pero hay algo que se me está escapando.
Me basé en

http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html

Estoy trabajando con SF2.0.17
Gracias a todos
Marcelo

--
Has recibido este mensaje porque estás suscrito al grupo "symfony-es" de Google Groups.
Para publicar en este grupo, envía un email a symfo...@googlegroups.com
Para darte de baja, envía un email a symfony-es+...@googlegroups.com
El resto de opciones puedes encontrarlas en http://groups.google.com/group/symfony-es?hl=es

Marcelo Prizmic

unread,
Nov 7, 2012, 10:09:13 AM11/7/12
to symfo...@googlegroups.com
Seguí probando y creo que es un bug.
Haciendo debug step by step vi que el listener es invocado y que el método que asocié al evento se ejecuta.
lo que sucede es que el EntityType no tiene esos 2 datos para mostrar en la página porque son los timestamp, entonces al momento de procesar el persist y el flush, como estos datos no existían en el EntityType, simplemente los ignora y no los procesa. Sólo actualiza los atributos del Entity que estaban en el EntityType.
si a estos 2 atributos los pongo en el EntityType como 'hidden' me tira error pues son tipo DateTime y no lo puede pasar a string (pese a que estén hidden)
Eso es todo. Espero que en 2.1 funcione.
Marcelo

Marcelo Prizmic

unread,
Nov 7, 2012, 10:16:19 AM11/7/12
to symfo...@googlegroups.com
Faltaba el último código, tal cual lo probé.


<?php

namespace Fd\EstablecimientoBundle\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;
//use Fd\EdificioBundle\Entity\Edificio;

class GrabaFechaComportamiento {

    public function preUpdate(LifecycleEventArgs $args) {

        $entity = $args->getEntity();
        $entity->setUpdate();
    }
}


en el services.yml

    fd.updatedAt.listener:

        class: Fd\EstablecimientoBundle\Listener\GrabaFechaComportamiento
        tags:
            - { name: doctrine.event_listener, event: preUpdate }


/**
 * Fd\TablaBundle\Entity\Barrio
 *
 * @ORM\Table(name="barrio")
 * @ORM\Entity
 */
class Barrio
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string $nombre
     *
     * @ORM\Column(name="nombre", type="string", length=50, nullable=true)
     */
    private $nombre;
    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @var type
     */
    private $createdAt;
    /**
     * @ORM\Column(type="datetime", nullable=true)
     * @var type
     */
    private $updateAt;
    /**
     * @var string $abreviatura
     *
     * @ORM\Column(name="abreviatura", type="string", length=5, nullable=true)
     */
    private $abreviatura;

    public function setUpdate(){
        $this->setUpdateAt(new \DateTime("now"));
    }
    public function __toString() {
        return $this->getNombre();
    }
    public function __construct() {
        $this->createdAt = new \DateTime("now");
        $this->updateAt = new \DateTime("now");
    }




Fran Moreno

unread,
Nov 8, 2012, 9:03:29 PM11/8/12
to symfo...@googlegroups.com
Buenas,

Si lo quieres hacer así, a malas siempre puedes añadirle display:none en el Type en vez de hidden:

->add('updateAt', null, array(
    'attr' => array(
        'style' => 'display:none;'
    )
))

De todas formas me parece raro que si salta el listener y se ejecuta el $entity->setUpdate() no funcione, bueno faltaría ver que la función setUpdateAt está bien. Otra cosa es que cuando guardes y llames a persist sobre la entity al no haber cambiado nada no detecta que hay cambios y no lanza los eventos. Bueno no sé si te habrá ayudado algo.

Saludos

Marcelo Prizmic

unread,
Nov 8, 2012, 9:09:01 PM11/8/12
to symfo...@googlegroups.com
En realidad se ejecuta, lo que pasa es que como el timestamp no es parte del Type, no lo procesa.
Por ahora no le he encontrado la solución.
Marcelo

aprendizenlared

unread,
Nov 10, 2012, 5:24:28 PM11/10/12
to symfo...@googlegroups.com
Bueno es la primera vez que escribo creo xD espero ser de ayuda.

Una opción sencilla podría ser usar un bundle de extensiones de Doctrine que puedes decir que sean timestampables. Lo puedes ver en la documentación de symfony: http://symfony.com/doc/master/cookbook/doctrine/common_extensions.html

si lo quieres hacer por tu propia cuenta usando los HasLifecycleCallbacks pero sí, tiene el inconveniente de tener que hacerlo uno a uno a mano. (ahora me entra la duda si se podría hacer una clase entidad padre que tenga estos campos comunes y que todos extiendan de ella... pero bueno son invenciones mías xD)

Sobre lo que estas haciendo creo que debería funcionar (no tienes que añadir esos campos al Type pues no los usaras) aunque creo que podrías llamar directamente a setUpdateAt sin crear un método intermedio. yo creo que una vez utilice algo así para ejectuar algo en el update de ciertas entidades... pero no me acuerdo ahora si guardaba algo en la base de datos o no. Sin mucho conocimiento del tema mirando tu código están vien los argumentos del preUpdate? me suenan que esos eran para el persist, yo creo que usaba PreUpdateEventArgs, aunque me suena que ami me tiraba error, nose...

Marcelo Prizmic

unread,
Nov 12, 2012, 8:27:01 AM11/12/12
to symfo...@googlegroups.com
el bundle que mencionás es mejor que hacerlo uno desde cero, pero estaba haciendo pruebas para aprender.
Reply all
Reply to author
Forward
0 new messages