Timestampable

Timestampable

Stores when an entity was created and last changed.

Entity

use Doctrine\ORM\Mapping as ORM;
use Ufo\DoctrineBehaviors\Contract\Entity\TimestampableInterface;
use Ufo\DoctrineBehaviors\Model\Timestampable\TimestampableTrait;

#[ORM\Entity]
class Category implements TimestampableInterface
{
    use TimestampableTrait;

    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;
}

How it works

  • On loadClassMetadata the bundle maps createdAt and updatedAt (nullable, type from the doctrine_behaviors_timestampable_date_field_type parameter, datetime by default) and adds the updateTimestamps() lifecycle callback on prePersist and preUpdate. The #[ORM\HasLifecycleCallbacks] attribute is not needed.
  • updateTimestamps() sets createdAt if it is still null and always updates updatedAt. The time has microseconds and uses the date_default_timezone_get() time zone.
  • Doctrine calls preUpdate only for entities with changed fields — a flush() without changes leaves updatedAt alone.
  • #[ORM\MappedSuperclass] is skipped; the columns go to the child entities.

Usage

$category = new Category();
$entityManager->persist($category);
$entityManager->flush();

$category->getCreatedAt(); // DateTime
$category->getUpdatedAt(); // DateTime

setCreatedAt() and setUpdatedAt() let you set values manually; a createdAt set this way is not overwritten on save.

Configuration

# config/services.yaml
parameters:
    doctrine_behaviors_timestampable_date_field_type: datetimetz

The trait writes DateTime, so only mutable types fit — datetime and datetimetz. The *_immutable types expect DateTimeImmutable and are not compatible.