Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

{ return $this->posts->count() < 5; // ドメイン知識:「ユーザーは最大5件まで投稿可能」 } // この実装がLaravel→Symfony移行時に変更不要となる理由 } id = $id; // Value Object を使用:IDの一意性と型安全性を保証 $this->name = $name; // バリデーションは Value Object 内で実行済み $this->email = $email; // フレームワーク依存なし:Laravel/Symfony問わず動作 $this->posts = new Posts([]); // 初期状態は空のコレクションで安全に初期化 } public function canCreateNewPost(): bool // ビジネスルールをEntityに集約

Slide 17

Slide 17 text

public function equals(Email $other): bool // 値による等価性:Value Objectの重要特性 { return $this->value === $other->value; // 同じ値 = 同じオブジェクト:ビジネス的な同一性判定 } // この仕組みがLaravel/Symfony関係なく動作する理由 } value = $email; // 妥当な値のみ保持:以降は常に正しいメールアドレスであることが保証される } public function getValue(): string // 値の取得:カプセル化されたプリミティブ値へのアクセス { return $this->value; // 内部表現を返却:フレームワーク層での利用時 }

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

CleanArchitecture/ ├── Pure PHP実装 (src/) ├── Laravel実装 (laravel/) └── Symfony実装 (symfony/)

Slide 25

Slide 25 text

src/ ├── Domain/ # ビジネスルール中核 │ ├── Entity/ # User.php - Pure PHPエンティティ │ ├── ValueObject/ # Email.php, UserId.php等 │ └── Repository/ # UserRepositoryInterface.php ├── Application/ # アプリケーション処理 │ └── UseCase/User/ # CreateUserUseCase.php等 └── Infrastructure/ # 外部技術実装 └── Repository/ # InMemoryUserRepository.php

Slide 26

Slide 26 text

laravel/ ├── src/ │ ├── Infrastructure/Repository/ # LaravelUserRepository.php │ ├── Http/Controllers/ # UserController.php │ └── Models/ # EloquentUser.php └── public/ # Webインターフェース symfony/ ├── src/ │ ├── Infrastructure/Repository/ # SymfonyUserRepository.php │ ├── Controller/ # UserController.php │ └── Entity/ # DoctrineUser.php ├── config/ # services.yaml └── public/ # Webインターフェース

Slide 27

Slide 27 text

// Infrastructure/Repository/LaravelUserRepository.php // Infrastructure層で具体実装 class LaravelUserRepository implements UserRepositoryInterface // Interface契約の実装 { public function findById(UserId $id): ?User // Domain Entityを返すことでDomain層との契約を守る { $eloquentUser = EloquentUser::find($id->getValue()); // Laravel固有:Eloquent Model 使用 if (!$eloquentUser) { return null; } return new User( // 重要:EloquentからDomain Entityへの変換 new UserId($eloquentUser->id), // ORMの詳細をDomain層から隠蔽 new UserName($eloquentUser->name), // フレームワーク固有データをDomain概念に変換 new Email($eloquentUser->email) // この変換層がフレームワーク移行を可能にする ); } }

Slide 28

Slide 28 text

$user->getName()->getValue(), // 外部システム(Controller等)への戻り値 $user->getEmail()->getValue(), // フレームワーク固有形式への変換は不要 $user->canCreateNewPost() // ビジネスルール結果もそのまま返却 ); // このコード全体がLaravel固有クラスを一切使用していない点が重要 } } userRepository->nextId(), // Repository経由でID生成:永続化層の詳細を隠蔽 new UserName($request->name), // Value Object でバリデーション:不正値は例外で弾かれる new Email($request->email) // Value Object でバリデーション:メール形式チェック済み ); $this->userRepository->save($user); // Repository 経由で永続化:ORM詳細は隠蔽 return new UserDto( // DTO で結果を返却:Domain EntityをAPI用データに変換 $user->getId()->getValue(), // Value Objectからプリミティブ値を取得

Slide 29

Slide 29 text

public function findById(UserId $id): ?User // 戻り値は同じDomain Entity:Laravel版と完全に同じ { $doctrineUser = $this->entityManager // Doctrine固有の取得方法 ->find(DoctrineUser::class, $id->getValue()); // Eloquentとは異なるAPI、同じ結果 if (!$doctrineUser) { return null; // 見つからない場合の処理も同じ } return new User( // 重要:全く同じDomain Entity に変換 new UserId($doctrineUser->getId()), // Doctrine→Domain変換:Eloquent版と同じ変換処理 new UserName($doctrineUser->getName()), // ORMの違いを吸収してDomain概念に統一 new Email($doctrineUser->getEmail()) // この変換があるからUseCase層は変更不要 ); // Laravel版のRepositoryと戻り値が完全に同じ:これがフレームワーク移行の鍵

Slide 30

Slide 30 text

$this->app->bind( // Laravelコンテナへのバインド UserRepositoryInterface::class, // Interface(契約) LaravelUserRepository::class // Laravel 版実装をバインド:Eloquent使用版 ); // この設定により、Interface注入時にLaravel実装が自動注入される } // Laravel - AppServiceProvider.php // Laravel固有のDI設定方法 public function register(): void // ServiceProviderでの依存関係定義 {

Slide 31

Slide 31 text

# Symfony - services.yaml # Symfony固有のDI設定方法 services: # サービスコンテナの定義 App\Domain\Repository\UserRepositoryInterface: # Interface(契約)の定義 alias: App\Infrastructure\Repository\SymfonyUserRepository # Symfony実装をエイリアス:Doctrine使用版 ``` # この設定により、Interface注入時にSymfony実装が自動注入される:Laravel版と同じ効果 **結果**: 設定変更だけで移行完了!

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

CleanArchitecture/ ├── Eloquent依存実装 (eloquent-dependent/) └── 段階的移行デモ (eloquent-to-symfony/) ├── Phase 1: Domain Entity抽出 └── Phase 2: Repository Pattern導入

Slide 36

Slide 36 text

eloquent-dependent/ └── src/ ├── Models/ │ └── User.php # Eloquentモデル + ビジネスロジック混在 └── Http/Controllers/ └── UserController.php # Model直接操作

Slide 37

Slide 37 text

phase1-domain-extraction/ └── src/ ├── Domain/Entity/ # User.php (Pure PHP Entity新規作成) ├── Http/Controllers/ # UserController.php (まだModel直接操作) └── Models/ └── User.php # toDomainEntity()メソッド追加 phase2-repository-pattern/ └── src/ ├── Domain/ │ ├── Entity/ # User.php │ └── Repository/ # UserRepositoryInterface.php ├── Infrastructure/Repository/ # EloquentUserRepository.php ├── Application/Service/ # UserValidationService.php ├── Http/Controllers/ # Repository経由に変更 └── Models/ # User.php (まだEloquent併存)

Slide 38

Slide 38 text

// 問題:バリデーションも Model 内に混在 public static function createWithValidation(array $data): self // スタティックメソッド:テスト難しい { $validator = Validator::make($data, [ // Laravel Validator 使用:Symfonyでは全く異なるAPI 'email' => 'required|email|unique:users', // Laravel固有バリデーションルール 'name' => 'required|min:2' // この書き方はSymfonyでは使えない ]); if ($validator->fails()) { // Laravel固有のエラーハンドリング throw new ValidationException($validator); // Laravel固有例外:Symfonyでは対応不可 } hasMany(Post::class); // Eloquent リレーション:Symfony/Doctrineでは使えない } // Laravel→Symfony移行時にこのメソッドは全書き直し必要 // 問題:ビジネスロジックが Model に混在 public function canCreateNewPost(): bool // ドメイン知識がORM層に漏出 { return $this->posts()->count() < 5; // Eloquent Query Builder 使用:フレームワーク固有処理 } // このビジネスルールがEloquentに依存:移行時の大きな障壁

Slide 39

Slide 39 text

'errors' => $e->validator->errors() // Validatorオブジェクトへの直接アクセス:Symfonyでは使えない ], 422); // Laravel固有HTTPステータスコード返却 } // この全体が密結合:Symfony移行時にリファクタ必要 } } all()); // ControllerがModelの内部実装を知っている return response()->json([ // Laravel固有のJSONレスポンス生成 'id' => $user->id, // 問題:Model の属性に直接アクセス 'name' => $user->name, // カプセル化されていないデータアクセス 'email' => $user->email, // ビジネスルールが無い直接アクセス 'can_create_post' => $user->canCreateNewPost() // Model のメソッド呼び出し:Controllerがビジネスロジックを直接利用 ], 201); } catch (ValidationException $e) { // Laravel固有例外のキャッチ return response()->json([ // エラーレスポンスもLaravel固有方式

Slide 40

Slide 40 text

$this->hasMany()

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

{ return count($this->posts) < 5; // Pure PHP でビジネスロジック:Eloquent非依存 } // これでLaravel→Symfony移行時にビジネスロジックが保持される } id = $id; // バリデーションは別途実装:関心の分離 $this->name = $name; // Eloquentの$fillableやmass assignmentではない $this->email = $email; // 直接的なプロパティ設定 $this->posts = $posts; // 簡潔な初期化 } public function canCreateNewPost(): bool // ビジネスルールの抽出成功

Slide 43

Slide 43 text

} return new User( // 重要:Eloquent→Domain Entity 変換 $eloquentUser->id, // ORM固有データをドメインオブジェクトに $eloquentUser->name, // この変換層がフレームワーク依存を隠蔽 $eloquentUser->email, // UseCase層はDomain Entityしか知らない $eloquentUser->posts->toArray() // Eloquent Collectionを普通の配列に変換 ); // この設計でUseCase層がフレームワーク非依存に } } find($id); // まだEloquent 使用:しかし局所化済み if (!$eloquentUser) { return null; // 結果なしの場合の処理

Slide 44

Slide 44 text

$user->getId(), // 正規化されたデータ取得 $user->getName(), // カプセル化されたアクセサ $user->getEmail(), // フレームワーク非依存データ $user->canCreateNewPost() // ビジネスルール結果も含めて返却 ); // このUseCaseがフレームワーク非依存なのでSymfony移行が可能 } } validator->validate($request); // Interface経由でバリデーション $user = new User( // Domain Entityでビジネスオブジェクト生成 0, // Repository で ID 生成:永続化詳細の隠蔽 $request->name, // シンプルなデータ渡し $request->email // フレームワーク固有処理なし ); $this->userRepository->save($user); // Repository経由で永続化:ORM詳細隠蔽 return new UserDto( // DTOで結果返却:ドメインオブジェクトからAPI用データ変換

Slide 45

Slide 45 text

$doctrineUser->getName(), // メソッド名は異なるが結果は同じ $doctrineUser->getEmail(), // ORMの違いをRepository層で吸収 $doctrineUser->getPosts()->toArray() // Collection→配列変換も同じ ); // この結果、UseCase層は何も変更せずに動作:移行成功 } } entityManager // Doctrine固有のデータ取得方法 ->getRepository(DoctrineUser::class) // Eloquent::find()とは異なるAPI ->find($id); // しかし同じ結果を得る if (!$doctrineUser) { return null; // エラーハンドリングも同じ } return new User( // 最重要:全く同じDomain Entity生成 $doctrineUser->getId(), // Doctrineエンティティ→Domain Entity変換

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

https://recruit.fusic.co.jp/