andanteproject/timestampable-bundle
Symfony bundle for Doctrine entities that automatically manages createdAt and updatedAt with DateTimeImmutable. Zero config to start, customizable, uses Symfony Clock, no attributes needed, and won’t overwrite timestamps you set manually. Compatible with Symfony 5–8, PHP 8.2.
Installation:
composer require andanteproject/timestampable-bundle
Register the bundle in config/bundles.php (Symfony Flex handles this automatically).
Enable for an Entity:
Add TimestampableInterface and TimestampableTrait to your entity:
use Andante\TimestampableBundle\Timestampable\{TimestampableInterface, TimestampableTrait};
#[ORM\Entity]
class Article implements TimestampableInterface
{
use TimestampableTrait;
// ... existing fields
}
Update Schema:
Run migrations or schema updates to add created_at and updated_at columns.
Audit Logging: Track when records are created/updated without manual timestamp management. Example:
$article = new Article('New Post');
$entityManager->persist($article); // Automatically sets `createdAt` and `updatedAt`
Default Usage (Traits + Interfaces):
TimestampableTrait for both createdAt and updatedAt.Selective Timestamping:
createdAt:
use Andante\TimestampableBundle\Timestampable\{CreatedAtTimestampableInterface, CreatedAtTimestampableTrait};
class Article implements CreatedAtTimestampableInterface
{
use CreatedAtTimestampableTrait;
}
updatedAt:
use Andante\TimestampableBundle\Timestampable\{UpdatedAtTimestampableInterface, UpdatedAtTimestampableTrait};
class Article implements UpdatedAtTimestampableInterface
{
use UpdatedAtTimestampableTrait;
}
Custom Property/Column Names:
Override defaults in config/packages/andante_timestampable.yaml:
andante_timestampable:
default:
created_at_property_name: createdOn
updated_at_column_name: last_modified
prePersist/preUpdate to log actions before timestamps update.createdAt/updatedAt in serializers for consistent JSON responses.php bin/console make:migration
php bin/console doctrine:migrations:migrate
Metadata Cache Stale:
php bin/console cache:clear
metadata_cache_warmer_enabled: true in production to avoid first-request delays.Explicit Overrides:
createdAt/updatedAt values. To force updates:
$article->setUpdatedAt(null); // Triggers auto-update
Naming Conflicts:
createdAt/updatedAt properties, exclude them from Doctrine mapping:
#[ORM\Column(ignore: true)]
private ?\DateTimeImmutable $createdAt;
%kernel.cache_dir%/timestampable_metadata.php.symfony/clock for testing time-sensitive logic:
$this->clock = new FrozenClock(new \DateTimeImmutable('2023-01-01'));
Custom Time Sources:
Inject a custom ClockInterface via dependency injection:
services:
App\Service\CustomClock:
arguments:
$clock: '@andante_timestampable.clock'
Event Subscribers:
Extend timestamp logic via TimestampableEvents:
use Andante\TimestampableBundle\Event\TimestampableEvents;
$dispatcher->addListener(TimestampableEvents::PRE_UPDATE, function ($event) {
if ($event->getEntity() instanceof Article) {
// Custom logic
}
});
Legacy Systems: Use the "no-trait" approach for entities with non-standard property names:
class LegacyArticle implements TimestampableInterface
{
private ?\DateTimeImmutable $created = null;
private ?\DateTimeImmutable $modified = null;
// Implement getters/setters for `created`/`modified`
}
Configure in andante_timestampable.yaml:
andante_timestampable:
entity:
App\Entity\LegacyArticle:
created_at_property_name: created
updated_at_property_name: modified
How can I help you explore Laravel packages today?