Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Doctrine is in your Lifecycle (with Callbacks)

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

Doctrine is in your Lifecycle (with Callbacks)

Remember when we used StofDoctrineExtensions to set the Event’s slug for us? That magic works by leveraging one of the most powerful features of Doctrine: events. Doctrine gives us the flexibility to have hooks that are called whenever certain things are done, like when an entity is first persisted, updated, or deleted.

Open up Event and remove the @Gedmo annotation above createdAt. Let’s see if we can set this ourselves:

// src/Yoda/EventBundle/Entity/Event.php
// ...

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

Replace this with a new function called prePersist that sets the value:

// src/Yoda/EventBundle/Entity/Event.php
// ...

public function prePersist()
{
    if (!$this->getCreatedAt()) {
        $this->createdAt = new \DateTime();
    }
}

Hey, don’t get too excited! This won’t work yet, but if we could tell Doctrine to call this before inserting an Event, we’d be golden!

The secret is a called lifecycle callbacks: a fancy word for a function that Doctrine will call when something happens, like when an entity is first inserted.

To enable lifecycle callbacks on an entity, add the HasLifecycleCallbacks annotation:

// src/Yoda/EventBundle/Entity/Event.php
// ...

/**
 * @ORM\Table(name="yoda_event")
 * @ORM\Entity(repositoryClass="Yoda\EventBundle\Entity\EventRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Event
{
    // ...
}

Now just put a PrePersist annotation above our function:

// src/Yoda/EventBundle/Entity/Event.php
// ...

/**
 * @ORM\PrePersist
 */
public function prePersist()
{
    if (!$this->getCreated()) {
        $this->createdAt = new \DateTime();
    }
}

PrePersist is called only when an entity is first inserted, and there are other lifecycle events like PreUpdate and PreRemove.

Cool, let’s give it a test! Reload your fixtures and then query to see the events:

php app/console doctrine:fixtures:load
php app/console doctrine:query:sql "SELECT * FROM yoda_event"

The createdAt column is set so this must be working.

Lifecycle callbacks are brilliant because they’re just so easy to setup.

But they have one big limitation. Because the callback is inside an entity, we don’t have access to the container or any services. This wasn’t a problem here, but what if we needed to access the router or the logger?

The solution is to use a slight spin on lifecycle callbacks: events.

Leave a comment!

3
Login or Register to join the conversation
Agnes Avatar

I had to add the setCreatedAt() method for this to work. I think it wasn't necessary with Gedmo.

Reply
Default user avatar

Yep... There is a problem in this lesson.

you have to add setCreatedAt, smth. like this:
public function setCreatedAt( $createdAt)
{
$this->createdAt = $createdAt;
}

Or change a bit prePrrsist, smth. like this:
/**
* @ORM\PrePersist
*/
public function prePersist()
{
if ( !$this->getCreatedAt())
$this->createdAt = new \DateTime();
}

1 Reply

Thanks - code block fixed - https://github.com/knpunive... In the video, I don't have a setCreatedAt method, so I changed things to user the property. This isn't on accident - I usually don't make setter methods until I actually need to set things from outside the class.

Cheers!

1 Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "~2.4", // v2.4.2
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.0.1
        "symfony/assetic-bundle": "~2.3", // v2.3.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.5
        "symfony/monolog-bundle": "~2.4", // v2.5.0
        "sensio/distribution-bundle": "~2.3", // v2.3.4
        "sensio/framework-extra-bundle": "~3.0", // v3.0.0
        "sensio/generator-bundle": "~2.3", // v2.3.4
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
        "ircmaxell/password-compat": "~1.0.3", // 1.0.3
        "phpunit/phpunit": "~4.1", // 4.1.0
        "stof/doctrine-extensions-bundle": "~1.1.0" // v1.1.0
    }
}
userVoice