Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2017/03 版 DDDパターンを活用した Laravelアプリケーション開発/201703-ddd-with-laravel

shin1x1
March 23, 2017

2017/03 版 DDDパターンを活用した Laravelアプリケーション開発/201703-ddd-with-laravel

shin1x1

March 23, 2017
Tweet

More Decks by shin1x1

Other Decks in Technology

Transcript

  1. ӳޠ ಺༰ ঎඼ *UFN ൢച͢Δ঎඼ɻԼهͷଐੑΛ࣋ͭɻ
 ɾ঎඼*% ɾ঎඼໊
 ɾ঎඼Ձ֨
 ɾࡏݿ ঎඼*%

    *UFN*E ঎඼Λࣝผ͢Δίʔυ
 ঎඼͝ͱʹҰҙ ঎඼໊ *UFN/BNF ঎඼ͷ໊শ ঎඼Ձ֨ *UFN1SJDF ঎඼ͷൢചՁ֨
 Ҏ্ͷ੔਺ ࡏݿ *UFN4UPDL ঎඼ͷࡏݿ਺ Ҏ্ͷ੔਺
  2. ӳޠ ಺༰ Χʔτ $BSU ߪೖ͢Δ঎඼ΛҰ࣌֨ೲ͢ΔೖΕ෺
 ΧʔτཁૉΛෳ਺࣋ͭ Χʔτཁૉ $BSU&MFNFOU Χʔτʹ֨ೲ͞Ε͍ͯΔཁૉ
 ঎඼໊ͱ঎඼ݸ਺Λଐੑʹ࣋ͭ

    ঎඼ݸ਺ *UFN$PVOU ঎඼ͷݸ਺ɻҎ্ͷ੔਺ɻ Χʔτʹ঎඼Λ ೖΕΔ "EE*UFN5P$BSU Χʔτʹ঎඼ΛೖΕΔ͜ͱɻ
 ঎඼ͱ঎඼ݸ਺Λ༩͑Δɻ
 ঎඼ݸ਺͸঎඼ࡏݿҎԼͰ͋Δඞཁ ͕͋Δɻ
  3. D .BTBTIJ4IJOCBSB!TIJOY ঎඼ΤϯςΟςΟ ঎඼ΤϯςΟςΟ͸ҎԼͷଐੑΛ࣋ͭ ଐੑ ಺༰ ৼΔ෣͍ʢԋࢉʣ ঎඼*% ঎඼ͷࣝผࢠ ঎඼͝ͱʹҰҙ

    ͳ͠ ঎඼໊ ঎඼ͷ໊শ ͳ͠ ঎඼Ձ֨ ঎඼ͷՁ֨ Ҏ্ͷ੔਺ ɾ঎඼ݸ਺ͱͷֻ͚ࢉ ࡏݿ ঎඼ͷࡏݿ਺ Ҏ্ͷ੔਺ ɾࡏݿ͕ෆ଍͍ͯ͠Δ͔
  4. &MPRVFOU 3FQPTJUPSZ class Item
 {
 /** @var int */
 private

    $id;
 
 /** @var string */
 private $name;
 
 /** @var int */
 private $price;
 
 /** @var int */
 private $stock;
 }
 int int int *UFNʢ঎඼ʣ
  5. &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ଐੑͷ಺༰͕൓ө͞Ε͍ͯͳ͍ wUIJTQSJDF
 ૝ఆ֎ͷ࢖͍ํʢ஋Ҿ͖༻঎඼ʣ wUIJTTUPDL UIJTTUPDL
 ͋Γ͑ͳ͍ԋࢉ
  6. &MPRVFOU 3FQPTJUPSZ class Item
 {
 /** @var ItemId */
 private

    $id;
 
 /** @var string */
 private $name;
 
 /** @var ItemPrice */
 private $price;
 
 /** @var Stock */
 private $stock;
 }
 ItemId ItemPrice Stock ܕʢΫϥεʣͰදݱ
  7. &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 ৼΔ෣͍ʢԋࢉʣ͕ແ͍
  8. &MPRVFOU 3FQPTJUPSZ class ItemPrice
 {
 /** @var int */
 private

    $value;
 
 
 public function __construct(int $value = 0)
 {
 if ($value < 0) {
 throw new InvariantException('value must be positive number:' . $value);
 }
 $this->value = $value;
 }
 //(snip)
 
 *UFN1SJDF ঎඼Ձ֨͸Ҏ্ͷ੔਺
  9. &MPRVFOU 3FQPTJUPSZ 
 public function calcSubtotal(ItemCount $count): ItemSubtotal
 {
 return

    new ItemSubtotal($this->value * $count->value());
 }
 *UFN1SJDF ঎඼Ձ֨ ঎඼ݸ਺঎඼খܭ
  10. &MPRVFOU 3FQPTJUPSZ class Cart
 {
 /** @var CartElement[]|Collection */
 private

    $elements;
 
 public function addItem(Item $item, ItemCount $count)
 {
 if (!$item->isSufficient($count)) {
 throw new InvariantException('stock is insufficient');
 }
 
 $this->elements->push(new CartElement($item, $count));
 }
 $BSU ࡏݿ͕଍Γͳ͚Ε͹ྫ֎
  11. &MPRVFOU 3FQPTJUPSZ class Cart
 {
 /** @var CartElement[]|Collection */
 private

    $elements;
 
 public function addItem(Item $item, ItemCount $count)
 {
 if (!$item->isSufficient($count)) {
 throw new PreconditionsException('stock is insufficient');
 }
 
 $this->elements->push(new CartElement($item, $count));
 }
 $BSU ΧʔτཁૉΛ௥Ճ
  12. &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
  13. &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
  14. &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
  15. &MPRVFOU 3FQPTJUPSZ class RepositoryServiceProvider extends ServiceProvider
 {
 public function register()


    {
 $this->app->bind(ItemRepository::class, EloquentItemRepository::class);
 }
 } ϦϙδτϦΛαʔϏείϯςφ΁όΠϯυ
  16. &MPRVFOU 3FQPTJUPSZ class AddItemToCart
 {
 private $itemRepo;
 
 public function

    __construct(ItemRepository $itemRepo)
 {
 $this->itemRepo = $itemRepo;
 }
 
 public function __invoke(int $itemId, int $count): Cart
 {
 $item = $this->itemRepo->findById(new ItemId($itemId));
 // (snip)
 }
 }
 ར༻ίʔυ
  17. &MPRVFOU 3FQPTJUPSZ public function find(): Cart
 {
 $cart = $this->session->get(static::SESSION_KEY);


    if (empty($cart)) {
 throw new NotFoundException('cart not found');
 }
 
 return $cart;
 }
 
 public function store(Cart $cart)
 {
 $this->session->put(static::SESSION_KEY, $cart);
 }
 )UUQ4FTTJPO$BSU3FQPTJUPSZ ηογϣϯ͔Βͷೖग़ྗ
  18. &MPRVFOU 3FQPTJUPSZ public function post(Request $request, AddItemToCart $useCase): JsonResponse
 {


    $this->validate($request, [
 'item_id' => 'required|integer',
 'count' => 'required|integer'
 ]);
 
 $cart = $useCase(
 $request->get('item_id'),
 $request->get('count')
 );
 return response()->json(['cart' => $this->cartToArray($cart)]); } $POUSPMMFS ͬ͘͟ΓόϦσʔγϣϯ
 ʢυϝΠϯϧʔϧ͸υϝΠϯϨΠϠͰʣ
  19. &MPRVFOU 3FQPTJUPSZ $POUSPMMFS public function post(Request $request, AddItemToCart $useCase): JsonResponse


    {
 $this->validate($request, [
 'item_id' => 'required|integer',
 'count' => 'required|integer'
 ]);
 
 $cart = $useCase(
 $request->get('item_id'),
 $request->get('count')
 );
 return response()->json(['cart' => $this->cartToArray($cart)]); } ϢʔεέʔεΛ࣮ߦ
  20. &MPRVFOU 3FQPTJUPSZ public function _invoke(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;
 }
 6TF$BTF