From c096a736a10b11a1ecbeb5de7507badb02e38844 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 20 Apr 2026 15:35:10 +0900 Subject: [PATCH 1/4] Add Directory Layout convention page (EN/JA) Documents the canonical Be Framework `src//` layout in a single reference page per language, with per-directory role / put-here / don't-put-here / deep-link entries for the ten standard slots. Linked from `11-reference-resources.md` (Development Reference section) alongside Naming Standards. Intended as the link target for downstream projects (skeleton, app templates) so the directory explanation lives in one i18n-aware place rather than duplicated per-repo. Co-Authored-By: Claude Opus 4.7 --- manuals/1.0/en/11-reference-resources.md | 1 + manuals/1.0/en/convention/directory-layout.md | 121 ++++++++++++++++++ manuals/1.0/ja/11-reference-resources.md | 1 + manuals/1.0/ja/convention/directory-layout.md | 121 ++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 manuals/1.0/en/convention/directory-layout.md create mode 100644 manuals/1.0/ja/convention/directory-layout.md diff --git a/manuals/1.0/en/11-reference-resources.md b/manuals/1.0/en/11-reference-resources.md index 327aec3..b1ea020 100644 --- a/manuals/1.0/en/11-reference-resources.md +++ b/manuals/1.0/en/11-reference-resources.md @@ -20,4 +20,5 @@ permalink: /manuals/1.0/en/11-reference-resources.html ## Development Reference - [Naming Standards](./convention/naming-standards.html) — Being-oriented naming principles +- [Directory Layout](./convention/directory-layout.html) — Canonical `src//` slots and what each is for - [Philosophy Behind](./12-philosophy-behind.html) — Philosophical roots of ontological programming diff --git a/manuals/1.0/en/convention/directory-layout.md b/manuals/1.0/en/convention/directory-layout.md new file mode 100644 index 0000000..ed383a2 --- /dev/null +++ b/manuals/1.0/en/convention/directory-layout.md @@ -0,0 +1,121 @@ +--- +layout: docs-en +title: "Be Framework Directory Layout" +category: Convention +permalink: /manuals/1.0/en/convention/directory-layout.html +--- + +# Be Framework Directory Layout + +> Ten `src//` slots, each with a single responsibility + +Every Be Framework application uses the same set of `src//` slots. Some are mandatory from day one; others stay empty until the pattern that needs them appears. The [skeleton](https://github.com/be-framework/skeleton) ships them all so you can drop code into the right place without guessing. + +## Source map + +| dir | role | manual | +|---|---|---| +| `src/Input/` | Pipeline entry. Declares `#[Be([Target::class])]`. | [Input Classes](../02-input-classes.html) | +| `src/Final/` | Terminus. Receives `#[Input]` data + `#[Inject]` services. | [Final Objects](../04-final-objects.html) | +| `src/Semantic/` | Semantic variables (validators). Class name = parameter name (camelCase). | [Semantic Variables](../06-semantic-variables.html) | +| `src/Exception/` | Semantic-validation exceptions with `#[Message]` for i18n. | [Error Handling](../09-error-handling.html) | +| `src/Reason/` | "What makes existence possible" — Entity, Media (Command/Query), policies, guards. | [Reason Layer](../08-reason-layer.html) | +| `src/Module/` | Ray.Di modules. `MODULE=` env switches the active module. | (skeleton-specific) | +| `src/Becoming/` | Framework wiring layer. Not user code. | [Becoming](../04a-becoming.html) | +| `src/Being/` | *(empty)* Branching intermediate with `$being` discriminator + `#[Be([FinalA, ...])]`. | [Being Classes](../03-being-classes.html) | +| `src/LogContext/` | *(empty)* Semantic-log event classes attached to `Been`. | [Semantic Logging](../10-semantic-logging.html) | +| `src/Moment/` | *(empty)* Diamond parts — `implements MomentInterface`, `be()` realizes potential. | [Metamorphosis Patterns](../05-metamorphosis-patterns.html) | + +## Per-directory reference + +### `src/Input/` + +**Role**: The starting point of every metamorphosis pipeline. +**Put here**: Final-readonly classes named `Input` that declare `#[Be([Target::class])]` to nominate their next form. +**Don't put here**: Validation, services, or business logic — Input is pure data + a forward-looking declaration. +**Skeleton example**: `HelloInput.php` +**Deep dive**: [Input Classes](../02-input-classes.html) + +### `src/Final/` + +**Role**: The terminus of a pipeline — the form an Input becomes. +**Put here**: Final-readonly classes that take `#[Input]` data + `#[Inject]` services in the constructor and freeze the resulting state. +**Don't put here**: `#[Be(...)]` declarations — once you reach Final, the pipeline ends. +**Skeleton example**: `HelloFinal.php` +**Deep dive**: [Final Objects](../04-final-objects.html) + +### `src/Semantic/` + +**Role**: Type-level meaning for parameters. The class name *is* the parameter name. +**Put here**: Validator classes (e.g. `EmailAddress`, `CustomerId`) whose constructor enforces the constraint and throws on violation. +**Don't put here**: Generic value objects — Semantic variables are anchored to a specific parameter name. +**Skeleton example**: `Name.php` +**Deep dive**: [Semantic Variables](../06-semantic-variables.html) + +### `src/Exception/` + +**Role**: Semantic-validation failures with i18n-ready messages. +**Put here**: Exception classes annotated with `#[Message(en: "...", ja: "...")]` and thrown from `src/Semantic/` constructors. +**Don't put here**: General runtime errors — those are framework concerns, not domain semantics. +**Skeleton example**: `InvalidNameException.php` +**Deep dive**: [Error Handling](../09-error-handling.html) + +### `src/Reason/` + +**Role**: "What makes existence possible." Houses Entities, Media (Command/Query interfaces via Ray.MediaQuery), policies, and guards. +**Put here**: Repository interfaces, Ray.MediaQuery interfaces, policy classes, and the entities they read or write. +**Don't put here**: Concrete service implementations belong in modules — Reason holds the contracts and rules. +**Skeleton example**: `Hello/HelloEntity.php`, `Hello/SayHelloInterface.php` +**Deep dive**: [Reason Layer](../08-reason-layer.html) + +### `src/Module/` + +**Role**: Dependency wiring. Each module is a Ray.Di module class. +**Put here**: `AppModule` (production wiring) plus alternates like `DevModule`, `TestModule`. The `MODULE=` env var picks one. +**Don't put here**: Application logic — modules only bind interfaces to implementations. +**Skeleton example**: `AppModule.php`, `DevModule.php` +**Deep dive**: skeleton-specific (see the skeleton's `CLAUDE.md`). + +### `src/Becoming/` + +**Role**: Framework wiring layer — adapters around `Becoming` itself. +**Put here**: Decorators or alternate `BecomingInterface` implementations (e.g. one that writes a semantic log on every run). +**Don't put here**: Application code. If it isn't about how the framework runs, it doesn't go here. +**Skeleton example**: `DevBecoming.php` +**Deep dive**: [Becoming](../04a-becoming.html) + +### `src/Being/` *(empty by default)* + +**Role**: Branching intermediates. A class that holds a `$being` discriminator and declares `#[Be([FinalA::class, FinalB::class])]` so the framework picks the next form at runtime. +**Put here**: One file per branching point — `Being.php` returning a union type for `$being`. +**Don't put here**: Linear pipelines — those go straight from Input to Final without an intermediate. +**Skeleton example**: *(empty by default)* +**Deep dive**: [Being Classes](../03-being-classes.html) + +### `src/LogContext/` *(empty by default)* + +**Role**: Semantic-log event classes that attach to `Been` to describe what happened in the pipeline. +**Put here**: `AbstractContext` subclasses named after the event (e.g. `OrderFinalizedContext`). +**Don't put here**: Plain DTOs — these classes are read by `koriym/semantic-logger` and rendered into the tree. +**Skeleton example**: *(empty by default)* +**Deep dive**: [Semantic Logging](../10-semantic-logging.html) + +### `src/Moment/` *(empty by default)* + +**Role**: Diamond-pattern parts. A `MomentInterface` implementation that holds a *potential* and realizes it via `be()`. +**Put here**: Classes named after the moment they capture (`PaymentCapture`, `InventoryReservation`) with a `realize` callable wired in by the surrounding pipeline. +**Don't put here**: One-shot operations — Moments are for the diamond convergence pattern, not linear steps. +**Skeleton example**: *(empty by default)* +**Deep dive**: [Metamorphosis Patterns](../05-metamorphosis-patterns.html) + +## Why three directories are empty by default + +`src/Being/`, `src/LogContext/`, and `src/Moment/` ship as `.gitkeep` placeholders. They correspond to optional patterns (Branching, Semantic Logging, Diamond convergence) that not every application needs. + +Keeping them empty means: + +- **Static analysis stays clean** — no example classes to confuse PHPStan or psalm. +- **Coverage reports stay honest** — no boilerplate inflating or deflating the percentage. +- **The shape of the project signals intent** — a file in `src/Being/` means *this app uses branching*, not *this is what the skeleton happened to ship with*. + +When you adopt one of these patterns, drop the first real class into the matching directory and the slot is no longer empty. diff --git a/manuals/1.0/ja/11-reference-resources.md b/manuals/1.0/ja/11-reference-resources.md index bc80862..9524374 100644 --- a/manuals/1.0/ja/11-reference-resources.md +++ b/manuals/1.0/ja/11-reference-resources.md @@ -20,4 +20,5 @@ permalink: /manuals/1.0/ja/11-reference-resources.html ## 開発リファレンス - [命名規約](./convention/naming-standards.html) — 存在指向の命名原則 +- [ディレクトリ構成](./convention/directory-layout.html) — `src//` 各スロットの役割と置くもの - [背後にある哲学](./12-philosophy-behind.html) — 存在論的プログラミングの思想的ルーツ diff --git a/manuals/1.0/ja/convention/directory-layout.md b/manuals/1.0/ja/convention/directory-layout.md new file mode 100644 index 0000000..c75eb20 --- /dev/null +++ b/manuals/1.0/ja/convention/directory-layout.md @@ -0,0 +1,121 @@ +--- +layout: docs-ja +title: "Be Framework ディレクトリ構成" +category: Convention +permalink: /manuals/1.0/ja/convention/directory-layout.html +--- + +# ディレクトリ構成 + +> 10個の `src//` スロット、それぞれに単一の責務 + +すべての Be Framework アプリケーションは同じ `src//` スロット群を使います。最初から必須のものもあれば、対応するパターンを採用するまで空のままにしておくものもあります。[スケルトン](https://github.com/be-framework/skeleton)はそれらすべてを同梱しているので、コードを置く場所に迷う必要はありません。 + +## 全体マップ + +| dir | 役割 | マニュアル | +|---|---|---| +| `src/Input/` | パイプラインの起点。`#[Be([Target::class])]` で次段を宣言。 | [Input クラス](../02-input-classes.html) | +| `src/Final/` | 終点。`#[Input]` でデータ、`#[Inject]` でサービスを受け取る。 | [Final オブジェクト](../04-final-objects.html) | +| `src/Semantic/` | セマンティック変数(バリデータ)。クラス名 = パラメータ名(camelCase)。 | [セマンティック変数](../06-semantic-variables.html) | +| `src/Exception/` | セマンティック検証例外。`#[Message]` で多言語化。 | [エラーハンドリング](../09-error-handling.html) | +| `src/Reason/` | 「存在を可能にするもの」— Entity、Media(Command/Query)、ポリシー、ガード。 | [Reason レイヤー](../08-reason-layer.html) | +| `src/Module/` | Ray.Di モジュール。`MODULE=` で有効モジュールを切り替え。 | (スケルトン固有) | +| `src/Becoming/` | フレームワーク配線層。ユーザーコードを置く場所ではない。 | [Becoming](../04a-becoming.html) | +| `src/Being/` | *(空)* `$being` 判別子 + `#[Be([FinalA, ...])]` を使う Branching 中間形。 | [Being クラス](../03-being-classes.html) | +| `src/LogContext/` | *(空)* `Been` に添えるセマンティックログのイベントクラス。 | [セマンティックロギング](../10-semantic-logging.html) | +| `src/Moment/` | *(空)* Diamond の部分 — `MomentInterface` を実装し、`be()` で潜在性を実現。 | [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) | + +## ディレクトリ別リファレンス + +### `src/Input/` + +**役割**: あらゆるメタモルフォーシスパイプラインの起点。 +**置くもの**: `Input` という命名の final readonly クラス。`#[Be([Target::class])]` で次の姿を宣言する。 +**置かないもの**: 検証、サービス、ビジネスロジック — Input は純粋なデータと「次は何になるか」の宣言だけ。 +**スケルトン例**: `HelloInput.php` +**詳しく**: [Input クラス](../02-input-classes.html) + +### `src/Final/` + +**役割**: パイプラインの終点 — Input が変容した先の姿。 +**置くもの**: コンストラクタで `#[Input]` データと `#[Inject]` サービスを受け取り、結果の状態を凍結する final readonly クラス。 +**置かないもの**: `#[Be(...)]` 宣言 — Final に到達した時点でパイプラインは終わる。 +**スケルトン例**: `HelloFinal.php` +**詳しく**: [Final オブジェクト](../04-final-objects.html) + +### `src/Semantic/` + +**役割**: パラメータに型レベルで意味を与える。クラス名そのものがパラメータ名。 +**置くもの**: バリデータクラス(例: `EmailAddress`、`CustomerId`)。コンストラクタで制約を強制し、違反時は例外を投げる。 +**置かないもの**: 汎用的な値オブジェクト — セマンティック変数は特定のパラメータ名に紐づく。 +**スケルトン例**: `Name.php` +**詳しく**: [セマンティック変数](../06-semantic-variables.html) + +### `src/Exception/` + +**役割**: 多言語対応メッセージ付きのセマンティック検証失敗。 +**置くもの**: `#[Message(en: "...", ja: "...")]` を付けた例外クラス。`src/Semantic/` のコンストラクタから throw される。 +**置かないもの**: 汎用的な実行時エラー — それはフレームワークの関心事であって、ドメインのセマンティクスではない。 +**スケルトン例**: `InvalidNameException.php` +**詳しく**: [エラーハンドリング](../09-error-handling.html) + +### `src/Reason/` + +**役割**: 「存在を可能にするもの」。Entity、Media(Ray.MediaQuery による Command/Query インタフェース)、ポリシー、ガードを収める。 +**置くもの**: リポジトリインタフェース、Ray.MediaQuery インタフェース、ポリシークラス、それらが読み書きする Entity。 +**置かないもの**: 具象サービスの実装はモジュールに置く — Reason は契約とルールの層。 +**スケルトン例**: `Hello/HelloEntity.php`、`Hello/SayHelloInterface.php` +**詳しく**: [Reason レイヤー](../08-reason-layer.html) + +### `src/Module/` + +**役割**: 依存性配線。各モジュールは Ray.Di のモジュールクラス。 +**置くもの**: `AppModule`(本番配線)と、`DevModule`、`TestModule` などの代替。`MODULE=` 環境変数で選択する。 +**置かないもの**: アプリケーションロジック — モジュールはインタフェースと実装の束縛だけを行う。 +**スケルトン例**: `AppModule.php`、`DevModule.php` +**詳しく**: スケルトン固有(スケルトンの `CLAUDE.md` を参照)。 + +### `src/Becoming/` + +**役割**: フレームワーク配線層 — `Becoming` 自体のアダプタ。 +**置くもの**: デコレータや代替の `BecomingInterface` 実装(例: 実行ごとにセマンティックログを書き出すもの)。 +**置かないもの**: アプリケーションコード。フレームワークの動作方法に関するものでなければここではない。 +**スケルトン例**: `DevBecoming.php` +**詳しく**: [Becoming](../04a-becoming.html) + +### `src/Being/` *(デフォルトでは空)* + +**役割**: 分岐の中間形。`$being` 判別子を持ち `#[Be([FinalA::class, FinalB::class])]` を宣言するクラス。フレームワークが実行時に次の姿を選ぶ。 +**置くもの**: 分岐ポイントごとに 1 ファイル — `$being` がユニオン型を返す `Being.php`。 +**置かないもの**: 線形パイプライン — 中間形を経由せず Input から Final まで直行する場合は不要。 +**スケルトン例**: *(デフォルトでは空)* +**詳しく**: [Being クラス](../03-being-classes.html) + +### `src/LogContext/` *(デフォルトでは空)* + +**役割**: パイプライン内で起きたことを記述する、`Been` に添えるセマンティックログのイベントクラス。 +**置くもの**: `AbstractContext` のサブクラス。イベントにちなんだ名前(例: `OrderFinalizedContext`)。 +**置かないもの**: 単なる DTO — これらのクラスは `koriym/semantic-logger` が読み取り、ツリーへ描画する。 +**スケルトン例**: *(デフォルトでは空)* +**詳しく**: [セマンティックロギング](../10-semantic-logging.html) + +### `src/Moment/` *(デフォルトでは空)* + +**役割**: Diamond パターンの部分。*潜在性* を保持し、`be()` でそれを実現する `MomentInterface` の実装。 +**置くもの**: 捉える瞬間にちなんだ名前のクラス(`PaymentCapture`、`InventoryReservation`)。周囲のパイプラインから `realize` callable が配線される。 +**置かないもの**: 単発の操作 — Moment は線形ステップではなく、Diamond の収束パターンのためのもの。 +**スケルトン例**: *(デフォルトでは空)* +**詳しく**: [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) + +## なぜ 3 つのディレクトリは空のままなのか + +`src/Being/`、`src/LogContext/`、`src/Moment/` は `.gitkeep` のプレースホルダで出荷されます。これらはオプションのパターン(Branching、セマンティックロギング、Diamond 収束)に対応しており、どのアプリケーションも必要とするわけではありません。 + +空のままにしておくことで、 + +- **静的解析がクリーンに保たれる** — PHPStan や psalm を惑わせるサンプルクラスがない。 +- **カバレッジレポートが正直になる** — パーセンテージを水増し・水減らしするボイラープレートがない。 +- **プロジェクトの形が意図を語る** — `src/Being/` にファイルがあれば *このアプリは分岐を使っている* という意味になる。スケルトンが偶然同梱していたから、ではない。 + +これらのパターンを採用するときに、対応するディレクトリへ最初の実クラスを置けば、そのスロットはもう空ではなくなります。 From 27047777b198bd04efcbb5191bea1f179e2a0052 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 20 Apr 2026 17:41:01 +0900 Subject: [PATCH 2/4] Tighten directory-layout page: Wittgenstein epigraph, drop filler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace the tagline with Tractatus 1.13 ("The facts in logical space are the world") — maps directly onto the page: the slots are the logical space, the classes are the facts. - Remove the obvious intro sentence; the epigraph and the Source map table carry the meaning without restating it. - Remove the "Why three directories are empty by default" section. The (empty) markers in the table already convey it, and hard-coding a count ("three") ages poorly as patterns are added. --- manuals/1.0/en/convention/directory-layout.md | 17 +++-------------- manuals/1.0/ja/convention/directory-layout.md | 17 +++-------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/manuals/1.0/en/convention/directory-layout.md b/manuals/1.0/en/convention/directory-layout.md index ed383a2..35f1463 100644 --- a/manuals/1.0/en/convention/directory-layout.md +++ b/manuals/1.0/en/convention/directory-layout.md @@ -7,9 +7,9 @@ permalink: /manuals/1.0/en/convention/directory-layout.html # Be Framework Directory Layout -> Ten `src//` slots, each with a single responsibility - -Every Be Framework application uses the same set of `src//` slots. Some are mandatory from day one; others stay empty until the pattern that needs them appears. The [skeleton](https://github.com/be-framework/skeleton) ships them all so you can drop code into the right place without guessing. +> "The facts in logical space are the world." +> +> —Ludwig Wittgenstein (*Tractatus Logico-Philosophicus*, 1.13, 1921) ## Source map @@ -108,14 +108,3 @@ Every Be Framework application uses the same set of `src//` slots. Some are **Skeleton example**: *(empty by default)* **Deep dive**: [Metamorphosis Patterns](../05-metamorphosis-patterns.html) -## Why three directories are empty by default - -`src/Being/`, `src/LogContext/`, and `src/Moment/` ship as `.gitkeep` placeholders. They correspond to optional patterns (Branching, Semantic Logging, Diamond convergence) that not every application needs. - -Keeping them empty means: - -- **Static analysis stays clean** — no example classes to confuse PHPStan or psalm. -- **Coverage reports stay honest** — no boilerplate inflating or deflating the percentage. -- **The shape of the project signals intent** — a file in `src/Being/` means *this app uses branching*, not *this is what the skeleton happened to ship with*. - -When you adopt one of these patterns, drop the first real class into the matching directory and the slot is no longer empty. diff --git a/manuals/1.0/ja/convention/directory-layout.md b/manuals/1.0/ja/convention/directory-layout.md index c75eb20..2dd14f8 100644 --- a/manuals/1.0/ja/convention/directory-layout.md +++ b/manuals/1.0/ja/convention/directory-layout.md @@ -7,9 +7,9 @@ permalink: /manuals/1.0/ja/convention/directory-layout.html # ディレクトリ構成 -> 10個の `src//` スロット、それぞれに単一の責務 - -すべての Be Framework アプリケーションは同じ `src//` スロット群を使います。最初から必須のものもあれば、対応するパターンを採用するまで空のままにしておくものもあります。[スケルトン](https://github.com/be-framework/skeleton)はそれらすべてを同梱しているので、コードを置く場所に迷う必要はありません。 +> 「論理的空間の中にある諸事実が、世界である」 +> +>   —ルートヴィヒ・ウィトゲンシュタイン(『論理哲学論考』1.13, 1921年) ## 全体マップ @@ -108,14 +108,3 @@ permalink: /manuals/1.0/ja/convention/directory-layout.html **スケルトン例**: *(デフォルトでは空)* **詳しく**: [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) -## なぜ 3 つのディレクトリは空のままなのか - -`src/Being/`、`src/LogContext/`、`src/Moment/` は `.gitkeep` のプレースホルダで出荷されます。これらはオプションのパターン(Branching、セマンティックロギング、Diamond 収束)に対応しており、どのアプリケーションも必要とするわけではありません。 - -空のままにしておくことで、 - -- **静的解析がクリーンに保たれる** — PHPStan や psalm を惑わせるサンプルクラスがない。 -- **カバレッジレポートが正直になる** — パーセンテージを水増し・水減らしするボイラープレートがない。 -- **プロジェクトの形が意図を語る** — `src/Being/` にファイルがあれば *このアプリは分岐を使っている* という意味になる。スケルトンが偶然同梱していたから、ではない。 - -これらのパターンを採用するときに、対応するディレクトリへ最初の実クラスを置けば、そのスロットはもう空ではなくなります。 From 0407795b7ee83747a88e7119f5040433bc9212b9 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 20 Apr 2026 18:41:53 +0900 Subject: [PATCH 3/4] Restructure directory-layout page around per-directory code samples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the repeated Role/Put here/Don't put here template with one minimal code sample per directory plus a 2-3 line note highlighting the distinctive feature at that moment. Fixes the src/Reason/ description, which previously listed Entities/Media/policies — Reason actually bundles related services as a "raison d'être" object used via #[Inject] or $being. Adds a Ray.Di manual link for src/Module/. Co-Authored-By: Claude Opus 4.7 --- manuals/1.0/en/convention/directory-layout.md | 299 +++++++++++------ manuals/1.0/ja/convention/directory-layout.md | 301 ++++++++++++------ 2 files changed, 415 insertions(+), 185 deletions(-) diff --git a/manuals/1.0/en/convention/directory-layout.md b/manuals/1.0/en/convention/directory-layout.md index 35f1463..09e82bc 100644 --- a/manuals/1.0/en/convention/directory-layout.md +++ b/manuals/1.0/en/convention/directory-layout.md @@ -15,96 +15,211 @@ permalink: /manuals/1.0/en/convention/directory-layout.html | dir | role | manual | |---|---|---| -| `src/Input/` | Pipeline entry. Declares `#[Be([Target::class])]`. | [Input Classes](../02-input-classes.html) | -| `src/Final/` | Terminus. Receives `#[Input]` data + `#[Inject]` services. | [Final Objects](../04-final-objects.html) | -| `src/Semantic/` | Semantic variables (validators). Class name = parameter name (camelCase). | [Semantic Variables](../06-semantic-variables.html) | -| `src/Exception/` | Semantic-validation exceptions with `#[Message]` for i18n. | [Error Handling](../09-error-handling.html) | -| `src/Reason/` | "What makes existence possible" — Entity, Media (Command/Query), policies, guards. | [Reason Layer](../08-reason-layer.html) | -| `src/Module/` | Ray.Di modules. `MODULE=` env switches the active module. | (skeleton-specific) | -| `src/Becoming/` | Framework wiring layer. Not user code. | [Becoming](../04a-becoming.html) | -| `src/Being/` | *(empty)* Branching intermediate with `$being` discriminator + `#[Be([FinalA, ...])]`. | [Being Classes](../03-being-classes.html) | -| `src/LogContext/` | *(empty)* Semantic-log event classes attached to `Been`. | [Semantic Logging](../10-semantic-logging.html) | -| `src/Moment/` | *(empty)* Diamond parts — `implements MomentInterface`, `be()` realizes potential. | [Metamorphosis Patterns](../05-metamorphosis-patterns.html) | - -## Per-directory reference - -### `src/Input/` - -**Role**: The starting point of every metamorphosis pipeline. -**Put here**: Final-readonly classes named `Input` that declare `#[Be([Target::class])]` to nominate their next form. -**Don't put here**: Validation, services, or business logic — Input is pure data + a forward-looking declaration. -**Skeleton example**: `HelloInput.php` -**Deep dive**: [Input Classes](../02-input-classes.html) - -### `src/Final/` - -**Role**: The terminus of a pipeline — the form an Input becomes. -**Put here**: Final-readonly classes that take `#[Input]` data + `#[Inject]` services in the constructor and freeze the resulting state. -**Don't put here**: `#[Be(...)]` declarations — once you reach Final, the pipeline ends. -**Skeleton example**: `HelloFinal.php` -**Deep dive**: [Final Objects](../04-final-objects.html) - -### `src/Semantic/` - -**Role**: Type-level meaning for parameters. The class name *is* the parameter name. -**Put here**: Validator classes (e.g. `EmailAddress`, `CustomerId`) whose constructor enforces the constraint and throws on violation. -**Don't put here**: Generic value objects — Semantic variables are anchored to a specific parameter name. -**Skeleton example**: `Name.php` -**Deep dive**: [Semantic Variables](../06-semantic-variables.html) - -### `src/Exception/` - -**Role**: Semantic-validation failures with i18n-ready messages. -**Put here**: Exception classes annotated with `#[Message(en: "...", ja: "...")]` and thrown from `src/Semantic/` constructors. -**Don't put here**: General runtime errors — those are framework concerns, not domain semantics. -**Skeleton example**: `InvalidNameException.php` -**Deep dive**: [Error Handling](../09-error-handling.html) - -### `src/Reason/` - -**Role**: "What makes existence possible." Houses Entities, Media (Command/Query interfaces via Ray.MediaQuery), policies, and guards. -**Put here**: Repository interfaces, Ray.MediaQuery interfaces, policy classes, and the entities they read or write. -**Don't put here**: Concrete service implementations belong in modules — Reason holds the contracts and rules. -**Skeleton example**: `Hello/HelloEntity.php`, `Hello/SayHelloInterface.php` -**Deep dive**: [Reason Layer](../08-reason-layer.html) - -### `src/Module/` - -**Role**: Dependency wiring. Each module is a Ray.Di module class. -**Put here**: `AppModule` (production wiring) plus alternates like `DevModule`, `TestModule`. The `MODULE=` env var picks one. -**Don't put here**: Application logic — modules only bind interfaces to implementations. -**Skeleton example**: `AppModule.php`, `DevModule.php` -**Deep dive**: skeleton-specific (see the skeleton's `CLAUDE.md`). - -### `src/Becoming/` - -**Role**: Framework wiring layer — adapters around `Becoming` itself. -**Put here**: Decorators or alternate `BecomingInterface` implementations (e.g. one that writes a semantic log on every run). -**Don't put here**: Application code. If it isn't about how the framework runs, it doesn't go here. -**Skeleton example**: `DevBecoming.php` -**Deep dive**: [Becoming](../04a-becoming.html) - -### `src/Being/` *(empty by default)* - -**Role**: Branching intermediates. A class that holds a `$being` discriminator and declares `#[Be([FinalA::class, FinalB::class])]` so the framework picks the next form at runtime. -**Put here**: One file per branching point — `Being.php` returning a union type for `$being`. -**Don't put here**: Linear pipelines — those go straight from Input to Final without an intermediate. -**Skeleton example**: *(empty by default)* -**Deep dive**: [Being Classes](../03-being-classes.html) - -### `src/LogContext/` *(empty by default)* - -**Role**: Semantic-log event classes that attach to `Been` to describe what happened in the pipeline. -**Put here**: `AbstractContext` subclasses named after the event (e.g. `OrderFinalizedContext`). -**Don't put here**: Plain DTOs — these classes are read by `koriym/semantic-logger` and rendered into the tree. -**Skeleton example**: *(empty by default)* -**Deep dive**: [Semantic Logging](../10-semantic-logging.html) - -### `src/Moment/` *(empty by default)* - -**Role**: Diamond-pattern parts. A `MomentInterface` implementation that holds a *potential* and realizes it via `be()`. -**Put here**: Classes named after the moment they capture (`PaymentCapture`, `InventoryReservation`) with a `realize` callable wired in by the surrounding pipeline. -**Don't put here**: One-shot operations — Moments are for the diamond convergence pattern, not linear steps. -**Skeleton example**: *(empty by default)* -**Deep dive**: [Metamorphosis Patterns](../05-metamorphosis-patterns.html) +| `src/Input/` | Pipeline entry. Declares `#[Be(...)]`. | [Input Classes](../02-input-classes.html) | +| `src/Final/` | Terminus. `#[Input]` data + `#[Inject]` services. | [Final Objects](../04-final-objects.html) | +| `src/Semantic/` | Semantic variables. Class name = parameter name. | [Semantic Variables](../06-semantic-variables.html) | +| `src/Exception/` | Semantic-validation exceptions with `#[Message]` for i18n. | [Error Handling](../09-error-handling.html) | +| `src/Reason/` | Raison d'être — related services bundled as one mode of existence. | [Reason Layer](../08-reason-layer.html) | +| `src/Module/` | Ray.Di modules. `MODULE=` env switches the active module. | [Ray.Di Manual](https://ray-di.github.io/manuals/1.0/en/index.html) | +| `src/Becoming/` | Framework wiring — `BecomingInterface` implementations/decorators. | [Becoming](../04a-becoming.html) | +| `src/Being/` | Branching — `$being` discriminator + `#[Be([A, B])]`. | [Being Classes](../03-being-classes.html) | +| `src/LogContext/` | Semantic-log event classes attached to `Been`. | [Semantic Logging](../10-semantic-logging.html) | +| `src/Moment/` | Moment — holds a Potential from Reason, realized via `be()`. | [Metamorphosis Patterns](../05-metamorphosis-patterns.html) | + +## `src/Input/` + +```php +#[Be(HelloFinal::class)] +final readonly class HelloInput +{ + public function __construct( + #[Input] public string $name, + ) {} +} +``` + +An Input carries not just data but the declaration of what it becomes. `#[Be(...)]` is the hand-off to the next form. + +→ [Input Classes](../02-input-classes.html) + +## `src/Final/` + +```php +final readonly class HelloFinal +{ + public string $message; + + public function __construct( + #[Input] string $name, + #[Inject] Greeting $greeting, + ) { + $this->message = $greeting->say($name); + } +} +``` + +No `#[Be(...)]` — this is the terminus. `#[Input]` is immanence (what came from the previous form); `#[Inject]` is transcendence (services from outside). Evidence of completion is recorded via `#[Inject] Been`. + +→ [Final Objects](../04-final-objects.html) + +## `src/Semantic/` + +```php +final class Email +{ + #[Validate] + public function validate(string $email): void + { + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new InvalidEmailException(); + } + } +} +``` + +Class name *is* the parameter name. `#[Validate]` auto-applies to every argument named `$email`, anywhere in the app — define once, enforced everywhere. + +→ [Semantic Variables](../06-semantic-variables.html) + +## `src/Exception/` + +```php +#[Message( + en: 'Invalid email: {email}', + ja: '不正なメールアドレス: {email}', +)] +final class InvalidEmailException extends \DomainException {} +``` + +`#[Message]` `en`/`ja` are the unit of i18n. Placeholders like `{email}` are filled from the exception's properties at throw time. + +→ [Error Handling](../09-error-handling.html) + +## `src/Reason/` + +```php +final readonly class ExpressShipping +{ + public function __construct( + private PriorityCarrier $carrier, + private RealTimeTracker $tracker, + ) {} + + public function calculateFee(Weight $weight): Fee + { + return $this->carrier->expressFee($weight); + } +} +``` + +One object answers "what's needed to exist as `ExpressDelivery`?" — carrier + tracker bundled together. Used as `#[Inject]` to provide capabilities, or as `$being` to let the type decide the next form. + +→ [Reason Layer](../08-reason-layer.html) + +## `src/Module/` + +```php +final class AppModule extends AbstractModule +{ + protected function configure(): void + { + $this->bind(PriorityCarrier::class)->to(FedExPriority::class); + $this->bind(RealTimeTracker::class)->to(FedExTracker::class); + } +} +``` + +Swapped via `MODULE=Dev` (or similar env). An alternate module can use `override` to substitute implementations without touching production wiring. + +→ [Ray.Di Manual](https://ray-di.github.io/manuals/1.0/en/index.html) + +## `src/Becoming/` +```php +final readonly class LoggingBecoming implements BecomingInterface +{ + public function __construct( + private Becoming $inner, + private LoggerInterface $logger, + ) {} + + public function __invoke(object $input): object + { + $this->logger->info('becoming', ['input' => $input::class]); + return ($this->inner)($input); + } +} +``` + +Touched rarely — only when you need to instrument metamorphosis itself (logging, tracing, timing). Everyday domain code never lands here. + +→ [Becoming](../04a-becoming.html) + +## `src/Being/` + +```php +#[Be([Approved::class, Rejected::class])] +final readonly class ApplicationReview +{ + public Approved|Rejected $being; + + public function __construct( + #[Input] LoanApplication $app, + #[Inject] CreditCheck $check, + ) { + $this->being = $check->evaluate($app); + } +} +``` + +The runtime type of `$being` picks which `#[Be([...])]` candidate comes next. The name can be anything — only the union type matters — but `$being` signals "branching point" at a glance. + +→ [Being Classes](../03-being-classes.html) + +## `src/LogContext/` + +```php +final class EmailFormatAssertedContext extends AbstractContext +{ + public const string TYPE = 'email_format_asserted'; + public const string SCHEMA_URL = 'https://example.com/schemas/email-format-asserted.json'; + + public function __construct( + public readonly string $email, + ) {} +} +``` + +`TYPE` is the event name that lands in the log; `SCHEMA_URL` links to the external schema. Attached via `$been->with(new EmailFormatAssertedContext(...))` inside a Final. + +→ [Semantic Logging](../10-semantic-logging.html) + +## `src/Moment/` + +```php +final readonly class PaymentCompleted implements MomentInterface +{ + public PaymentCapture $capture; + + public function __construct( + #[Input] string $cardNumber, + #[Input] int $amount, + #[Inject] PaymentGateway $gateway, + ) { + $this->capture = $gateway->authorize($cardNumber, $amount); + } + + public function be(): void + { + $this->capture->be(); + } +} +``` + +The constructor completes `authorize()` (the Potential), but not `capture()`. Only a Final that could construct *every* Moment then calls `be()` on each — so partial commits never happen. + +→ [Metamorphosis Patterns](../05-metamorphosis-patterns.html) + +--- + +Three directories — `Being/`, `LogContext/`, `Moment/` — ship empty. The skeleton's default is a linear `Input → Final` pipeline; branching, semantic logging, and the Diamond pattern are opt-in. Leaving them empty keeps static analysis and coverage clean until the project needs them. diff --git a/manuals/1.0/ja/convention/directory-layout.md b/manuals/1.0/ja/convention/directory-layout.md index 2dd14f8..92cbb95 100644 --- a/manuals/1.0/ja/convention/directory-layout.md +++ b/manuals/1.0/ja/convention/directory-layout.md @@ -9,102 +9,217 @@ permalink: /manuals/1.0/ja/convention/directory-layout.html > 「論理的空間の中にある諸事実が、世界である」 > ->   —ルートヴィヒ・ウィトゲンシュタイン(『論理哲学論考』1.13, 1921年) +>   —ルートヴィヒ・ウィトゲンシュタイン(『論理哲学論考』1.13, 1921年) ## 全体マップ | dir | 役割 | マニュアル | |---|---|---| -| `src/Input/` | パイプラインの起点。`#[Be([Target::class])]` で次段を宣言。 | [Input クラス](../02-input-classes.html) | -| `src/Final/` | 終点。`#[Input]` でデータ、`#[Inject]` でサービスを受け取る。 | [Final オブジェクト](../04-final-objects.html) | -| `src/Semantic/` | セマンティック変数(バリデータ)。クラス名 = パラメータ名(camelCase)。 | [セマンティック変数](../06-semantic-variables.html) | -| `src/Exception/` | セマンティック検証例外。`#[Message]` で多言語化。 | [エラーハンドリング](../09-error-handling.html) | -| `src/Reason/` | 「存在を可能にするもの」— Entity、Media(Command/Query)、ポリシー、ガード。 | [Reason レイヤー](../08-reason-layer.html) | -| `src/Module/` | Ray.Di モジュール。`MODULE=` で有効モジュールを切り替え。 | (スケルトン固有) | -| `src/Becoming/` | フレームワーク配線層。ユーザーコードを置く場所ではない。 | [Becoming](../04a-becoming.html) | -| `src/Being/` | *(空)* `$being` 判別子 + `#[Be([FinalA, ...])]` を使う Branching 中間形。 | [Being クラス](../03-being-classes.html) | -| `src/LogContext/` | *(空)* `Been` に添えるセマンティックログのイベントクラス。 | [セマンティックロギング](../10-semantic-logging.html) | -| `src/Moment/` | *(空)* Diamond の部分 — `MomentInterface` を実装し、`be()` で潜在性を実現。 | [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) | - -## ディレクトリ別リファレンス - -### `src/Input/` - -**役割**: あらゆるメタモルフォーシスパイプラインの起点。 -**置くもの**: `Input` という命名の final readonly クラス。`#[Be([Target::class])]` で次の姿を宣言する。 -**置かないもの**: 検証、サービス、ビジネスロジック — Input は純粋なデータと「次は何になるか」の宣言だけ。 -**スケルトン例**: `HelloInput.php` -**詳しく**: [Input クラス](../02-input-classes.html) - -### `src/Final/` - -**役割**: パイプラインの終点 — Input が変容した先の姿。 -**置くもの**: コンストラクタで `#[Input]` データと `#[Inject]` サービスを受け取り、結果の状態を凍結する final readonly クラス。 -**置かないもの**: `#[Be(...)]` 宣言 — Final に到達した時点でパイプラインは終わる。 -**スケルトン例**: `HelloFinal.php` -**詳しく**: [Final オブジェクト](../04-final-objects.html) - -### `src/Semantic/` - -**役割**: パラメータに型レベルで意味を与える。クラス名そのものがパラメータ名。 -**置くもの**: バリデータクラス(例: `EmailAddress`、`CustomerId`)。コンストラクタで制約を強制し、違反時は例外を投げる。 -**置かないもの**: 汎用的な値オブジェクト — セマンティック変数は特定のパラメータ名に紐づく。 -**スケルトン例**: `Name.php` -**詳しく**: [セマンティック変数](../06-semantic-variables.html) - -### `src/Exception/` - -**役割**: 多言語対応メッセージ付きのセマンティック検証失敗。 -**置くもの**: `#[Message(en: "...", ja: "...")]` を付けた例外クラス。`src/Semantic/` のコンストラクタから throw される。 -**置かないもの**: 汎用的な実行時エラー — それはフレームワークの関心事であって、ドメインのセマンティクスではない。 -**スケルトン例**: `InvalidNameException.php` -**詳しく**: [エラーハンドリング](../09-error-handling.html) - -### `src/Reason/` - -**役割**: 「存在を可能にするもの」。Entity、Media(Ray.MediaQuery による Command/Query インタフェース)、ポリシー、ガードを収める。 -**置くもの**: リポジトリインタフェース、Ray.MediaQuery インタフェース、ポリシークラス、それらが読み書きする Entity。 -**置かないもの**: 具象サービスの実装はモジュールに置く — Reason は契約とルールの層。 -**スケルトン例**: `Hello/HelloEntity.php`、`Hello/SayHelloInterface.php` -**詳しく**: [Reason レイヤー](../08-reason-layer.html) - -### `src/Module/` - -**役割**: 依存性配線。各モジュールは Ray.Di のモジュールクラス。 -**置くもの**: `AppModule`(本番配線)と、`DevModule`、`TestModule` などの代替。`MODULE=` 環境変数で選択する。 -**置かないもの**: アプリケーションロジック — モジュールはインタフェースと実装の束縛だけを行う。 -**スケルトン例**: `AppModule.php`、`DevModule.php` -**詳しく**: スケルトン固有(スケルトンの `CLAUDE.md` を参照)。 - -### `src/Becoming/` - -**役割**: フレームワーク配線層 — `Becoming` 自体のアダプタ。 -**置くもの**: デコレータや代替の `BecomingInterface` 実装(例: 実行ごとにセマンティックログを書き出すもの)。 -**置かないもの**: アプリケーションコード。フレームワークの動作方法に関するものでなければここではない。 -**スケルトン例**: `DevBecoming.php` -**詳しく**: [Becoming](../04a-becoming.html) - -### `src/Being/` *(デフォルトでは空)* - -**役割**: 分岐の中間形。`$being` 判別子を持ち `#[Be([FinalA::class, FinalB::class])]` を宣言するクラス。フレームワークが実行時に次の姿を選ぶ。 -**置くもの**: 分岐ポイントごとに 1 ファイル — `$being` がユニオン型を返す `Being.php`。 -**置かないもの**: 線形パイプライン — 中間形を経由せず Input から Final まで直行する場合は不要。 -**スケルトン例**: *(デフォルトでは空)* -**詳しく**: [Being クラス](../03-being-classes.html) - -### `src/LogContext/` *(デフォルトでは空)* - -**役割**: パイプライン内で起きたことを記述する、`Been` に添えるセマンティックログのイベントクラス。 -**置くもの**: `AbstractContext` のサブクラス。イベントにちなんだ名前(例: `OrderFinalizedContext`)。 -**置かないもの**: 単なる DTO — これらのクラスは `koriym/semantic-logger` が読み取り、ツリーへ描画する。 -**スケルトン例**: *(デフォルトでは空)* -**詳しく**: [セマンティックロギング](../10-semantic-logging.html) - -### `src/Moment/` *(デフォルトでは空)* - -**役割**: Diamond パターンの部分。*潜在性* を保持し、`be()` でそれを実現する `MomentInterface` の実装。 -**置くもの**: 捉える瞬間にちなんだ名前のクラス(`PaymentCapture`、`InventoryReservation`)。周囲のパイプラインから `realize` callable が配線される。 -**置かないもの**: 単発の操作 — Moment は線形ステップではなく、Diamond の収束パターンのためのもの。 -**スケルトン例**: *(デフォルトでは空)* -**詳しく**: [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) +| `src/Input/` | パイプラインの起点。`#[Be(...)]` を宣言。 | [Input クラス](../02-input-classes.html) | +| `src/Final/` | 終点。`#[Input]` データと `#[Inject]` サービスを受ける。 | [Final オブジェクト](../04-final-objects.html) | +| `src/Semantic/` | セマンティック変数。クラス名 = パラメータ名。 | [セマンティック変数](../06-semantic-variables.html) | +| `src/Exception/` | セマンティック検証例外。`#[Message]` で多言語化。 | [エラーハンドリング](../09-error-handling.html) | +| `src/Reason/` | 「存在理由」 — ある存在のしかたに必要なサービスを束ねたもの。 | [Reason レイヤー](../08-reason-layer.html) | +| `src/Module/` | Ray.Di モジュール。`MODULE=` 環境変数で有効モジュールを切り替える。 | [Ray.Di マニュアル](https://ray-di.github.io/manuals/1.0/ja/index.html) | +| `src/Becoming/` | フレームワーク配線層 — `BecomingInterface` の実装やデコレータ。 | [Becoming](../04a-becoming.html) | +| `src/Being/` | 分岐 — `$being` 判別子 + `#[Be([A, B])]`。 | [Being クラス](../03-being-classes.html) | +| `src/LogContext/` | `Been` に添えるセマンティックログのイベントクラス。 | [セマンティックロギング](../10-semantic-logging.html) | +| `src/Moment/` | Moment — Reason が返した Potential を保持し、`be()` で実現する。 | [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) | + +## `src/Input/` + +```php +#[Be(HelloFinal::class)] +final readonly class HelloInput +{ + public function __construct( + #[Input] public string $name, + ) {} +} +``` + +Input はデータだけでなく「次に何になるか」を持ちます。`#[Be(...)]` が次段への引き渡しになります。 + +→ [Input クラス](../02-input-classes.html) + +## `src/Final/` + +```php +final readonly class HelloFinal +{ + public string $message; + + public function __construct( + #[Input] string $name, + #[Inject] Greeting $greeting, + ) { + $this->message = $greeting->say($name); + } +} +``` + +`#[Be(...)]` は持ちません — ここが終点です。`#[Input]` は内在(前段から渡ってきたもの)、`#[Inject]` は超越(外から与えられるサービス)。完了の証拠は `#[Inject] Been` に記されます。 + +→ [Final オブジェクト](../04-final-objects.html) + +## `src/Semantic/` + +```php +final class Email +{ + #[Validate] + public function validate(string $email): void + { + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new InvalidEmailException(); + } + } +} +``` + +クラス名そのものがパラメータ名です。`#[Validate]` は `$email` という名の引数すべてに自動で効きます — 一度定義すれば、アプリ全域に適用されます。 + +→ [セマンティック変数](../06-semantic-variables.html) + +## `src/Exception/` + +```php +#[Message( + en: 'Invalid email: {email}', + ja: '不正なメールアドレス: {email}', +)] +final class InvalidEmailException extends \DomainException {} +``` + +`#[Message]` の `en`/`ja` が i18n の単位です。`{email}` のようなプレースホルダは、throw 時に例外のプロパティから埋まります。 + +→ [エラーハンドリング](../09-error-handling.html) + +## `src/Reason/` + +```php +final readonly class ExpressShipping +{ + public function __construct( + private PriorityCarrier $carrier, + private RealTimeTracker $tracker, + ) {} + + public function calculateFee(Weight $weight): Fee + { + return $this->carrier->expressFee($weight); + } +} +``` + +1つのオブジェクトが「`ExpressDelivery` になるために必要なものは?」に答えます — carrier と tracker を束ねる形で。`#[Inject]` で能力として使うことも、`$being` に型付けして次段を決めることもできます。 + +→ [Reason レイヤー](../08-reason-layer.html) + +## `src/Module/` + +```php +final class AppModule extends AbstractModule +{ + protected function configure(): void + { + $this->bind(PriorityCarrier::class)->to(FedExPriority::class); + $this->bind(RealTimeTracker::class)->to(FedExTracker::class); + } +} +``` + +`MODULE=Dev` のような環境変数で切り替わります。代替モジュール側で `override` を使えば、本番配線に一切触れずに実装を差し替えられます。 + +→ [Ray.Di マニュアル](https://ray-di.github.io/manuals/1.0/ja/index.html) + +## `src/Becoming/` +```php +final readonly class LoggingBecoming implements BecomingInterface +{ + public function __construct( + private Becoming $inner, + private LoggerInterface $logger, + ) {} + + public function __invoke(object $input): object + { + $this->logger->info('becoming', ['input' => $input::class]); + return ($this->inner)($input); + } +} +``` + +普段は触りません。メタモルフォーシスの実行そのものに手を入れたいとき(ログ・トレース・計測)だけ使います。ドメインコードは置きません。 + +→ [Becoming](../04a-becoming.html) + +## `src/Being/` + +```php +#[Be([Approved::class, Rejected::class])] +final readonly class ApplicationReview +{ + public Approved|Rejected $being; + + public function __construct( + #[Input] LoanApplication $app, + #[Inject] CreditCheck $check, + ) { + $this->being = $check->evaluate($app); + } +} +``` + +`$being` の実行時の型が `#[Be([...])]` の中から次段を選びます。プロパティ名はユニオン型でありさえすれば自由ですが、`$being` と書くと分岐点であることが一目で伝わります。 + +→ [Being クラス](../03-being-classes.html) + +## `src/LogContext/` + +```php +final class EmailFormatAssertedContext extends AbstractContext +{ + public const string TYPE = 'email_format_asserted'; + public const string SCHEMA_URL = 'https://example.com/schemas/email-format-asserted.json'; + + public function __construct( + public readonly string $email, + ) {} +} +``` + +`TYPE` はログに出るイベント名、`SCHEMA_URL` は外部スキーマへのリンクです。Final 内で `$been->with(new EmailFormatAssertedContext(...))` として添付します。 + +→ [セマンティックロギング](../10-semantic-logging.html) + +## `src/Moment/` + +```php +final readonly class PaymentCompleted implements MomentInterface +{ + public PaymentCapture $capture; + + public function __construct( + #[Input] string $cardNumber, + #[Input] int $amount, + #[Inject] PaymentGateway $gateway, + ) { + $this->capture = $gateway->authorize($cardNumber, $amount); + } + + public function be(): void + { + $this->capture->be(); + } +} +``` + +コンストラクタで `authorize()` は済みます(Potential)が、`capture()` はまだです。全 Moment を生成できた Final だけが `be()` を一斉に呼びます — 部分的なコミットは起こりません。 + +→ [メタモルフォーシスパターン](../05-metamorphosis-patterns.html) + +--- + +3つのディレクトリ — `Being/`、`LogContext/`、`Moment/` — はデフォルトでは空です。スケルトンのデフォルトは `Input → Final` の線形パイプラインで、分岐・セマンティックロギング・Diamond パターンは opt-in です。空のまま置いておくことで、そのパターンが必要になるまで静的解析とカバレッジをクリーンに保てます。 From e304bf77772e422b0bf35ace629dc15f891e91f8 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Mon, 20 Apr 2026 19:49:15 +0900 Subject: [PATCH 4/4] Refine directory-layout captions and sync EN/JA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tighten per-directory captions — most notably rewrite Reason as "capabilities an existence requires, gathered into one" to match the Reason Layer chapter, align tone to です・ます in JA, drop redundant tail note about static analysis, and restore a schema URL that reads as a real link. Co-Authored-By: Claude Opus 4.7 --- manuals/1.0/en/convention/directory-layout.md | 24 +++++++++---------- manuals/1.0/ja/convention/directory-layout.md | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/manuals/1.0/en/convention/directory-layout.md b/manuals/1.0/en/convention/directory-layout.md index 09e82bc..7ac9821 100644 --- a/manuals/1.0/en/convention/directory-layout.md +++ b/manuals/1.0/en/convention/directory-layout.md @@ -19,7 +19,7 @@ permalink: /manuals/1.0/en/convention/directory-layout.html | `src/Final/` | Terminus. `#[Input]` data + `#[Inject]` services. | [Final Objects](../04-final-objects.html) | | `src/Semantic/` | Semantic variables. Class name = parameter name. | [Semantic Variables](../06-semantic-variables.html) | | `src/Exception/` | Semantic-validation exceptions with `#[Message]` for i18n. | [Error Handling](../09-error-handling.html) | -| `src/Reason/` | Raison d'être — related services bundled as one mode of existence. | [Reason Layer](../08-reason-layer.html) | +| `src/Reason/` | Raison d'être — capabilities an existence requires, gathered into one. | [Reason Layer](../08-reason-layer.html) | | `src/Module/` | Ray.Di modules. `MODULE=` env switches the active module. | [Ray.Di Manual](https://ray-di.github.io/manuals/1.0/en/index.html) | | `src/Becoming/` | Framework wiring — `BecomingInterface` implementations/decorators. | [Becoming](../04a-becoming.html) | | `src/Being/` | Branching — `$being` discriminator + `#[Be([A, B])]`. | [Being Classes](../03-being-classes.html) | @@ -38,7 +38,7 @@ final readonly class HelloInput } ``` -An Input carries not just data but the declaration of what it becomes. `#[Be(...)]` is the hand-off to the next form. +An Input is the first domain class, built from data handed in from outside. `#[Be(...)]` declares what it becomes next — one candidate, or several. → [Input Classes](../02-input-classes.html) @@ -58,7 +58,7 @@ final readonly class HelloFinal } ``` -No `#[Be(...)]` — this is the terminus. `#[Input]` is immanence (what came from the previous form); `#[Inject]` is transcendence (services from outside). Evidence of completion is recorded via `#[Inject] Been`. +The terminus of metamorphosis. No `#[Be(...)]`. `#[Input]` is immanence (what came from the previous form); `#[Inject]` is transcendence (services from outside). Evidence of completion is recorded via `#[Inject] Been`. → [Final Objects](../04-final-objects.html) @@ -77,7 +77,7 @@ final class Email } ``` -Class name *is* the parameter name. `#[Validate]` auto-applies to every argument named `$email`, anywhere in the app — define once, enforced everywhere. +The class name becomes the parameter name. `#[Validate]` auto-applies to every argument named `$email`, anywhere in the app — define once, enforced everywhere. → [Semantic Variables](../06-semantic-variables.html) @@ -91,7 +91,7 @@ Class name *is* the parameter name. `#[Validate]` auto-applies to every argument final class InvalidEmailException extends \DomainException {} ``` -`#[Message]` `en`/`ja` are the unit of i18n. Placeholders like `{email}` are filled from the exception's properties at throw time. +`#[Message]` `en`/`ja` declare the per-language message. Placeholders like `{email}` are assigned from the exception's properties at throw time. → [Error Handling](../09-error-handling.html) @@ -112,7 +112,7 @@ final readonly class ExpressShipping } ``` -One object answers "what's needed to exist as `ExpressDelivery`?" — carrier + tracker bundled together. Used as `#[Inject]` to provide capabilities, or as `$being` to let the type decide the next form. +"What does it take to exist as `ExpressDelivery`?" — `ExpressShipping` is the answer. It gathers the capabilities that existence requires into one class, usable as `#[Inject]` to provide capabilities, or as the type of `$being` to decide the next form. → [Reason Layer](../08-reason-layer.html) @@ -129,7 +129,7 @@ final class AppModule extends AbstractModule } ``` -Swapped via `MODULE=Dev` (or similar env). An alternate module can use `override` to substitute implementations without touching production wiring. +DI bindings swapped via an env var like `MODULE=Dev`. A `DevModule` or `TestModule` substitutes implementations without touching the production `AppModule`. → [Ray.Di Manual](https://ray-di.github.io/manuals/1.0/en/index.html) @@ -151,7 +151,7 @@ final readonly class LoggingBecoming implements BecomingInterface } ``` -Touched rarely — only when you need to instrument metamorphosis itself (logging, tracing, timing). Everyday domain code never lands here. +Touched rarely — only when you need to instrument metamorphosis itself (logging, tracing, timing). → [Becoming](../04a-becoming.html) @@ -172,7 +172,7 @@ final readonly class ApplicationReview } ``` -The runtime type of `$being` picks which `#[Be([...])]` candidate comes next. The name can be anything — only the union type matters — but `$being` signals "branching point" at a glance. +Which class comes next is declared by the union-typed `$being` property. In practice, the framework picks the `#[Be([...])]` candidate whose constructor arguments can be satisfied. → [Being Classes](../03-being-classes.html) @@ -182,7 +182,7 @@ The runtime type of `$being` picks which `#[Be([...])]` candidate comes next. Th final class EmailFormatAssertedContext extends AbstractContext { public const string TYPE = 'email_format_asserted'; - public const string SCHEMA_URL = 'https://example.com/schemas/email-format-asserted.json'; + public const string SCHEMA_URL = '../schemas/email-format-asserted.json'; public function __construct( public readonly string $email, @@ -190,7 +190,7 @@ final class EmailFormatAssertedContext extends AbstractContext } ``` -`TYPE` is the event name that lands in the log; `SCHEMA_URL` links to the external schema. Attached via `$been->with(new EmailFormatAssertedContext(...))` inside a Final. +`TYPE` is the event name that lands in the log; `SCHEMA_URL` links to the schema. Inside a Final, `$been->with(new EmailFormatAssertedContext(...))` records the evidence that the object was established. → [Semantic Logging](../10-semantic-logging.html) @@ -222,4 +222,4 @@ The constructor completes `authorize()` (the Potential), but not `capture()`. On --- -Three directories — `Being/`, `LogContext/`, `Moment/` — ship empty. The skeleton's default is a linear `Input → Final` pipeline; branching, semantic logging, and the Diamond pattern are opt-in. Leaving them empty keeps static analysis and coverage clean until the project needs them. +Three directories — `Being/`, `LogContext/`, `Moment/` — ship empty. Add classes as the project needs them. diff --git a/manuals/1.0/ja/convention/directory-layout.md b/manuals/1.0/ja/convention/directory-layout.md index 92cbb95..7876126 100644 --- a/manuals/1.0/ja/convention/directory-layout.md +++ b/manuals/1.0/ja/convention/directory-layout.md @@ -19,7 +19,7 @@ permalink: /manuals/1.0/ja/convention/directory-layout.html | `src/Final/` | 終点。`#[Input]` データと `#[Inject]` サービスを受ける。 | [Final オブジェクト](../04-final-objects.html) | | `src/Semantic/` | セマンティック変数。クラス名 = パラメータ名。 | [セマンティック変数](../06-semantic-variables.html) | | `src/Exception/` | セマンティック検証例外。`#[Message]` で多言語化。 | [エラーハンドリング](../09-error-handling.html) | -| `src/Reason/` | 「存在理由」 — ある存在のしかたに必要なサービスを束ねたもの。 | [Reason レイヤー](../08-reason-layer.html) | +| `src/Reason/` | 「存在理由」 — その存在に必要な能力を1つに集めたもの。 | [Reason レイヤー](../08-reason-layer.html) | | `src/Module/` | Ray.Di モジュール。`MODULE=` 環境変数で有効モジュールを切り替える。 | [Ray.Di マニュアル](https://ray-di.github.io/manuals/1.0/ja/index.html) | | `src/Becoming/` | フレームワーク配線層 — `BecomingInterface` の実装やデコレータ。 | [Becoming](../04a-becoming.html) | | `src/Being/` | 分岐 — `$being` 判別子 + `#[Be([A, B])]`。 | [Being クラス](../03-being-classes.html) | @@ -38,7 +38,7 @@ final readonly class HelloInput } ``` -Input はデータだけでなく「次に何になるか」を持ちます。`#[Be(...)]` が次段への引き渡しになります。 +Input は外部から渡されるデータで作られる最初のドメインクラスです。`#[Be(...)]` 属性で「次に何になるか」を1つ、または複数持ちます。 → [Input クラス](../02-input-classes.html) @@ -58,7 +58,7 @@ final readonly class HelloFinal } ``` -`#[Be(...)]` は持ちません — ここが終点です。`#[Input]` は内在(前段から渡ってきたもの)、`#[Inject]` は超越(外から与えられるサービス)。完了の証拠は `#[Inject] Been` に記されます。 +変容の終点のクラスです。`#[Be(...)]` は持ちません。`#[Input]` は内在(前段から渡ってきたもの)、`#[Inject]` は超越(外から与えられるサービス)です。完了の証拠は `#[Inject] Been` で記されます。 → [Final オブジェクト](../04-final-objects.html) @@ -77,7 +77,7 @@ final class Email } ``` -クラス名そのものがパラメータ名です。`#[Validate]` は `$email` という名の引数すべてに自動で効きます — 一度定義すれば、アプリ全域に適用されます。 +クラス名がそのままパラメータ名になります。`#[Validate]` は `$email` という名の引数すべてに自動で効きます — 一度定義すれば、アプリ全域に適用されます。 → [セマンティック変数](../06-semantic-variables.html) @@ -91,7 +91,7 @@ final class Email final class InvalidEmailException extends \DomainException {} ``` -`#[Message]` の `en`/`ja` が i18n の単位です。`{email}` のようなプレースホルダは、throw 時に例外のプロパティから埋まります。 +`#[Message]` の `en`/`ja` で、言語ごとのメッセージを指定します。`{email}` のようなプレースホルダは、throw 時に例外のプロパティからアサインされます。 → [エラーハンドリング](../09-error-handling.html) @@ -112,7 +112,7 @@ final readonly class ExpressShipping } ``` -1つのオブジェクトが「`ExpressDelivery` になるために必要なものは?」に答えます — carrier と tracker を束ねる形で。`#[Inject]` で能力として使うことも、`$being` に型付けして次段を決めることもできます。 +「`ExpressDelivery` として存在するには何が必要か?」 — その答えが `ExpressShipping` です。その存在に必要な能力を1つに集めたクラスで、`#[Inject]` で能力として注入することも、`$being` の型として次段を決めることもできます。 → [Reason レイヤー](../08-reason-layer.html) @@ -129,7 +129,7 @@ final class AppModule extends AbstractModule } ``` -`MODULE=Dev` のような環境変数で切り替わります。代替モジュール側で `override` を使えば、本番配線に一切触れずに実装を差し替えられます。 +`MODULE=Dev` のような環境変数で切り替えるDIの束縛設定です。本番用の `AppModule` を変えずに、`DevModule` や `TestModule` で実装を差し替えられます。 → [Ray.Di マニュアル](https://ray-di.github.io/manuals/1.0/ja/index.html) @@ -151,7 +151,7 @@ final readonly class LoggingBecoming implements BecomingInterface } ``` -普段は触りません。メタモルフォーシスの実行そのものに手を入れたいとき(ログ・トレース・計測)だけ使います。ドメインコードは置きません。 +普段は触りません。メタモルフォーシスの実行そのものに手を入れたいとき(ログ・トレース・計測)だけ使います。 → [Becoming](../04a-becoming.html) @@ -172,7 +172,7 @@ final readonly class ApplicationReview } ``` -`$being` の実行時の型が `#[Be([...])]` の中から次段を選びます。プロパティ名はユニオン型でありさえすれば自由ですが、`$being` と書くと分岐点であることが一目で伝わります。 +次にどのクラスに分岐するかは、ユニオン型の `$being` プロパティで明示的に示します。実際には `#[Be([...])]` の候補のうち、引数が用意できるものが次のクラスとして選ばれます。 → [Being クラス](../03-being-classes.html) @@ -182,7 +182,7 @@ final readonly class ApplicationReview final class EmailFormatAssertedContext extends AbstractContext { public const string TYPE = 'email_format_asserted'; - public const string SCHEMA_URL = 'https://example.com/schemas/email-format-asserted.json'; + public const string SCHEMA_URL = '../schemas/email-format-asserted.json'; public function __construct( public readonly string $email, @@ -190,7 +190,7 @@ final class EmailFormatAssertedContext extends AbstractContext } ``` -`TYPE` はログに出るイベント名、`SCHEMA_URL` は外部スキーマへのリンクです。Final 内で `$been->with(new EmailFormatAssertedContext(...))` として添付します。 +`TYPE` はログに出るイベント名、`SCHEMA_URL` はスキーマへのリンクです。Final 内で `$been->with(new EmailFormatAssertedContext(...))` として、そのオブジェクトが成立したことの証拠を記録します。 → [セマンティックロギング](../10-semantic-logging.html) @@ -222,4 +222,4 @@ final readonly class PaymentCompleted implements MomentInterface --- -3つのディレクトリ — `Being/`、`LogContext/`、`Moment/` — はデフォルトでは空です。スケルトンのデフォルトは `Input → Final` の線形パイプラインで、分岐・セマンティックロギング・Diamond パターンは opt-in です。空のまま置いておくことで、そのパターンが必要になるまで静的解析とカバレッジをクリーンに保てます。 +3つのディレクトリ — `Being/`、`LogContext/`、`Moment/` — はデフォルトでは空です。必要に応じて、クラスを追加していきます。 \ No newline at end of file