Slide 1

Slide 1 text

PofEAAで読み解く Doctrine2 @dnskimox

Slide 2

Slide 2 text

自己紹介 ⊡ 本名:丹賀健一 ⊡ 通称:男爵 ⊡ dnskimo ⊡ dnskimox ⊡ 北海道在住 ⊡ 株式会社インフィニットループ ⊡ ソシャゲバックエンドAPI開発

Slide 3

Slide 3 text

宣伝のやつ https://www.infiniteloop.co.jp/blog/2018/06/seventeenth/

Slide 4

Slide 4 text

P of EAA https://ja.wikipedia.org/wiki/マーティン・ファウ ラー ⊡ 原題『Patterns of Enterprise Application Architecture』 ⊡ マーティン・ファウラー著 ⊡ エンタープライズアプリケーションの ための設計パターン集

Slide 5

Slide 5 text

エンタープライズアプリケーションと は? 1. データを永続化する 2. 大量のデータを扱う 3. 同時に多数のリクエストを受けつける 4. 他のエンタープライズアプリケーションと連携する

Slide 6

Slide 6 text

エンタープライズアプリケーションと は? P of EAA ≒ WEBアプリケーションのための設 計パターン集

Slide 7

Slide 7 text

Catalog of P of EAA ⊡ Domain Model ⊡ Active Record ⊡ Data Mapper ⊡ Unit of Work ⊡ Identity Map ⊡ Metadata Mapping ⊡ Foreign Key Mapping ⊡ Lazy Load ⊡ Single Table Inheritance ⊡ Repository ⊡ Model View Controller ⊡ Front Controller ⊡ Remote Facade ⊡ Service Layer ⊡ Data Transfer Object ⊡ Optimistic Offline Lock ⊡ Layer Supertype ⊡ Separated Interface ⊡ Value Object ⊡ etc...

Slide 8

Slide 8 text

Doctrine2 ⊡ Data Mapperパターンを採用したORM ⊡ Symfony Standard Editionに同梱 ⊡ Doctrine2単独で使うことも可能

Slide 9

Slide 9 text

架空のActive Record

Slide 10

Slide 10 text

関心事多すぎ? Characterクラスの関心事 ⊡ 自身が保有するデータ ⊡ ドメインロジック ⊡ 自身の状態をDBに反映する方法 ⊡ DBから自身を復元する方法

Slide 11

Slide 11 text

関心の分離ができたら…… Characterクラスの関心事 ⊡ 自身が保有するデータ ⊡ ドメインロジック ???の関心事 ⊡ オブジェクトの状態をDBに 反映する方法 ⊡ DBからオブジェクトを復元 する方法

Slide 12

Slide 12 text

Data Mapper オブジェクトとデータベースを分離する

Slide 13

Slide 13 text

“ A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.

Slide 14

Slide 14 text

Doctrine2のData Mapperのイメージ

Slide 15

Slide 15 text

登場人物紹介

Slide 16

Slide 16 text

Entity ⊡ 永続化されるオブジェクト ⊡ 一意な識別子を持つ ⊡ Plain Old PHP Object

Slide 17

Slide 17 text

ClassMetadata ⊡ エンティティとテーブルを対 応付けるための地図 ⊡ エンティティ同士の関係図

Slide 18

Slide 18 text

Persister ⊡ DBにデータを保存する ⊡ DBからデータを取り出す ⊡ SQLを組み立てる

Slide 19

Slide 19 text

Hyderator ⊡ DBから取り出したデータか らエンティティを復元する ⊡ 乾燥保存されたデータに水 を与える(Hydrate)

Slide 20

Slide 20 text

Repository ⊡ エンティティ検索のためのコ レクション風のインター フェースを提供 ⊡ アプリケーション側の拡張ポ イント

Slide 21

Slide 21 text

UnitOfWork ⊡ エンティティを監視し、その 変化を記録する ⊡ 詳細は後述

Slide 22

Slide 22 text

EntityManager ⊡ データマッパーオブジェクト達 の窓口役(Facade) ⊡ データマッパーオブジェクト間 の調停者(Mediator)

Slide 23

Slide 23 text

How It Works

Slide 24

Slide 24 text

CRUDのC $em = EntityManager::create(...); $character = new Character(); $character->setName(“Bob”); $em->persist($character); $em->flush(); // Executed SQL: INSERT INTO characters (name) VALUES(‘Bob’);

Slide 25

Slide 25 text

CRUDのCの舞台裏(1)

Slide 26

Slide 26 text

CRUDのCの舞台裏(2)

Slide 27

Slide 27 text

CRUDのR $em = EntityManager::create(...); $characterRepository = $em->getRepository(Character::class); $character = $characterRepository->find(1); // Executed SQL: SELECT FROM characters WHERE id = 1; $characters = $characterRepository->findByName(“Bob”); // Executed SQL: SELECT FROM characters WHERE name = ‘Bob’; $characters = $characterRepository->findAll(); // Executed SQL: SELECT FROM characters;

Slide 28

Slide 28 text

CRUDのRの舞台裏

Slide 29

Slide 29 text

経験値獲得メソッド class Character... public function gainExp(int $exp) { assert(0 < $exp); $this->setExp($this->getExp() + $exp); // 以下レベルアップ判定など ... } }

Slide 30

Slide 30 text

CRUDのU $em = EntityManager::create(...); $characterRepository = $em->getRepository(Character::class); $character = $characterRepository->find(1); // Executed SQL: SELECT FROM characters WHERE id = 1; $character->gainExp(100); $em->flush(); // Executed SQL: UPDATE characters SET exp = 100 WHERE id = 1;

Slide 31

Slide 31 text

Unit of Work オブジェクトを追跡し、その変化を書き出す

Slide 32

Slide 32 text

“ Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

Slide 33

Slide 33 text

How It Works

Slide 34

Slide 34 text

UnitOfWorkの暗躍 Rで密かにやっていたこと ⊡ エンティティを監視下に置く ⊡ エンティティのオリジナルデー タを保持する Uでやること ⊡ 現在のエンティティとオリジ ナルデータを比較する ⊡ 差分があったらPersisterに 更新を依頼する

Slide 35

Slide 35 text

CRUDのUの舞台裏(1)

Slide 36

Slide 36 text

CRUDのUの舞台裏(2)

Slide 37

Slide 37 text

ロストアップデートの予感…… $character1A = $characterRepository->find(1); // Executed SQL: SELECT FROM characters WHERE id = 1; $character1B = $characterRepository->find(1); // Executed SQL?: SELECT FROM characters WHERE id = 1; $character1A->gainExp(100); $character1B->gainExp(100); $em->flush(); // Executed SQL?: UPDATE characters SET exp = 100 WHERE id = 1; // Executed SQL?: UPDATE characters SET exp = 100 WHERE id = 1;

Slide 38

Slide 38 text

Identity Map メモリ上のオブジェクトを一意にする

Slide 39

Slide 39 text

“ Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them.

Slide 40

Slide 40 text

How It Works

Slide 41

Slide 41 text

真・CRUDのRの舞台裏(1)

Slide 42

Slide 42 text

真・CRUDのRの舞台裏(2)

Slide 43

Slide 43 text

ロストアップデートは起きない $character1A = $characterRepository->find(1); // Executed SQL: SELECT FROM characters WHERE id = 1; $character1B = $characterRepository->find(1); // Executed SQL: NONE $character1A->gainExp(100); $character1B->gainExp(100); $em->flush(); // Executed SQL: UPDATE characters SET exp = 200 WHERE id = 1;

Slide 44

Slide 44 text

CRUDのDについ ては割愛

Slide 45

Slide 45 text

その他Doctrine2で使われているパ ターン ⊡ Domain Model ⊡ Active Record ⊡ Data Mapper ⊡ Unit of Work ⊡ Identity Map ⊡ Metadata Mapping ⊡ Foreign Key Mapping ⊡ Lazy Load ⊡ Single Table Inheritance ⊡ Repository ⊡ Model View Controller ⊡ Front Controller ⊡ Remote Facade ⊡ Service Layer ⊡ Data Transfer Object ⊡ Optimistic Offline Lock ⊡ Layer Supertype ⊡ Separated Interface ⊡ Value Object ⊡ etc...

Slide 46

Slide 46 text

Let’s Doctrine!

Slide 47

Slide 47 text

参考文献 ⊡ Patterns of Enterprise Application Architecture ⊡ Catalog of Patterns of Enterprise Application Architecture ⊡ Data Mapper ⊡ Unit of Work ⊡ Identity Map ⊡ POJO