Share
Embed
DDDパターンを活用した Laravelアプリケーション開発/ddd-with-laravel
2016/10/29 Laravel Osaka 2016 http://php-jp.github.io/laravel-osaka-2016/
shin1x1
October 29, 2016
Transcript
64 slides
-
ӳޠ ༰ *UFN ൢച͢ΔɻԼهͷଐੑΛ࣋ͭɻ ɾ*% ɾ໊ ɾՁ֨ ɾࡏݿ *%
*UFN*E Λࣝผ͢Δίʔυ ͝ͱʹҰҙ ໊ *UFN/BNF ͷ໊শ Ձ֨ *UFN1SJDF ͷൢചՁ֨ Ҏ্ͷ ࡏݿ *UFN4UPDL ͷࡏݿ Ҏ্ͷ -
ӳޠ ༰ Χʔτ $BSU ߪೖ͢ΔΛҰ࣌֨ೲ͢ΔೖΕ ΧʔτཁૉΛෳ࣋ͭ Χʔτཁૉ $BSU&MFNFOU Χʔτʹ֨ೲ͞Ε͍ͯΔཁૉ ໊ͱݸΛଐੑʹ࣋ͭ
ݸ *UFN$PVOU ͷݸɻҎ্ͷɻ ΧʔτʹΛ ೖΕΔ "EE*UFN5P$BSU ΧʔτʹΛೖΕΔ͜ͱɻ ͱݸΛ༩͑Δɻ ݸࡏݿҎԼͰ͋Δඞཁ ͕͋Δɻ -
D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1* 1045ϦΫΤετ͔Β*%ͱݸΛऔಘ σʔλϕʔε͔Β*%ͰΛऔಘ ΧʔτʹΛೖΕΔ
ΧʔτΛηογϣϯʹอଘ ϨεϙϯεΛฦ͢ -
D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1* 1045ϦΫΤετ͔Β*%ͱݸΛऔಘ σʔλϕʔε͔Β*%ͰΛऔಘ ΧʔτʹΛೖΕΔ
ΧʔτΛηογϣϯʹอଘ ϨεϙϯεΛฦ͢ -
D .BTBTIJ4IJOCBSB!TIJOY ΤϯςΟςΟ ΤϯςΟςΟҎԼͷଐੑΛ࣋ͭ ༰ ৼΔ͍ʢԋࢉʣ *% ͷࣝผࢠ ͝ͱʹҰҙ ͳ͠
໊ ͷ໊শ ͳ͠ Ձ֨ ͷՁ֨ Ҏ্ͷ ɾݸͱͷֻ͚ࢉ ࡏݿ ͷࡏݿ Ҏ্ͷ ɾࡏݿ͕ෆ͍ͯ͠Δ͔ -
&MPRVFOU 3FQPTJUPSZ class Item { /** @var int */ private
$id; /** @var string */ private $name; /** @var int */ private $price; /** @var int */ private $stock; } int int int *UFNʢʣ -
&MPRVFOU 3FQPTJUPSZ class Item { /** @var int */ private
$id; /** @var string */ private $name; /** @var int */ private $price; /** @var int */ private $stock; } int int int *UFNʢʣ wυϝΠϯ͕ө͞Ε͍ͯͳ͍ wUIJTTUPDL UIJTTUPDL ͋Γ͑ͳ͍ԋࢉ͕Ͱ͖Δ wUIJTQSJDF ఆ֎ͷ͍ํ͞ΕΔ -
&MPRVFOU 3FQPTJUPSZ class Item { /** @var ItemId */ private
$id; /** @var string */ private $name; /** @var ItemPrice */ private $price; /** @var Stock */ private $stock; } ItemId ItemPrice Stock ܕʢΫϥεʣͰදݱ -
&MPRVFOU 3FQPTJUPSZ class ItemId { /** @var int */ private
$value; /** * @param int $value */ public function __construct(int $value) { $this->value = $value; } public function value(): int { return $this->value; } } *UFN*E ৼΔ͍ʢԋࢉʣ͕ແ͍ -
&MPRVFOU 3FQPTJUPSZ class ItemPrice { /** @var int */ private
$value; public function __construct(int $value = 0) { if ($value < 0) { throw new PreconditionsException('value must be positive number:' . $value); } $this->value = $value; } //(snip) *UFN1SJDF Ձ֨Ҏ্ͷ -
&MPRVFOU 3FQPTJUPSZ public function multi(ItemCount $count): ItemSubtotal { return
new ItemSubtotal($this->value * $count->value()); } *UFN1SJDF Ձ֨ ݸখܭ -
&MPRVFOU 3FQPTJUPSZ class Cart { /** @var CartElement[]|Collection */ private
$elements; public function addItem(Item $item, ItemCount $count) { if ($item->stock()->isInsufficient($count)) { throw new PreconditionsException('stock is insufficient'); } $this->elements->push(new CartElement($item, $count)); } $BSUΧʔτʹΛೖΕΔ ࡏݿ͕ෆ͍ͯ͠Δ͔ʁ -
&MPRVFOU 3FQPTJUPSZ class Cart { /** @var CartElement[]|Collection */ private
$elements; public function addItem(Item $item, ItemCount $count) { if ($item->stock()->isInsufficient($count)) { throw new PreconditionsException('stock is insufficient'); } $this->elements->push(new CartElement($item, $count)); } $BSUΧʔτʹΛೖΕΔ ΧʔτཁૉΛՃ -
D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1* 1045ϦΫΤετ͔Β*%ͱݸΛऔಘ σʔλϕʔε͔Β*%ͰΛऔಘ ΧʔτʹΛೖΕΔ
ΧʔτΛηογϣϯʹอଘ ϨεϙϯεΛฦ͢ -
&MPRVFOU 3FQPTJUPSZ class EloquentItemRepository implements ItemRepository { private $eloquent;
public function __construct(EloquentItem $eloquent) { $this->eloquent = $eloquent; } public function findById(ItemId $id): Item { $item = $this->eloquent->find($id->value()); if (empty($item)) { throw new NotFoundException('item not found'); } return $item->toDomain(); } } &MPRVFOU*UFN3FQPTJUPSZ -
&MPRVFOU 3FQPTJUPSZ class EloquentItemRepository implements ItemRepository { private $eloquent;
public function __construct(EloquentItem $eloquent) { $this->eloquent = $eloquent; } public function findById(ItemId $id): Item { $item = $this->eloquent->find($id->value()); if (empty($item)) { throw new NotFoundException('item not found'); } return $item->toDomain(); } } &MPRVFOU*UFN3FQPTJUPSZ -
&MPRVFOU 3FQPTJUPSZ class EloquentItem extends AppEloquent implements Domainable { protected
$table = 'items'; public function toDomain(): Item { return new Item( new ItemId($this->id), $this->name, new ItemPrice($this->price), new Stock($this->stock) ); } } &MPRVFOU*UFN -
&MPRVFOU 3FQPTJUPSZ class RepositoryServiceProvider extends ServiceProvider { public function register()
{ $this->app->bind(ItemRepository::class, EloquentItemRepository::class); } } ϦϙδτϦΛαʔϏείϯςφόΠϯυ -
&MPRVFOU 3FQPTJUPSZ class AddItemToCart { private $itemRepo; public function
__construct(ItemRepository $itemRepo) { $this->itemRepo = $itemRepo; } public function add(int $itemId, int $count): Cart { $item = $this->itemRepo->findById(new ItemId($itemId)); // (snip) } } ར༻ίʔυ -
D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1* 1045ϦΫΤετ͔Β*%ͱݸΛऔಘ σʔλϕʔε͔Β*%ͰΛऔಘ ΧʔτʹΛೖΕΔ
ΧʔτΛηογϣϯʹอଘ ϨεϙϯεΛฦ͢ -
&MPRVFOU 3FQPTJUPSZ public function post(Request $request, AddItemToCart $service): JsonResponse {
$this->validate($request, [ 'item_id' => 'required|integer', 'count' => 'required|integer' ]); $cart = $service->add( $request->get('item_id'), $request->get('count') ); return $this->ok(['cart' => $this->cartToArray($cart)]); } $POUSPMMFS ͬ͘͟ΓόϦσʔγϣϯ ʢυϝΠϯϧʔϧυϝΠϯϨΠϠͰʣ -
&MPRVFOU 3FQPTJUPSZ public function post(Request $request, AddItemToCart $service): JsonResponse {
$this->validate($request, [ 'item_id' => 'required|integer', 'count' => 'required|integer' ]); $cart = $service->add( $request->get('item_id'), $request->get('count') ); return $this->ok(['cart' => $this->cartToArray($cart)]); } $POUSPMMFS ΞϓϦέʔγϣϯαʔϏε࣮ߦ -
&MPRVFOU 3FQPTJUPSZ public function add(int $itemId, int $count): Cart {
$item = $this->itemRepo->findById(new ItemId($itemId)); try { $cart = $this->cartRepo->find(); } catch (NotFoundException $e) { $cart = new Cart(); } $cart->addItem($item, new ItemCount($count)); $this->cartRepo->store($cart); return $cart; } "QQMJDBUJPO4FSWJDF -
&MPRVFOU 3FQPTJUPSZ class DateOfBirth { /** @var Carbon */ private
$date; public function __construct(Carbon $date) { $this->date = $date; } public function age(): int { return $this->date->age; } } ੜ݄Λ7BMVF0CKFDUԽ $BSCPOΛϥοϓ ඞཁͳૢ࡞ͷΈ࣮