Buy

Activating Timestampable

Ok, let's add Timestampable! First, we need to activate it, which again, is described way down on the bundle's docs. Open config/packages/stof_doctrine_extensions.yaml, and add timestampable: true:

9 lines config/packages/stof_doctrine_extensions.yaml
... lines 1 - 2
stof_doctrine_extensions:
default_locale: en_US
orm:
default:
sluggable: true
timestampable: true

Second, your entity needs some annotations. For this, go back to the library's docs. Easy enough: we just need @Gedmo\Timestampable.

Back in our project, open Article and scroll down to find the new fields. Above createdAt, add @Timestampable() with on="create":

192 lines src/Entity/Article.php
... lines 1 - 10
class Article
{
... lines 13 - 55
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
... lines 61 - 190
}

Copy that, paste above updatedAt, and use on="update":

192 lines src/Entity/Article.php
... lines 1 - 10
class Article
{
... lines 13 - 61
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
... lines 67 - 190
}

That should be it! Find your terminal, and reload the fixtures!

php bin/console doctrine:fixtures:load

No errors... but, let's make sure it's actually working. Run:

php bin/console doctrine:query:sql 'SELECT * FROM article'

Yes! They are set! And each time we update, the updated_at will change.

The TimestampableEntity Trait

I love Timestampable. Heck, I put it everywhere. And, fortunately, there is a shortcut! Yea, we did way too much work.

Check it out: completely delete the createdAt and updatedAt fields that we so-carefully added. And, remove the getter and setter methods at the bottom too:

192 lines src/Entity/Article.php
... lines 1 - 10
class Article
{
... lines 13 - 55
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
... lines 67 - 167
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(?\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
}

But now, all the way on top, add use TimestampableEntity:

159 lines src/Entity/Article.php
... lines 1 - 6
use Gedmo\Timestampable\Traits\TimestampableEntity;
... lines 8 - 11
class Article
{
use TimestampableEntity;
... lines 15 - 157
}

Yea! Hold Command or Ctrl and click to see that. Awesome: this contains the exact same code that we had before! If you want Timestampable, just use this trait, generate a migration and... done!

And, talking about migrations, there could be some slight column differences between these columns and the original ones we created. Let's check that. Run:

php bin/console make:migration

No database changes were detected

Cool! The fields in the trait are identical to what we had before. That means that we can already test things with:

php bin/console doctrine:fixtures:load

Thank you TimestampableEntity!

Up Next: Relations!

Ok guys! I hope you are loving Doctrine! We just got a lot of functionality fast. We have magic - like Timestampable & Sluggable - rich data fixtures, and a rocking migration system.

One thing that we have not talked about yet is production config. And... that's because it's already setup. The Doctrine recipe came with its own config/packages/prod/doctrine.yaml config file, which makes sure that anything that can be cached easily, is cached:

32 lines config/packages/prod/doctrine.yaml
doctrine:
orm:
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
services:
doctrine.result_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.result_cache_pool'
doctrine.system_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.system_cache_pool'
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

This means you get nice performance, out-of-the-box.

The other huge topic that we have not talked about yet is Doctrine relations. But, we should totally talk about those - they're awesome! So let's do that in our next tutorial, with foreign keys, join queries and high-fives so that we can create a really rich database.

Alright guys, seeya next time.

Leave a comment!