Timestamped
#[Silverback\Timestamped] automatically populates createdAt and modifiedAt on persist and flush. It's a lightweight annotation with no configuration required — add it and forget it.
Setup
use Silverback\ApiComponentsBundle\Annotation as Silverback;
use Silverback\ApiComponentsBundle\Entity\Core\AbstractComponent;
use Silverback\ApiComponentsBundle\Entity\Utility\TimestampedTrait;
#[Silverback\Timestamped]
#[ORM\Entity]
#[ApiResource(mercure: true)]
class Article extends AbstractComponent
{
use TimestampedTrait;
}
What TimestampedTrait Adds
| Property | Type | Behaviour |
|---|---|---|
createdAt | ?\DateTimeImmutable | Set once on first persist; never updated after that |
modifiedAt | ?\DateTime | Updated on every Doctrine flush |
Both are serialized and included in API responses automatically. They are read-only from the API — the bundle manages them, not the client.
Customising Field Names
The default names are createdAt and modifiedAt, matching TimestampedTrait. If those names conflict with your own fields, override them:
#[Silverback\Timestamped(createdAtField: 'publishedOn', modifiedAtField: 'lastEdited')]
When using custom names you must define the properties and getters/setters yourself rather than using TimestampedTrait:
#[Silverback\Timestamped(createdAtField: 'publishedOn', modifiedAtField: 'lastEdited')]
#[ORM\Entity]
#[ApiResource]
class Article extends AbstractComponent
{
#[ORM\Column(nullable: true)]
public ?\DateTimeImmutable $publishedOn = null;
#[ORM\Column(nullable: true)]
public ?\DateTime $lastEdited = null;
}
Combining with Publishable
Timestamps and publish workflow are commonly used together for blog-style content:
#[Silverback\Publishable]
#[Silverback\Timestamped]
#[ORM\Entity]
#[ApiResource(mercure: true)]
class Article extends AbstractComponent
{
use PublishableTrait;
use TimestampedTrait;
public ?string $headline = null;
}
The createdAt and modifiedAt fields reflect the draft entity's lifecycle. The published twin gets its own timestamps set when it's first created.
Using Timestamps on the Front-End
Access them via resource.value?.data:
const resource = getResource()
const createdAt = computed(() =>
resource.value?.data?.createdAt
? new Date(resource.value.data.createdAt).toLocaleDateString()
: ''
)
Both properties are ISO 8601 strings in the API response. Use Intl.DateTimeFormat or a library like date-fns to format them for display.
Migration Notes
TimestampedTrait adds two nullable columns to your entity's table. The migration is straightforward — no foreign keys or join tables involved. createdAt is a datetime_immutable column; modifiedAt is a datetime column.