1

I am trying to make an abstract class to extend my entity from in order to give them some basic functionalities such as automatic timestamp.

So I created this abstract class:

/**
 * Class Model
 * @package AppBundle
 * @ORM\MappedSuperclass
 */
abstract class Model 
{
    /**
     * @var \DateTime $created_at
     *
     * @ORM\Column(type="datetime")
     */
    protected $created_at;

    /**
     * @var \DateTime $updated_at
     *
     * @ORM\Column(type="datetime")
     */
    protected $updated_at;

    /**
     *
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function updatedTimestamps()
    {
        $this->setUpdatedAt(new \DateTime('now'));

        if ($this->getCreatedAt() == null) {
            $this->setCreatedAt(new \DateTime('now'));
        }
    }

   public function getUpdatedAt()
   {
       return $this->updated_at;
   }

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

   public function getCreatedAt()
   {
       return $this->created_at;
   }

   public function setCreatedAt($created_at)
   {
       $this->created_at = $created_at;
       return $this;
   }

}

So now, I just need to extend my entity from this class:

class MyEntity extends Model 
{
    ....
}

However, if I want my timestamps to work, I still need to add the @ORM\HasLifecycleCallbacks on top of MyEntity class to trigger the updatedTimestamps() method on persist and on update.

I tried to add the annotation on top of my super class but it does not work.

Would someone have a solution to avoid to add the annotation on top of every entity?

I just want to extend my superclass and that's it...

Thank you for your answers and have a nice day!

Hammerbot
  • 15,696
  • 9
  • 61
  • 103

1 Answers1

1

I implements it on a previous project, the annotation on MappedSuperclass work. The anotation I used is @ORM\HasLifecycleCallbacks() with the parenthesis, and not @ORM\HasLifecycleCallbacks.

This is how I done it (I give all the MappedSuperclass code in a didactic way):

AbstractGenericEntity.php

namespace Services\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass
 * @ORM\HasLifecycleCallbacks()
 */
class AbstractGenericEntity
{
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="Z_CREATION_DATE", type="datetime", nullable=false)
     */
    private $dateCreation;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="Z_UPDATE_DATE", type="datetime", nullable=false)
     */
    private $dateMaj;


    // I just need this getter
    public function getUpdateDate($format= 'Y-m-d h:i:s:u') {
        return $this->dateMaj->format($format) ;
    }

    /**
     * @return AbstractGenericEntity
     * @ORM\PreUpdate
     */
    public function preUpdateCallback()
    {
        $this->dateMaj = new \DateTime("now");
        return $this;
    }

    /**
     * @return AbstractGenericEntity
     * @ORM\PrePersist
     */
    public function prePersistCallback()
    {
        $this->preUpdateCallback();
        $this->dateCreation = new \DateTime("now");
        return $this;
    }
}

And all my entities inherit of this super-class, without any special other annotation:

namespace Services\Entity;

use Doctrine\ORM\Mapping as ORM;
use Services\Entity\AbstractGenericEntity;

/**
 * @ORM\Table(name="MY_TABLE_NAME")
 * @ORM\Entity (repositoryClass="Services\Repositories\MyEntityRepository")
 */
class MyEntity extends AbstractGenericEntity
{
    public function __construct()
    {
        $this->id = uniqid('', true);
    }

    /**
     * @var string
     *
     * @ORM\Column(name="ID", type="string", length=23, nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="NONE")
     *
     */
    private $id;

    // etc, as usual...
Al Foиce ѫ
  • 4,195
  • 12
  • 39
  • 49
  • Well, I must have made an error somewhere else, thank you for your time, I will let you know! – Hammerbot Oct 21 '16 at 13:33
  • Check the parenthesis on `@ORM\HasLifecycleCallbacks()`. – Al Foиce ѫ Oct 21 '16 at 13:36
  • Sadly, this doesn't work, I still get a `SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null` on creation... My Symfony version is `2.8.*`, don't know if something changed somewhere... I tried with and without the parenthesis. – Hammerbot Oct 21 '16 at 14:40
  • Some hint here: http://stackoverflow.com/questions/7320425/doctrine-2-lifecyclecallbacks-with-abstract-base-class-are-not-called one answer says: "It is important that the MappedSuperclass with HasLifecycleCallbacks is in the same namespace or directory as their child Entities." and that is not the case for me. – Hammerbot Oct 21 '16 at 14:43
  • Sure. It works this way in my Symfony 2.8.12 but also in a ZendFramework2.4 application, it is not Symfony related but Doctrine2 specific. – Al Foиce ѫ Oct 21 '16 at 14:45
  • Does your SuperClass have the same namespace as your entities? – Hammerbot Oct 21 '16 at 14:48
  • 1
    Yes. You can also work with Doctrine2 events in Symfony, as discussed here http://stackoverflow.com/questions/39332767/symfony-get-connected-user-id-from-entity It will works even if you have several namespaces. – Al Foиce ѫ Oct 21 '16 at 14:48
  • Ho, you are right, I forgot the listeners! That would be the best answer I think! However, I still think that "my way to do it" that is yours too should work. I'd love to make a github issue but they already have 976 opened issues and this problem looks to be very old, I'd love to have their opinion on this... Anyway, thank you for your time, I'm going to do it with listeners! – Hammerbot Oct 21 '16 at 14:53