leeovery/agentic-skills/laravel-value-objects
Claude Code and agent skill by leeovery/agentic-skills
- community
Checking that the SKILL.md file is still in the repository.
Domain values are immutable value objects in app/Values, validated on construction, compared by value and cast onto models through Castable. Use when creating or changing a value object, its model cast, an action's result object, or money handling.
Install
npx vskill@latest install leeovery/agentic-skills/laravel-value-objectsSKILL.md
Laravel Value Objects
A value object is a domain value that has rules: a coordinate, a date range, an email address. It is defined by what it holds, not by an identity, and it can't exist in an invalid state, so code that receives one never checks it again. Behaviour that belongs to the value lives on it. A DTO only carries data between layers (laravel-dtos); once a value has rules or behaviour of its own, it's a value object.
Rules
- Lives in `app/Values/`, named for the value.
Coordinate,DateRange, neverCoordinateValueorCoordinateVO. A project on the domain layout keeps itsValueObjects/(see laravel-architecture). - Immutable. A
readonly classwith its parts as public promoted properties, and no setters. An operation that would change it returns a new instance. A value handed to several objects can't then change under one of them. - Valid or it doesn't exist. The public constructor validates its input and throws
InvalidArgumentException, or the project's domain exception when a caller is expected to handle it. No separatevalidate()orisValid()for a caller to forget. - Named constructors for other inputs.
fromString(),fromArray()parse their input, then callnew self(...), so validation stays in the constructor. The constructor stays public: it is the plain, validated way in. - Equal by value. An
equals(self $other): boolthat compares the parts. Equality is a domain decision (case, precision, normalisation), and==on objects hides it. - Behaviour belongs on the value. Distance between coordinates, whether a range contains a date, formatting the value itself. Anything that needs the database or a service stays in an action.
- Interfaces only when they're used.
Stringablewhen it's printed,JsonSerializablewhen it's serialised,Arrayablewhen it becomes an array. A__toString()that a named constructor can parse back makes the pair round-trip.
Example
Casting onto a model
A value object stored on a model implements Castable, and its castUsing() names a dedicated cast in app/Casts/. The model then casts to the value itself: 'location' => Coordinate::class. The cast's set() accepts only that value object and throws for anything else, so a raw array or string can't be written past it. A value spread over several columns is read from $attributes and written back as an array of columns:
Reach for these when the situation calls for it
The domain handles money. Use moneyphp/money's Money as the value, build it through one MoneyFactory, and store it with a MoneyCast. Read money.md before writing any code that stores, calculates or displays an amount of money.
An action can end in more than one expected way, and its caller acts on which. Return a result object: an outcome enum plus an optional message, with a named constructor per outcome. The caller matches on the outcome. Errors still throw; a result is for outcomes the caller expects, such as "nothing to do".
Name the enum for the outcome (ImportOutcome), not the result, so the two never need an import alias.
Testing
Unit-test each constructor rule, each named constructor and each behaviour; every rule is a test that fails when the rule goes:
More in laravel-testing.
Anti-patterns
- ❌ A setter, or a property that isn't
readonly. - ❌ A constructor that accepts anything, with validation left to the caller.
- ❌ A private constructor that forces every caller through static factories.
- ❌
__call()forwarding to a wrapped library. The value's API should be readable in its class. - ❌ A value object that queries the database or calls a service.
- ❌ A cast whose
set()accepts a raw array or string as well as the value object. - ❌ An array or a loose pair of primitives (
$latitude,$longitude) passed around where a value object exists.
Related
- laravel-models — model casts beyond value objects
- laravel-dtos — data that crosses layers, which may hold value objects
- laravel-enums — fixed sets of values, and the outcome enum of a result object
- laravel-actions — the actions that take value objects and return result objects
- laravel-exceptions — domain exceptions a constructor can throw
- laravel-testing — test style
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckinglaravel/skills/laravel-value-objects/SKILL.md
Popularity
- Repository stars
- 14
- Repository forks
- 4
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/leeovery/agentic-skills/laravel-value-objects)