entities-mapping
Skill4 starsChanged 4 months agoMITView on GitHub
Map PHP classes to database tables with Doctrine — PHP 8 attribute mapping, identifiers and generation strategies, column types, and nullability, so entities load and persist with the right SQL types. Use when the user must pick a primary key and an id generation strategy (auto, identity, sequence, or UUID) for a Doctrine entity; the user needs to map PHP property types to Doctrine column types, lengths, and nullability; the user needs to declare how a PHP class maps to a table with Doctrine — entity, columns, and identifier. Keywords: doctrine, orm, mapping, attributes, entity, identifier, sql.
In this repository119 other files it gives its agents.
- strategy-bitrix-d7-incrementalSkill
- strategy-explicit-over-magicSkill
- strategy-framework-conventionsSkill
- strategy-legacy-safe-editsSkill
- strategy-minimal-diffSkill
- strategy-no-untested-refactorSkill
- strategy-preserve-public-apiSkill
- strategy-readonly-immutabilitySkill
- strategy-security-firstSkill
- strategy-test-drivenSkill
- openapiSkill
- paginationSkill
- rest-designSkill
- versioningSkill
- cqrsSkill
- dependency-inversionSkill
- hexagonalSkill
- repository-patternSkill
- service-layerSkill
- bitrixSkill
- findings-reportSkill
- laravelSkill
- performanceSkill
- phpSkill
- project-analysisSkill
- refactoringSkill
- roi-prioritizationSkill
- securitySkill
- stack-detectionSkill
- cache-layersSkill
- component-engineSkill
- d7-eventsSkill
- d7-loaderSkill
- d7-orm-queriesSkill
- iblock-elementsSkill
- kernel-main-moduleSkill
- localizationSkill
- controllersSkill
- ormSkill
- validationSkill
- controllersSkill
- query-builderSkill
- routingSkill
- autoload-psr4Skill
- dependency-managementSkill
- scriptsSkill
- connection-poolingSkill
- mysql-indexingSkill
- redisSkill
- transactionsSkill
- ci-github-actionsSkill
- deployment-strategiesSkill
- docker-phpSkill
- env-configSkill
- associationsSkill
- orm-basicsSkill
- entity-apiSkill
- module-developmentSkill
- routing-controllersSkill
- formsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 66
Do not use Doctrine mapping attributes on an Active Record model (for example an Eloquent model) that already maps itself by convention.
- Distinctive: line 67
Do not map an entity for data that is only queried read-only and never persisted, such as ad-hoc report rows.
- Very specific: line 80
Add #[ORM\Entity] (and #[ORM\Table(name: 'orders')] if the table name differs) to the class so Doctrine treats it as a mapped entity.
- Very specific: line 82
Add an id property with #[ORM\Id], #[ORM\GeneratedValue], and #[ORM\Column] so the entity has a primary key and a generation strategy.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- generated: do not edit — source: knowledge/atoms/doctrine/entities-mapping/ --><!-- schema: atomVersion=3 skillVersion=2 graphVersion=1 --><!-- compile: @php-skills/compiler v1.0.0 (deterministic build) -->Doctrine Entity Mapping
When to use
- The user must pick a primary key and an id generation strategy (auto, identity, sequence, or UUID) for a Doctrine entity.
- The user needs to map PHP property types to Doctrine column types, lengths, and nullability.
- The user needs to declare how a PHP class maps to a table with Doctrine — entity, columns, and identifier.
When NOT to use
- Do not use Doctrine mapping attributes on an Active Record model (for example an Eloquent model) that already maps itself by convention.
- Do not map an entity for data that is only queried read-only and never persisted, such as ad-hoc report rows.
Core guidance
- Keep large columns out of the default hydration path — For large text or BLOB columns rarely needed at read time, split them into a separate entity or use a partial/projection query, so the common load does not hydrate megabytes per row.
- Prefer PHP 8 attribute mapping over annotations — On PHP 8.1+, map entities with native attributes (
#[ORM\Entity],#[ORM\Column]) rather than doc-block annotations. Reserve XML mapping for cases where mapping must live outside the class.
Quick recipe
- Add
#[ORM\Entity](and#[ORM\Table(name: 'orders')]if the table name differs) to the class so Doctrine treats it as a mapped entity. (verify:orm:mapping:describe App\Entity\Orderlists the class without a mapping error.) - Add an id property with
#[ORM\Id],#[ORM\GeneratedValue], and#[ORM\Column]so the entity has a primary key and a generation strategy. (verify: The mapping describe output shows the id field flagged as the identifier.) - Map each field with
#[ORM\Column(type: ..., nullable: ...)], then generate a reviewed migration from the mapping diff and apply it. (verify: The generated migration creates the table with the expected columns, types, and nullability.)
Best practices
- Persist a value object (money, email, coordinates) with an
#[ORM\Embedded]embeddable or a registered custom DBAL type, rather than flattening it into loose scalar columns by hand - Declare the identifier with
#[ORM\Id],#[ORM\GeneratedValue], and choose the strategy to fit the driver — IDENTITY for MySQL auto-increment, SEQUENCE for PostgreSQL, or an application-assigned UUID when ids must be known before insert - Set
nullable: trueon the column only when the PHP property type is nullable (?string), and keep them in sync — a non-nullable typed property must map to a NOT NULL column
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| New annotation-based mapping on ORM 3 | ORM 3 removed the annotation driver, so annotation mapping simply does not load and the entity is treated as unmapped. | Use native PHP attributes (or XML) for all new mapping, and convert legacy annotations during the ORM 3 upgrade. |
| Public mutable properties on the entity | Public setters everywhere let any caller push an entity into an invalid state, defeating the invariants the domain should enforce. | Keep mapped properties private and expose intent-revealing methods (for example markPaid()) that enforce valid transitions. |
| Running schema-tool update against production | The tool issues unversioned, potentially destructive ALTER and DROP statements with no review or rollback path. | Generate a reviewed migration with doctrine/migrations from the mapping diff and apply that, so schema changes are versioned and reversible. |
See references/anti-patterns.md.
Common mistakes
- Mapping to datetime lets mutable DateTime corrupt change tracking — Mapping a property as the mutable
datetimetype with aDateTimeobject lets in-place mutation slip past dirty checking. Fix: Map asdatetime_immutableand type the propertyDateTimeImmutableso every change produces a new object the unit of work can detect. - Entity without an — An entity class annotated
#[ORM\Entity]but with no#[ORM\Id]property throws a MappingException at boot. Fix: Declare exactly one identifier property with#[ORM\Id](or a composite of several) before using the entity. - Unspecified string length silently defaults to 255 — A
#[ORM\Column(type: 'string')]without an explicit length generates a VARCHAR(255), truncating longer values. Fix: Setlengthexplicitly, or map to thetexttype when the field has no natural bound.
Version notes
- Attributes are the only in-core annotation format on ORM 3 (PHP >=8.1) — Doctrine ORM 3 ships attribute and XML mapping in core and drops the doc-block annotation driver; on ORM 2 both attributes and annotations still work.
Security
- Do not hydrate entities directly from request input — Do not build or populate a mapped entity by copying raw request arrays field by field; map validated input onto the entity through explicit setters or a DTO, and never expose the identifier or internal flags to mass assignment.
Testing
- Activation and decision behavior are verified in
eval/scenarios/doctrine/entities-mapping.yaml.
Additional resources
- references/anti-patterns.md
- references/core.md
- references/examples.md
- references/pitfalls.md
- references/recipes.md
- references/version-differences.md
Knowledge graph
Prerequisites: doctrine/orm-basics
Related: doctrine/associations, doctrine/orm-basics, php/value-objects
<!-- graph-fragment: graph/fragments/doctrine/entities-mapping.yaml -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

