Features Pattern ​
Modularous features use a triple pattern: Entity trait + Repository trait + Hydrate. Understanding this pattern helps when adding or customizing features.
Pattern Overview ​
mermaid
flowchart LR
Config[Route config type: file]
Hydrate[FileHydrate]
Schema[schema type: input-file]
Repo[FilesTrait]
Model[HasFiles]
Config --> Hydrate
Hydrate --> Schema
Schema --> Repo
Repo --> Model- Route config defines input with
type(e.g.file,image,repeater) - Hydrate transforms to frontend schema (
input-file, etc.) - Repository trait handles persistence in
hydrate*Trait,afterSave*Trait,getFormFields*Trait - Entity trait provides model relationships and accessors
Entity Trait (Model) ​
- Location:
src/Entities/Traits/Has*.phpor*.php(e.g.Assignable) - Purpose: Relationships, boot logic, accessors, scopes
- Convention:
HasXfor "has many/one X";IsXfor behavior (e.g.IsSingular);Xablefor "can be X'd" (e.g.Assignable,Processable)
Example — HasFiles:
files()— morphToMany File with pivot (role, locale)file($role, $locale)— URL for first filefilesList($role, $locale)— array of URLsfileObject($role, $locale)— File model
Repository Trait ​
- Location:
src/Repositories/Traits/*Trait.php - Purpose: Persistence hooks called by Repository lifecycle
- Convention:
setColumns*Trait,hydrate*Trait,afterSave*Trait,getFormFields*Trait
Example — FilesTrait:
setColumnsFilesTrait— registers file columns from inputs withtypecontainingfilehydrateFilesTrait— sets$object->filesrelation from form dataafterSaveFilesTrait— syncs pivot (attach/updateExistingPivot)getFormFieldsFilesTrait— loads existing files into form fields
Hydrate ​
- Location:
src/Hydrates/Inputs/*Hydrate.php - Purpose: Transform module config into frontend schema
- Convention:
$input['type'] = 'input-{kebab}'(e.g.input-file,input-assignment); some hydrates outputselect(e.g. AuthorizeHydrate, StateableHydrate); setname,label,items,endpoint, etc.
Example — FileHydrate:
requirements:name=>files,translated=> false,default=> []hydrate():type→input-file,label→__('Files')
Adding a New Feature ​
- Entity trait: Add
HasMyFeaturewith relationships and accessors - Repository trait: Add
MyFeatureTraitwithhydrate*,afterSave*,getFormFields* - Hydrate: Add
MyFeatureHydrateextendingInputHydrate; settype→input-my-feature - Vue component: Create
VInputMyFeature; register inregistry.js - Config: Add trait to
modularous.traitsif needed; add input to route config
Feature Dependencies ​
Some features compose others:
- HasRepeaters uses HasFiles, HasImages, HasPriceable, HasFileponds
- HasPayment uses HasPriceable
- Processable uses HasFileponds
See Also ​
- Module Features Overview — Feature matrix and quick reference
- Hydrates — Schema transformation
- Repositories — Lifecycle and traits
- Entities — Entity traits list