Concerns و Traits
Weaver ORM provides built-in concerns — PHP traits that add common behaviour (timestamps, soft deletes, UUID generation) to entities and their mappers. They follow the same explicit-mapping philosophy: each concern contributes both the entity-side PHP logic and the mapper-side column definitions.
HasTimestamps
Automatically manages created_at and updated_at columns. When an entity is first persisted, both timestamps are set. On every subsequent update, updated_at is refreshed to the current time.
Entity trait
<?php
// src/Entity/Post.php
declare(strict_types=1);
namespace App\Entity;
use DateTimeImmutable;
use Weaver\ORM\Concerns\HasTimestamps;
final class Post
{
use HasTimestamps;
public function __construct(
public readonly ?int $id,
public readonly string $title,
public readonly string $body,
// HasTimestamps adds:
// public readonly DateTimeImmutable $createdAt
// public readonly ?DateTimeImmutable $updatedAt
) {}
}
Mapper trait
<?php
// src/Mapper/PostMapper.php
declare(strict_types=1);
namespace App\Mapper;
use App\Entity\Post;
use Weaver\ORM\Mapping\AbstractMapper;
use Weaver\ORM\Mapping\ColumnDefinition;
use Weaver\ORM\Mapping\SchemaDefinition;
use Weaver\ORM\Concerns\Mapper\HasTimestampsMapper;
final class PostMapper extends AbstractMapper
{
use HasTimestampsMapper;
public function table(): string { return 'posts'; }
public function primaryKey(): string { return 'id'; }
public function schema(): SchemaDefinition
{
return SchemaDefinition::define(
ColumnDefinition::integer('id')->autoIncrement()->unsigned(),
ColumnDefinition::string('title')->notNull(),
ColumnDefinition::text('body')->notNull(),
...$this->timestampColumns(), // adds created_at, updated_at
);
}
public function hydrate(array $row): Post
{
return new Post(
id: (int) $row['id'],
title: $row['title'],
body: $row['body'],
createdAt: new \DateTimeImmutable($row['created_at']),
updatedAt: isset($row['updated_at'])
? new \DateTimeImmutable($row['updated_at'])
: null,
);
}
public function dehydrate(object $entity): array
{
return [
'id' => $entity->id,
'title' => $entity->title,
'body' => $entity->body,
// HasTimestampsMapper::dehydrateTimestamps() handles the rest
...$this->dehydrateTimestamps($entity),
];
}
}
Generated columns
created_at DATETIME NOT NULL,
updated_at DATETIME NULL,
Behaviour
| Action | created_at | updated_at |
|---|---|---|
save() on new entity (id is null) | Set to now() | Set to now() |
save() on existing entity | Unchanged | Set to now() |
| Manual override | Set explicitly if passed to constructor | Set explicitly if passed to constructor |
HasSoftDeletes
Adds a deleted_at timestamp column. Instead of issuing a DELETE statement, Weaver sets deleted_at = now(). All subsequent queries automatically exclude soft-deleted rows unless you opt in with withTrashed() or onlyTrashed().
Entity trait
<?php
// src/Entity/User.php
declare(strict_types=1);
namespace App\Entity;
use DateTimeImmutable;
use Weaver\ORM\Concerns\HasSoftDeletes;
use Weaver\ORM\Concerns\HasTimestamps;
final class User
{
use HasTimestamps;
use HasSoftDeletes;
public function __construct(
public readonly ?int $id,
public readonly string $name,
public readonly string $email,
// HasTimestamps adds: createdAt, updatedAt
// HasSoftDeletes adds: ?deletedAt
) {}
public function isDeleted(): bool
{
return $this->deletedAt !== null;
}
}