Laravel value objects
Skill noppu-labs/ai-toolkit/laravel/skills/laravel-value-objects
Toolkit for agentic development of Laravel & React apps
npx -y skills add noppu-labs/ai-toolkit --skill laravel-value-objectsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Immutable value objects for domain values. Use when creating or modifying value objects like money, coordinates, or other domain primitives.
SKILL.md
4.6 KB, as published. Nobody here has run it
Laravel Value Objects
Value objects are simple, immutable objects representing domain concepts.
Related guides:
- DTOs - DTOs are for data transfer, value objects for domain concepts
When to Use
Use value objects when:
- Complex domain value with behavior
- Immutability required
- Rich validation logic
- Need equality comparison
- Encapsulating domain rules
Use DTOs when:
- Transferring data between layers
- No domain behavior needed
- See DTOs
Simple Value Object
<?php
declare(strict_types=1);
namespace App\Values;
use App\Enums\ProcessResult as ProcessResultEnum;
class ProcessResult
{
public function __construct(
public readonly ProcessResultEnum $result,
public readonly ?string $message = null,
) {}
public static function success(?string $message = null): self
{
return new self(ProcessResultEnum::Success, $message);
}
public static function skip(?string $message = null): self
{
return new self(ProcessResultEnum::Skip, $message);
}
public static function fail(?string $message = null): self
{
return new self(ProcessResultEnum::Fail, $message);
}
public function isSuccess(): bool
{
return $this->result === ProcessResultEnum::Success;
}
public function isFail(): bool
{
return $this->result === ProcessResultEnum::Fail;
}
}
Money Value Object
Usage Examples
ProcessResult
// In actions
return ProcessResult::success('Order processed successfully');
return ProcessResult::skip('Order already processed');
return ProcessResult::fail('Payment declined');
// Checking results
if ($result->isSuccess()) {
// Handle success
}
if ($result->isFail()) {
// Handle failure
}
Money (Brick\Money wrapper)
// Creating money values
$price = Money::of(29.99); // From major units (£29.99)
$shipping = Money::ofMinor(500); // From minor units (£5.00)
$usdPrice = Money::of(19.99, 'USD'); // Explicit currency
// Arithmetic (returns new instances)
$total = $price->plus($shipping);
$discounted = $total->minus(Money::of(5));
$refund = $total->negated();
// Comparison
$total->isZero();
$total->isGreaterThan($price);
$total->isEqualTo($other);
// Display
echo $total->format(); // "£34.99"
echo $refund->format(showNegativeInParentheses: true); // "(£34.99)"
// Storage (minor units as int)
$total->getMinorAmount(); // 3499
$total->getCurrencyCode(); // "GBP"
→ Full implementation: Money.php
Key Patterns
1. Immutability
Use final readonly class — all properties immutable, class cannot be extended:
final readonly class Money implements JsonSerializable, Stringable
{
private function __construct(private BrickMoney $money) {}
}
2. Private Constructor + Static Factories
Force controlled instantiation:
private function __construct(/* ... */) {}
public static function of(BigNumber|int|float|string $amount, string $currency = 'GBP'): self
public static function ofMinor(BigNumber|int|float|string $minorAmount, string $currency = 'GBP'): self
public static function success(?string $message = null): self
3. Library Wrapping
Wrap third-party libraries behind your own API using __call() delegation:
public function __call(string $name, array $arguments): mixed
{
// Delegate to wrapped library, wrapping results as needed
}
4. Return New Instances
Operations always return new instances (immutability):
$discounted = $price->minus(Money::of(5)); // $price unchanged
$refund = $price->negated(); // $price unchanged
5. Implement Serialization Interfaces
Value objects typically implement JsonSerializable, Stringable, and Wireable (Livewire) for integration with framework features and storage.
Directory Structure
app/ValueObjects/
├── Money.php
├── ProcessResult.php
├── Coordinate.php
└── EmailAddress.php
Summary
Value objects:
- Are immutable (use
readonly) - Have static factory methods
- Encapsulate domain logic
- Return new instances from operations
- Validate in constructor
Use for domain concepts with behavior, not simple data transfer.