Doctrine postPersist / postUpdate events not firing in Symfony 2?

So let’s say you’ve been tinkering about with the example given on the Symfony 2 manual page for configuring a Doctrine Event Subscriber.

All is good.

Maybe you’ve been through and configured it just like the example, added a subscriber, re-run your fixtures, and everything is tickedyboo.

But then you make a few changes to the subscriber implementation. Maybe it should do something a little differently, and you want to re-save the entity, and get the new implementation to take effect.

Only, it won’t.

You tinker about some more, and everything looks sane. But for some reason, when you go to your form, change nothing, and click the Submit button, the listener just doesn’t seem to take effect.

Strange, eh?

Not exactly.

See, there’s a big ol’ list of lifecycle events that you can hook into, and do funky things with.

But each one has a weird, technical description that doesn’t quite seem to explain what it does in a way that’s easy to comprehend.

If you followed the Symfony documentation example, you might think a postUpdate or postPersist would be triggered whenever you Submit the form. After all, if you stick some debugs in your code, you can see the entity is persisted and the unit of work is flushed.

But yet, your listener doesn’t fire.

Try changing the data in your form, though, and suddenly the listener is triggered.

I’m 100% sure this isn’t a bug. It’s a misunderstanding.

But if you’ve been sat tearing your hair out as to why this damn thing just won’t do your bidding for the last 30 minutes, the only sane solution is to blog about it, and move on.

Hopefully this will save you a headache or two.

Using LifecycleCallbacks for CreatedAt and UpdatedAt in Symfony 2

It's a life cycle. *Tumbleweed*

[Update: May 2015 – This post has been updated with videos]

Lifecycle Callbacks are a super helpful bit of code that I use in a good number of my entities.

They are scary sounding and the documentation on the Symfony 2 official docs doesn’t give a detailed enough demonstration (in my opinion) to explain to the new Symfony user how useful they are.

So, rather than waffle on, I will give a bit of handy code that you can steal and re-use.

namespace MCM\MyExampleBundle\Entity;

// some use statements here

/**
 * MyPretendEntity
 *
 * @ORM\Table(name="my_table_name")
 * @ORM\Entity(repositoryClass="\MCM\MyExampleBundle\Repository\MyPretendRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class MyPretendEntity
{
    // snip snip snip

    /**
     * created Time/Date
     *
     * @var \DateTime
     *
     * @ORM\Column(name="created_at", type="datetime", nullable=false)
     */
    protected $createdAt;

    /**
     * updated Time/Date
     *
     * @var \DateTime
     *
     * @ORM\Column(name="updated_at", type="datetime", nullable=false)
     */
    protected $updatedAt;

    // snip snip snip

    /**
     * Set createdAt
     *
     * @ORM\PrePersist
     */
    public function setCreatedAt()
    {
        $this->createdAt = new \DateTime();
        $this->updatedAt = new \DateTime();
    }

    /**
     * Get createdAt
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt
     *
     * @ORM\PreUpdate
     */
    public function setUpdatedAt()
    {
        $this->updatedAt = new \DateTime();
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
}

I have seen this done other ways – some people use only one method for both.

The implementation is up to you – but do remember to use the correct annotations – @ORM\HasLifecycleCallbacks() , @ORM\PrePersist , and @ORM\PreUpdate.

There are some other events you can interact with, so be sure to check out the official docs – they become much more useful now that you understand how they work.

Doctrine Schema Validation Problems, and how to fix them

Doctrine has a habit of throwing strange errors my way – usually when things look like they should just work.

As I encounter more of them, I will add them below.

The referenced column name ‘your_field_name’ has to be a primary key column on the target entity class ‘My\FriendlyBundle\Entity\EntityName’

You may be thinking – well, just add the primary key, as it’s suggesting. But no, that would have been silly.

Instead, as is usually the case, I deleted the problem fields on both ends, and recreated them using my MySQL tool of choice, SQLyog.

After that, the foreign key relationship was recreated. Then I ran:

php app/console doctrine:mapping:import CoreDatabaseBundle annotation

followed by:

php app/console doctrine:schema:validate

And the entities were magically happy again.

This fix works well for many doctrine issues I find.