entities

Defines Doctrine ORM entities in OrangeHRM using docblock annotations, relations, listeners, and Decorators.

Updated Jul 23, 2026
One-click install
npx skills add https://github.com/snow-gift111/orangehrm-ai-sdlc-capstone --skill entities-snow-gift111
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: entities
Source: https://github.com/snow-gift111/orangehrm-ai-sdlc-capstone/tree/main/.agents/skills/entities
Command: npx skills add https://github.com/snow-gift111/orangehrm-ai-sdlc-capstone --skill entities-snow-gift111

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Defining Doctrine entities in OrangeHRM requires following strict project-specific conventions—flat namespaces, docblock-only annotations, table naming prefixes, external entity listeners, and a Decorator pattern—that are easy to get wrong and silently break discovery, lazy loading, or change tracking. ## Core Features & Use Cases - Entity Definition Conventions: Covers the flat OrangeHRM\Entity namespace, @ORM\Entity/@ORM\Table annotations, ohrm_ vs hs_hr_ table naming, column types, reserved-word quoting, and integer AUTO_INCREMENT IDs. - Relations & Collections: Documents ManyToOne, OneToMany, ManyToMany, and OneToOne mappings with mappedBy/inversedBy, @JoinColumn/@JoinTable, and mandatory ArrayCollection initialization in constructors. - Lifecycle & Decorator Patterns: Explains @ORM\EntityListeners for field encryption (the only lifecycle pattern used) and the DecoratorTrait + sibling Decorator class for DB-touching logic like setXById shortcuts. - Use Case: When adding a new Widget entity with an owner relation to Employee, follow the recipes to annotate the class, initialize collections, write a Decorator with setOwnerByEmpNumber, and avoid pitfalls like missing referencedColumnName="emp_number". ## Quick Start Ask the agent to create a new Doctrine entity with a ManyToOne relation to Employee following the OrangeHRM entity conventions.

Frequently Asked Questions about entities

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I create a new Doctrine entity in OrangeHRM?

Create the class in a plugin's entity/ directory under the flat OrangeHRM\Entity namespace with @ORM\Entity and @ORM\Table(name="ohrm_<resource>") annotations. Add an integer AUTO_INCREMENT ID, initialize collections in the constructor, and register the plugin's entity path in composer.json PSR-4.

How do I map a ManyToOne relation to the Employee entity in Doctrine?

Use @ORM\ManyToOne with targetEntity="OrangeHRM\Entity\Employee" and a @JoinColumn specifying referencedColumnName="emp_number", since Employee's ID column is not the default "id". Add inversedBy to point at the OneToMany collection on the other side.

Can I use PHP 8 attributes instead of docblock annotations for Doctrine mapping?

No. OrangeHRM's bootstrap uses createAnnotationMetadataConfiguration, so only docblock annotations are scanned. Mixing PHP 8 attributes silently breaks entity discovery for the affected classes.

Why does my Doctrine relation throw 'Call to a member function add() on null'?

The collection was not initialized in the entity constructor. Every OneToMany or ManyToMany property must be set to new ArrayCollection() in __construct, because constructors run before Doctrine hydrates collections from the database.

Should I use @HasLifecycleCallbacks or @ORM\EntityListeners for entity lifecycle logic?

Use @ORM\EntityListeners with an external listener class extending BaseListener. The codebase never uses @HasLifecycleCallbacks, because listeners can pull in services like the Cryptographer via traits while entity callbacks cannot.

When should I use a Decorator versus a Service for entity logic?

Use a Decorator when logic is intrinsic to one entity, such as setXById shortcuts, date formatting, or computed properties like getFullName. Use a Service when logic spans multiple unrelated entities, complex workflows, or external integrations.