← スキル一覧に戻る

doctrine-mapping
by dairectiv
⭐ 0🍴 0📅 2026年1月3日
SKILL.md
name: doctrine-mapping description: Guide for Doctrine entity/aggregate mapping conventions. Use when mapping entities, configuring relationships, or adding custom types. allowed-tools: Read, Write, Edit, Glob, Grep
Doctrine Mapping Guide
This Skill provides conventions for mapping entities with Doctrine ORM.
When to Use
- Mapping a new aggregate or entity
- Adding relationships (OneToMany, ManyToOne)
- Configuring custom types
- Understanding naming conventions
Configuration
Doctrine is configured in api/config/packages/doctrine.yaml:
doctrine:
dbal:
types:
# Custom types registered here
chronos: Dairectiv\SharedKernel\Infrastructure\Doctrine\DBAL\Types\ChronosType
authoring_directive_id: Dairectiv\Authoring\Infrastructure\Doctrine\DBAL\Types\DirectiveIdType
orm:
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
mappings:
Authoring:
type: attribute
dir: '%kernel.project_dir%/src/Authoring/Domain'
prefix: 'Dairectiv\Authoring\Domain'
Key points:
- Uses
underscore_number_awarenaming strategy (camelCase → snake_case) - Mappings are per bounded context
- Entities live in Domain layer but use Doctrine attributes
Entity Mapping
Basic Entity
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'authoring_directive')]
class Directive extends AggregateRoot
{
#[ORM\Id]
#[ORM\Column(type: 'authoring_directive_id')]
public private(set) DirectiveId $id;
#[ORM\Column(type: Types::STRING)]
public private(set) string $name;
#[ORM\Column(type: Types::TEXT)]
public private(set) string $description;
#[ORM\Column(type: 'chronos')]
public private(set) Chronos $createdAt;
}
Table Naming
- Use explicit
#[ORM\Table(name: '...')]for aggregate roots - Format:
{bounded_context}_{aggregate}(e.g.,authoring_directive) - Child entities inherit table from single table inheritance or get own table
Column Naming
The underscore_number_aware strategy handles column naming automatically:
createdAt→created_atdirectiveId→directive_id
For explicit naming, use the name parameter:
#[ORM\Column(name: 'workflow_content', type: Types::TEXT, nullable: true)]
public private(set) ?string $content = null;
Property Visibility
Use PHP 8.4 asymmetric visibility:
// Public read, private write
public private(set) DirectiveId $id;
// Nullable property
public private(set) ?string $content = null;
Custom Types
Reference custom types by their registered name in doctrine.yaml:
// Custom type for value objects
#[ORM\Column(type: 'authoring_directive_id')]
public private(set) DirectiveId $id;
// Custom type for dates
#[ORM\Column(type: 'chronos')]
public private(set) Chronos $createdAt;
// Built-in types from Doctrine\DBAL\Types\Types
#[ORM\Column(type: Types::STRING)]
#[ORM\Column(type: Types::TEXT)]
#[ORM\Column(type: Types::INTEGER)]
#[ORM\Column(type: Types::BOOLEAN)]
Relationships
OneToMany (Parent → Children)
/**
* @var Collection<int, Example>
*/
#[ORM\OneToMany(
targetEntity: Example::class,
mappedBy: 'rule',
cascade: ['persist'],
orphanRemoval: true,
fetch: 'EAGER'
)]
public private(set) Collection $examples;
Options:
cascade: ['persist']- Auto-persist children when parent is savedorphanRemoval: true- Delete children when removed from collectionfetch: 'EAGER'- Load children immediately (use for small collections)
ManyToOne (Child → Parent)
#[ORM\ManyToOne(targetEntity: Rule::class, inversedBy: 'examples')]
#[ORM\JoinColumn(nullable: false)]
public private(set) Rule $rule;
Ordered Collections
#[ORM\OneToMany(targetEntity: Step::class, mappedBy: 'workflow', ...)]
#[ORM\OrderBy(['order' => 'ASC'])]
public private(set) Collection $steps;
Inheritance
Single Table Inheritance
#[ORM\Entity]
#[ORM\Table(name: 'authoring_directive')]
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
#[ORM\DiscriminatorMap(['rule' => Rule::class, 'workflow' => Workflow::class])]
abstract class Directive extends AggregateRoot
{
// Common fields
}
#[ORM\Entity]
class Rule extends Directive
{
// Rule-specific fields
#[ORM\Column(name: 'rule_content', type: Types::TEXT, nullable: true)]
public private(set) ?string $content = null;
}
Enum Mapping
#[ORM\Column(type: 'string', enumType: DirectiveState::class)]
public private(set) DirectiveState $state;
Collection Initialization
Always initialize collections in constructor:
public function __construct()
{
$this->examples = new ArrayCollection();
$this->steps = new ArrayCollection();
}
Checklist
When mapping an entity:
- Add
#[ORM\Entity]attribute - Add
#[ORM\Table(name: '...')]for aggregate roots - Use custom types for value objects (registered in doctrine.yaml)
- Use
Types::*constants for built-in types - Add PHPDoc
@var Collection<int, Entity>for collections - Initialize collections in constructor
- Use asymmetric visibility (
public private(set))
Reference Files
api/config/packages/doctrine.yaml- Doctrine configurationapi/src/Authoring/Domain/Object/Directive/Directive.php- Inheritance exampleapi/src/Authoring/Domain/Object/Workflow/Workflow.php- Relationships example
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です