mcpField
L
laravel-value-objects

laravel-value-objects

github.com/leeovery開発1548 回インストール2 週間前に更新
リポジトリ

laravel-value-objects について

Laravel 開発者向けに、ドメインの値オブジェクトの設計を解説するガイドです。DTOとの使い分けに加え、不変性、ファクトリーメソッド、検証、シリアライズを扱います。

主な機能

  1. 01値オブジェクトとDTOの用途の区別
  2. 02readonlyクラスによる不変性
  3. 03静的ファクトリーによる生成制御
  4. 04ドメインルールと検証のカプセル化
  5. 05シリアライズインターフェースの実装

活用シーン

  1. 01振る舞いを持つドメイン概念のモデル化
  2. 02金額などの不変値の表現
  3. 03サードパーティーライブラリのAPIラップ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/leeovery/agentic-skills --skill laravel-value-objects

インストール後、Claude Code で/laravel-value-objectsを入力して読み込まれたか確認します。

同梱ファイルreferences/Money.php

詳細

Laravel 値オブジェクト

値オブジェクトは、ドメインの概念を表すシンプルで不変なオブジェクトです。

関連ガイド:

  • DTO - DTO はデータ転送に、値オブジェクトはドメインの概念に使用します

使用する場面

値オブジェクトを使用する場面:

  • 振る舞いを持つ複雑なドメイン値がある
  • 不変性が必要
  • 詳細なバリデーションロジックがある
  • 等価性の比較が必要
  • ドメインルールをカプセル化する

DTO を使用する場面:

  • レイヤー間でデータを転送する
  • ドメインの振る舞いが不要
  • DTOを参照

シンプルな値オブジェクト

<?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;
    }
}

金額の値オブジェクト

完全な実装を見る →

使用例

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 ラッパー)
// 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"

→ 完全な実装:Money.php

主なパターン

1. 不変性

final readonly classを使用します。すべてのプロパティが不変になり、クラスを拡張できません。

final readonly class Money implements JsonSerializable, Stringable
{
    private function __construct(private BrickMoney $money) {}
}
2. プライベートコンストラクター+静的ファクトリー

生成方法を制御します。

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. ライブラリーのラップ

__call()による委譲を使い、サードパーティーライブラリーを独自の API の背後にラップします。

public function __call(string $name, array $arguments): mixed
{
    // Delegate to wrapped library, wrapping results as needed
}
4. 新しいインスタンスを返す

操作は常に新しいインスタンスを返します(不変性)。

$discounted = $price->minus(Money::of(5));  // $price unchanged
$refund = $price->negated();                // $price unchanged
5. シリアライズ用インターフェースを実装する

値オブジェクトは通常、フレームワークの機能やストレージとの連携のために、JsonSerializable、Stringable、Wireable(Livewire)を実装します。

ディレクトリー構成

app/ValueObjects/
├── Money.php
├── ProcessResult.php
├── Coordinate.php
└── EmailAddress.php

まとめ

値オブジェクト:

  • 不変です(readonlyを使用します)
  • 静的ファクトリーメソッドを持ちます
  • ドメインロジックをカプセル化します
  • 操作の結果として新しいインスタンスを返します
  • コンストラクターで検証します

単純なデータ転送ではなく、振る舞いを持つドメインの概念に使用します。

コメント