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

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

Ca17a082a30f4cbfed1d0a6dacbe3af2?s=47 shin1x1
October 29, 2016

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

2016/10/29 Laravel Osaka 2016 http://php-jp.github.io/laravel-osaka-2016/

Ca17a082a30f4cbfed1d0a6dacbe3af2?s=128

shin1x1

October 29, 2016
Tweet

Transcript

  1. ɹ!shin1x1 2016//29 LBSBWFM0TBLB %%%ύλʔϯΛ׆༻ͨ͠ -BSBWFMΞϓϦέʔγϣϯ։ൃ

  2. ର৅γεςϜ
 Ϣʔεέʔε

  3. &$αΠτ ΧʔτʹೖΕΔ

  4. %%%

  5. D .BTBTIJ4IJOCBSB!TIJOY %PNBJO%SJWFO%FTJHO wʮΤϦοΫɾΤϰΝϯεͷυϝΠϯۦಈઃܭʯ wυϝΠϯʹϑΥʔΧεͨ͠ઃܭɺ։ൃख๏ wଟ͘ͷύλʔϯ͕঺հ͞Ε͍ͯΔ

  6. D .BTBTIJ4IJOCBSB!TIJOY ιϑτ΢ΣΞͷυϝΠϯ wγεςϜͷର৅ྖҬɺղܾ͢Δ໰୊ྖҬ wۀ຿γεςϜͰ͋Ε͹ɺ
 ର৅ͷϏδωε͕υϝΠϯ wιʔείʔυ؅ཧγεςϜͰ͋Ε͹ɺ
 ιϑτ΢ΣΞ։ൃ͕υϝΠϯ wຊηογϣϯͰ͸ɺ&$αΠτ͕υϝΠϯ

  7. ϢϏΩλεݴޠ

  8. ϢϏΩλεݴޠ D .BTBTIJ4IJOCBSB!TIJOY wυϝΠϯ༻ޠࣙॻ
 ঎඼ɺΧʔτɺΧʔτʹ঎඼ΛೖΕΔɺͳͲ wϓϩδΣΫτνʔϜ಺Ͱಉ͡ݴ༿Λར༻
 ։ൃऀ΋ϏδωεΤΩεύʔτ΋શһ wͦͷݴ༿ΛίʔυͰ΋ར༻
 ʢ໊લۭؒɺΫϥεɺϝιου౳ʣ

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

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

    ঎඼ݸ਺ *UFN$PVOU ঎඼ͷݸ਺ɻҎ্ͷ੔਺ɻ Χʔτʹ঎඼Λ ೖΕΔ "EE*UFN5P$BSU Χʔτʹ঎඼ΛೖΕΔ͜ͱɻ
 ঎඼ͱ঎඼ݸ਺Λ༩͑Δɻ
 ঎඼ݸ਺͸঎඼ࡏݿҎԼͰ͋Δඞཁ ͕͋Δɻ
  11. D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1*  1045ϦΫΤετ͔Β঎඼*%ͱ঎඼ݸ਺Λऔಘ  σʔλϕʔε͔Β঎඼*%Ͱ঎඼Λऔಘ  Χʔτʹ঎඼ΛೖΕΔ 

    ΧʔτΛηογϣϯʹอଘ  ϨεϙϯεΛฦ͢
  12. ϨΠϠʔυ ΞʔΩςΫνϟ

  13. ϨΠϠʔυΞʔΩςΫνϟ D .BTBTIJ4IJOCBSB!TIJOY wγεςϜΛϨΠϠʢ૚ʣʹ෼ׂ wϨΠϠ͸ࣗ਎ͷ໾ׂΛ୲͏ wϨΠϠؒͰڠௐͯ͠ɺॲཧΛߦ͏ wϨΠϠؒͷྲྀΕ͸Ұํ௨ߦ

  14. %%%&SJD&WBOT D .BTBTIJ4IJOCBSB!TIJOY UI Application Infrastructure Domain

  15. D .BTBTIJ4IJOCBSB!TIJOY 6*-BZFS wϢʔβʢ࿈ܞγεςϜؚΉʣͱγεςϜͷ઀఺ wϢʔβ͸͜ͷϨΠϠΛ௨ͯ͡γεςϜʹ৮ΕΔ w)551 )5.- +40/ 45%*/ 45%065

    wϏϡʔɺ3FRVFTUɺ3FTQPOTF
  16. ඞཁ࠷௿ݶ͚ͩར༻ ͪ͜Βʹ࣮૷

  17. ΞϓϦέʔγϣϯ υϝΠϯ ΠϯϑϥετϥΫνϟ

  18. ϨΠϠؒͷྲྀΕ D .BTBTIJ4IJOCBSB!TIJOY UI Application Infrastructure Domain

  19. υϝΠϯϨΠϠ

  20. D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1*  1045ϦΫΤετ͔Β঎඼*%ͱ঎඼ݸ਺Λऔಘ  σʔλϕʔε͔Β঎඼*%Ͱ঎඼Λऔಘ  Χʔτʹ঎඼ΛೖΕΔ 

    ΧʔτΛηογϣϯʹอଘ  ϨεϙϯεΛฦ͢
  21. D .BTBTIJ4IJOCBSB!TIJOY υϝΠϯϨΠϠ wγεςϜͷυϝΠϯΛ࣮૷͢ΔϨΠϠ wυϝΠϯҎ֎ͷؔ৺ࣄ͸ؚΊͳ͍
 )551%#Ωϟογϡ౳ w1010Ͱ࣮૷͠ɺϑϨʔϜϫʔΫ͔Β͸ಠཱ
 'BDBEF΍ϔϧύʔؔ਺΋࢖Θͳ͍ wϞσϧɺαʔϏεɺΠϕϯτͳͲ

  22. D .BTBTIJ4IJOCBSB!TIJOY ΤϯςΟςΟ wυϝΠϯϞσϧͷ࣮૷
 ঎඼ɺΧʔτ w&MPRVFOUΛܧঝ͠ͳ͍ wಉҰੑ͸ࣝผࢠʢJEʣͰ൑ผ wϛϡʔλϒϧ

  23. D .BTBTIJ4IJOCBSB!TIJOY 7BMVF0CKFDU wՁ֨΍೔෇ͳͲϓϦϛςΟϒͳ஋Λࣔ͢
 ঎඼*%ɺ঎඼Ձ֨ɺࡏݿ wಉҰੑ͸ଐੑͰ൑ผ w஋ʹର͢Δ੍໿΍ৼΔ෣͍ʢԋࢉʣΛ࣮૷ wΠϛϡʔλϒϧ

  24. D .BTBTIJ4IJOCBSB!TIJOY ঎඼ΤϯςΟςΟ ঎඼ΤϯςΟςΟ͸ҎԼͷଐੑΛ࣋ͭ ಺༰ ৼΔ෣͍ʢԋࢉʣ ঎඼*% ঎඼ͷࣝผࢠ ঎඼͝ͱʹҰҙ ͳ͠

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

    $id;
 
 /** @var string */
 private $name;
 
 /** @var int */
 private $price;
 
 /** @var int */
 private $stock;
 }
 int int int *UFNʢ঎඼ʣ
  26. &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
 ૝ఆ֎ͷ࢖͍ํ͞ΕΔ
  27. &MPRVFOU 3FQPTJUPSZ class Item
 {
 /** @var ItemId */
 private

    $id;
 
 /** @var string */
 private $name;
 
 /** @var ItemPrice */
 private $price;
 
 /** @var Stock */
 private $stock;
 }
 ItemId ItemPrice Stock ܕʢΫϥεʣͰදݱ
  28. &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 ৼΔ෣͍ʢԋࢉʣ͕ແ͍
  29. &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 ঎඼Ձ֨͸Ҏ্ͷ੔਺
  30. &MPRVFOU 3FQPTJUPSZ 
 public function multi(ItemCount $count): ItemSubtotal
 {
 return

    new ItemSubtotal($this->value * $count->value());
 }
 *UFN1SJDF ঎඼Ձ֨ ঎඼ݸ਺঎඼খܭ
  31. D .BTBTIJ4IJOCBSB!TIJOY 7BMVF0CKFDUͷϙΠϯτ wϢϏΩλεݴޠΛίʔυͰදݱ
 ίʔυΛݟΕ͹࢓༷͕෼͔Δ wϝιουͰఆٛͨ͠ԋࢉ͔͠Ͱ͖ͳ͍
 ؒҧ͍ΛݮΒͤΔ w൚༻ܕͰ͸ͳ͘ಛԽܕͰ
 ʮ਺ࣈʯͰ͸ͳ͘ʮ঎඼Ձ֨ʯ wڽू౓্͕͕Γɺѻ͍΍͍͢ɻςετͷ༰қ

  32. &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Χʔτʹ঎඼ΛೖΕΔ ࡏݿ͕ෆ଍͍ͯ͠Δ͔ʁ
  33. &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Χʔτʹ঎඼ΛೖΕΔ ΧʔτཁૉΛ௥Ճ
  34. D .BTBTIJ4IJOCBSB!TIJOY υϝΠϯϨΠϠͷ࣮૷ wϑϨʔϜϫʔΫ͔Βಠཱͯ͠1010Ͱ࣮૷ w$PMMFDUJPOͳͲυϝΠϯΛදݱ͢ΔൣғͳΒPL w7BMVF0CKFDUͰυϝΠϯಛԽܕΛ࡞Γɺ
 ϢϏΩλεݴޠΛදݱ wυϝΠϯϨΠϠͰ͸70Λ࠷খཻ౓ʹ͢Δ
 70಺Ҏ֎Ͱ͸εΧϥʔܕ͸࢖Θͳ͍ʢཧ૝ʣ

  35. ΠϯϑϥετϥΫνϟϨΠϠ

  36. D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1*  1045ϦΫΤετ͔Β঎඼*%ͱ঎඼ݸ਺Λऔಘ  σʔλϕʔε͔Β঎඼*%Ͱ঎඼Λऔಘ  Χʔτʹ঎඼ΛೖΕΔ 

    ΧʔτΛηογϣϯʹอଘ  ϨεϙϯεΛฦ͢
  37. D .BTBTIJ4IJOCBSB!TIJOY ΠϯϑϥετϥΫνϟϨΠϠ wσʔλετΞ΍ϝʔϧૹ৴ɺ֎෦"1*࿈ܞͳͲ
 Ұൠతͳٕज़ػೳΛఏڙ͢ΔϨΠϠ wϦϙδτϦɺΩϟογϡɺ"1*ΫϥΠΞϯτͳͲ w&MPRVFOU2VFSZ#VJMEFS$BDIF

  38. D .BTBTIJ4IJOCBSB!TIJOY ϦϙδτϦ wϞσϧͱσʔλετΞͷؒʹհࡏ͠ɺ෼཭ wσʔλετΞ͔ΒͷϞσϧͷऔಘɺอଘૢ࡞Λ
 ΠϯλʔϑΣΠεͰఆٛ wσʔλετΞʹԠͯ͡ɺΠϯλʔϑΣΠεΛ࣮૷
 σʔλϕʔεɺ,74ɺϝϞϦͳͲ

  39. D .BTBTIJ4IJOCBSB!TIJOY ঎඼৘ใͷऔಘ wυϝΠϯϞσϧ*UFNΫϥε wσʔλϕʔεJUFNTςʔϒϧ w*UFN*EΛҾ਺ʹऔΓɺ߹க͢Δ*UFNΛฦ͢

  40. None
  41. ΠϯϑϥετϥΫνϟ $POUSPMMFS %BUB5SBOTGFS0CKFDU 3FQPTJUPSZ*OUFSGBDF 'PSN3FRVFTU "QQMJDBUJPO4FSWJDF ϑΝΠϧߏ੒%PNBJOϨΠϠ ϦϙδτϦ ΠϯλʔϑΣΠε

  42. &MPRVFOU 3FQPTJUPSZ interface ItemRepository
 {
 public function findById(ItemId $id): Item;


    } *UFN3FQPTJUPSZ
  43. ΠϯϑϥετϥΫνϟ $POUSPMMFS %BUB5SBOTGFS0CKFDU 3FQPTJUPSZ*OUFSGBDF 'PSN3FRVFTU "QQMJDBUJPO4FSWJDF ϑΝΠϧߏ੒*OGSBTUSVDUVSF ϦϙδτϦ &MPRVFOU

  44. &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
  45. &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
  46. &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
  47. &MPRVFOU 3FQPTJUPSZ class RepositoryServiceProvider extends ServiceProvider
 {
 public function register()


    {
 $this->app->bind(ItemRepository::class, EloquentItemRepository::class);
 }
 } ϦϙδτϦΛαʔϏείϯςφ΁όΠϯυ
  48. &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)
 }
 }
 ར༻ίʔυ
  49. D .BTBTIJ4IJOCBSB!TIJOY ϦϙδτϦ &MPRVFOU w&MPRVFOUΛ1FSTJTUFODF.PEFMʹ࢖͏ wΠϯϑϥετϥΫνϟϨΠϠͷ
 ϦϙδτϦ࣮૷ʹด͡ࠐΊΔ wଞϨΠϠͰ&MPRVFOU͸جຊ࢖Θͳ͍
 ʢϑϨʔϜϫʔΫར༻࣌͸আ͘ʣ

  50. D .BTBTIJ4IJOCBSB!TIJOY ϦϙδτϦͷϝϦοτ wσʔλετΞ΍ΞΫηεखஈͷ੾ସ͕༰қ
 ຊ൪͸1PTUHSF42-ςετ͸ϝϞϦ wυϝΠϯϨΠϠ͔ΒσʔλετΞ΁ͷ࣮૷Λഉআ
 υϝΠϯϨΠϠ͸ΠϯλʔϑΣΠεͷϝιουΛݺͿ͚ͩ wඞཁͳσʔλετΞ΁ͷૢ࡞Λ໌ࣔ
 7BMVF0CKFDUͱಉ༷

  51. ΞϓϦέʔγϣϯϨΠϠ

  52. D .BTBTIJ4IJOCBSB!TIJOY ΧʔτʹೖΕΔ"1*  1045ϦΫΤετ͔Β঎඼*%ͱ঎඼ݸ਺Λऔಘ  σʔλϕʔε͔Β঎඼*%Ͱ঎඼Λऔಘ  Χʔτʹ঎඼ΛೖΕΔ 

    ΧʔτΛηογϣϯʹอଘ  ϨεϙϯεΛฦ͢
  53. D .BTBTIJ4IJOCBSB!TIJOY ΞϓϦέʔγϣϯϨΠϠ wγεςϜͷίϯτϩʔϧΛ୲͏ϨΠϠ wϢʔεέʔεͷྲྀΕΛ࡞Γɺ۩ମతͳॲཧ͸
 υϝΠϯ΍ΠϯϑϥετϥΫνϟʹҕৡ w3PVUF$POUSPMMFS"QQMJDBUJPO4FSWJDF

  54. &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 ͬ͘͟ΓόϦσʔγϣϯ
 ʢυϝΠϯϧʔϧ͸υϝΠϯϨΠϠͰʣ
  55. &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 ΞϓϦέʔγϣϯαʔϏε࣮ߦ
  56. &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
  57. ·ͱΊ

  58. D .BTBTIJ4IJOCBSB!TIJOY ·ͱΊ wυϝΠϯϨΠϠ͕ओɺͦΕҎ֎͸ै
 υϝΠϯϨΠϠͦ͜ΞϓϦέʔγϣϯ
 มԽͷૣ͍-BSBWFM͔ͩΒͦ͜ wυϝΠϯʹಛԽ࣮ͨ͠૷ w-BSBWFM͸ࣗ༝౓ͷߴ͍ϑϨʔϜϫʔΫ w஌ݟΛͲΜͲΜڞ༗͠Α͏ʂ

  59. D .BTBTIJ4IJOCBSB!TIJOY !TIJOY !TIJOY D .BTBTIJ4IJOCBSB!TIJOY

  60. "QQFOEJY

  61. D .BTBTIJ4IJOCBSB!TIJOY ͲΕ͔Β͸͡ΊΔʁ 7BMVF0CKFDU

  62. D .BTBTIJ4IJOCBSB!TIJOY ୈҰาͱͯ͠ w੍໿͕͋Δ΋ͷɺԋࢉΛߦ͏΋ͷΛ70Խ wՁ֨ɺ೔෇ɺಛघͳ஋ʢ঎඼ίʔυͱ͔ʣ wJOUʹͯ͠΋ɺ$BSCPOʹͯ͠΋ૢ࡞͕๛෋
 υϝΠϯͰٻΊΒΕ͍ͯΔૢ࡞͕ݟ͑ͳ͍
 ஀ੜ೔ʹ࣌ؒ΍೔෇ͷ଍͠ࢉͱ͔͍Βͳ͍ wυϝΠϯಛԽܕͱͯ͠ΫϥεԽ

  63. &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Λϥοϓ ඞཁͳૢ࡞ͷΈ࣮૷
  64. D .BTBTIJ4IJOCBSB!TIJOY શ෦7BMVF0CKFDUʹ͢Δʁ w࣮ࡍɺखؒ͸͔͔Δ wJEʢJOUʣɺOBNFʢTUSJOHʣ͸70ʹͤͣ w70ʹ͢ΔͱɺϢϏΩλεݴޠΛਂ͘ߟ͑Δ
 ੍໿ɺඞཁͳૢ࡞ wڽू౓ͷߴ͍খ͞ͳΫϥεͷ࢖͍উखͷྑ͞
 ͜Εͦ͜ɺΦϒδΣΫτࢦ޲։ൃ