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

WEB アプリケーション設計入門 / Introduction to web application design

E37b4344ef4bfd0fc4826c04971e54fb?s=47 nrs
December 12, 2020

WEB アプリケーション設計入門 / Introduction to web application design

PHP Conference Japan 2020
トーク前提の資料です。そのため、トークがないと理解が難しいかもしれません。
https://youtu.be/UTKJ-Lgn3aI?t=36
※冒頭音声が小さいです。マイクを手に持ってから聞こえやすくなると思います。

資料中の ADOP については下記を参照ください。
https://nrslib.com/adop/

# Abstract
https://fortee.jp/phpcon-2020/proposal/da5b9d99-e5a6-4f51-adea-1f1c10d99020

# Ref
https://github.com/nrslib/scrum-app-sample-php
https://github.com/nrslib/repository-support-php

# URL
Togetter: https://togetter.com/li/1635360
YouTube: https://www.youtube.com/c/narusemi
HomePage: https://nrslib.com
Twitter: https://twitter.com/nrslib

E37b4344ef4bfd0fc4826c04971e54fb?s=128

nrs

December 12, 2020
Tweet

Transcript

  1. 10年 先を見据えて作る PHP WEBアプリケーション設計入門

  2. 2 10年

  3. 3 10年続くことなんて そうそうなくない?

  4. 4 2000 2005 2010 2015 2020

  5. 5 2000 2005 2010 2015 2020

  6. 6 2000 2005 2010 2015 2020

  7. 7 2000 2005 2010 2015 2020

  8. 8 2000 2005 2010 2015 2020

  9. 9 2000 2005 2010 2015 2020

  10. 10 2000 2005 2010 2015 2020

  11. 11 2000 2005 2010 2015 2020

  12. 12 2000 2005 2010 2015 2020

  13. 13 2000 2005 2010 2015 2020

  14. 14 2000 2005 2010 2015 2020 SDプラン

  15. 15 2000 2005 2010 2015 2020 SDプラン RSプラン

  16. 16 10年の月日が もたらすもの

  17. 17 10年 ×

  18. 18 2000 2005 2010 2015 2020

  19. 19 2000 2005 2010 2015 2020 PHP Tools (1995)

  20. 20 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020)
  21. 21 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008)
  22. 22 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008)
  23. 23 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008)
  24. 24 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008)
  25. 25 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 1 (2011)
  26. 26 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 1 (2011)
  27. 27 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 3 (2012) 1 (2011)
  28. 28 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 3 (2012) 4.0 (2013) 4.1 (2013) 4.2 (2014) 1 (2011)
  29. 29 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 3 (2012) 4.0 (2013) 5.0 (2015) 5.1 (2015) 4.1 (2013) 4.2 (2014) 5.2 (2015) 5.3 (2016) 5.4 (2017) 5.5 (2017) 5.6 (2018) 5.7 (2018) 5.8 (2019) 1 (2011)
  30. 30 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 3 (2012) 4.0 (2013) 5.0 (2015) 5.1 (2015) 4.1 (2013) 4.2 (2014) 5.2 (2015) 5.3 (2016) 5.4 (2017) 5.5 (2017) 5.6 (2018) 5.7 (2018) 5.8 (2019) 6 (2019) 7 (2020) 8 (2020) 1 (2011)
  31. 31 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 2 (2011) 3 (2012) 4.0 (2013) 5.0 (2015) 5.1 (2015) 4.1 (2013) 4.2 (2014) 5.2 (2015) 5.3 (2016) 5.4 (2017) 5.5 (2017) 5.6 (2018) 5.7 (2018) 5.8 (2019) 6 (2019) 7 (2020) 8 (2020) 1 (2011)
  32. 32 どんな手立てを取れるか

  33. 33

  34. 34

  35. 35

  36. 36

  37. 37

  38. 10年 先を見据えて作る PHP WEBアプリケーション設計入門

  39. None
  40. None
  41. None
  42. None
  43. None
  44. 44 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008)
  45. 45

  46. 46 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 候補があがったら ・チームの士気が上がるか ・10年後に残ってそうか の観点で選ぶ
  47. 47 2000 2005 2010 2015 2020 PHP Tools (1995) PHP2

    (1996) PHP3 (1998) PHP4 (2000) PHP5 (2004) PHP6 PHP7 (2015) PHP8 (2020) phrame (2003) mojavi (2004) Agavi (2005) Ethna (2005) Maple (2005) CakePHP (2006) Symfony (2007) Zend Framework (2007) Laravel (2011) CodeIgniter (2006) FuelPHP (2011) Phalcon (2012) Yii (2008) 候補があがったら ・チームの士気が上がるか ・10年後に残ってそうか の観点で選ぶ 10年残るかは運次第
  48. 48

  49. 49

  50. 50

  51. None
  52. 52

  53. 53

  54. 54 https://alistair.cockburn.us/hexagonal-architecture/ https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html User Interface Application Domain Infrastructure

  55. 55 https://alistair.cockburn.us/hexagonal-architecture/ https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html User Interface Application Domain Infrastructure

  56. 56 https://alistair.cockburn.us/hexagonal-architecture/ https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html User Interface Application Domain Infrastructure

  57. 57 User Interface Application Domain Infrastructure

  58. 58 User Interface Application Domain Infrastructure OK

  59. 59 User Interface Application Domain Infrastructure OK NG

  60. 60 User Interface Application Domain Infrastructure OK NG MVC Framework

  61. None
  62. 62 https://github.com/nrslib/scrum-app-sample-php

  63. 63

  64. 64

  65. 65

  66. 66

  67. 67 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  68. 68 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  69. 69 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  70. 70 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  71. 71 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  72. 72 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  73. 73 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  74. 74 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  75. 75 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  76. 76 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  77. 77 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  78. 78 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  79. 79 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  80. 80 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  81. 81 class BackLogController extends Controller { ... public function postAddUserStory(

    Request $request, BackLogApplicationService $applicationService ) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  82. 82 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; public function __construct( Transaction $transaction, UserContextInterface $userContext, UserStoryRepositoryInterface $userStoryRepository ) { $this->transaction = $transaction; $this->userContext = $userContext; $this->userStoryRepository = $userStoryRepository; } public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  83. 83 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; public function __construct( Transaction $transaction, UserContextInterface $userContext, UserStoryRepositoryInterface $userStoryRepository ) { $this->transaction = $transaction; $this->userContext = $userContext; $this->userStoryRepository = $userStoryRepository; } public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  84. 84 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  85. 85 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  86. 86 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  87. 87 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  88. 88 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  89. 89 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  90. 90 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  91. 91 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  92. 92 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  93. 93 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  94. 94 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  95. 95 interface UserStoryRepositoryInterface { public function find(UserStoryId $id): ?UserStory; public

    function save(UserStory $userStory): void; }
  96. 96 class EloquentUserStoryRepository implements UserStoryRepositoryInterface { ... public function save(UserStory

    $userStory): void { UserStoryDataModel::updateOrCreate( ["id" => $userStory->getId()->getValue()], [ "story" => $userStory->getStory(), "author" => $userStory->getAuthor()->getValue(), "demo" => $userStory->getDemo(), "estimate" => $userStory->getEstimate(), "seq" => $userStory->getSeq() ] ); } }
  97. 97 class EloquentUserStoryRepository implements UserStoryRepositoryInterface { ... public function save(UserStory

    $userStory): void { UserStoryDataModel::updateOrCreate( ["id" => $userStory->getId()->getValue()], [ "story" => $userStory->getStory(), "author" => $userStory->getAuthor()->getValue(), "demo" => $userStory->getDemo(), "estimate" => $userStory->getEstimate(), "seq" => $userStory->getSeq() ] ); } }
  98. 98 User Interface Application Domain Infrastructure OK NG MVC Framework

  99. 99

  100. 100

  101. None
  102. 102

  103. 103

  104. 104

  105. 105

  106. 106

  107. 107

  108. 108

  109. None
  110. 110 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $repository = new EloquentUserStoryRepository(); $repository->save($story); }); } }
  111. 111 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $repository = new EloquentUserStoryRepository(); $repository->save($story); }); } }
  112. 112 class BackLogApplicationService { /** @var UserStoryRepositoryInterface */ private $userStoryRepository;

    ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  113. 113 class BackLogApplicationService { /** @var UserStoryRepositoryInterface */ private $userStoryRepository;

    ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  114. 114 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; public function __construct( Transaction $transaction, UserContextInterface $userContext, UserStoryRepositoryInterface $userStoryRepository ) { $this->transaction = $transaction; $this->userContext = $userContext; $this->userStoryRepository = $userStoryRepository; } ... }
  115. 115 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; public function __construct( Transaction $transaction, UserContextInterface $userContext, UserStoryRepositoryInterface $userStoryRepository ) { $this->transaction = $transaction; $this->userContext = $userContext; $this->userStoryRepository = $userStoryRepository; } ... }
  116. 116 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; public function __construct( Transaction $transaction, UserContextInterface $userContext, UserStoryRepositoryInterface $userStoryRepository ) { $this->transaction = $transaction; $this->userContext = $userContext; $this->userStoryRepository = $userStoryRepository; } ... }
  117. 117

  118. 118 class ProductionServiceProvider implements Provider { ... private function registerApplications()

    { $this->app->bind(BackLogApplicationService::class); ... } private function registerInfrastructures() { $this->app->bind( BackLogQueryServiceInterface::class, EloquentBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, EloquentUserStoryRepository::class ); ... } }
  119. 119 class ProductionServiceProvider implements Provider { ... private function registerApplications()

    { $this->app->bind(BackLogApplicationService::class); ... } private function registerInfrastructures() { $this->app->bind( BackLogQueryServiceInterface::class, EloquentBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, EloquentUserStoryRepository::class ); ... } }
  120. 120 class LocalServiceProvider implements Provider { ... private function registerInfrastructures()

    { $this->app->bind( BackLogQueryServiceInterface::class, FileBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, StubUserStoryRepository::class ); $this->app->bind(FileUserStoryRepository::class); ... } }
  121. 121 class LocalServiceProvider implements Provider { ... private function registerInfrastructures()

    { $this->app->bind( BackLogQueryServiceInterface::class, FileBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, StubUserStoryRepository::class ); $this->app->bind(FileUserStoryRepository::class); ... } }
  122. 122 class StubUserStoryRepository implements UserStoryRepositoryInterface { public function find(UserStoryId $id):

    ?UserStory { return new UserStory( new UserStoryId("test-id"), "test-story", new UserId("test-author-id"), "demo sequence", 3, 1 ); } public function save(UserStory $userStory): void { } }
  123. 123 Eloquent UserStoryRepository BackLog ApplicationService

  124. 124 Eloquent UserStoryRepository BackLog ApplicationService UserStoryRepository Interface

  125. 125 Eloquent UserStoryRepository BackLog ApplicationService UserStoryRepository Interface

  126. 126

  127. 127

  128. 128

  129. 129 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー

  130. 130 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー テーブル定義 変えないとな―

  131. 131 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー テーブル定義 変えないとな― ALTER TABLE

    ...
  132. 132 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー テーブル定義 変えないとな― ALTER TABLE

    ...
  133. 133 class LocalServiceProvider implements Provider { ... private function registerInfrastructures()

    { $this->app->bind( BackLogQueryServiceInterface::class, FileBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, StubUserStoryRepository::class ); $this->app->bind(FileUserStoryRepository::class); ... } }
  134. 134 class StubUserStoryRepository implements UserStoryRepositoryInterface { public function find(UserStoryId $id):

    ?UserStory { return new UserStory( new UserStoryId("test-id"), "test-story", new UserId("test-author-id"), "demo sequence", 3, 1 ); } public function save(UserStory $userStory): void { } }
  135. 135 class StubUserStoryRepository implements UserStoryRepositoryInterface { public function find(UserStoryId $id):

    ?UserStory { return new UserStory( new UserStoryId("test-id"), "test-story", new UserId("test-author-id"), "demo sequence", 3, 1 ); } public function save(UserStory $userStory): void { } }
  136. 136

  137. 137 https://github.com/nrslib/repository-support-php

  138. 138 class LocalServiceProvider implements Provider { ... private function registerInfrastructures()

    { $this->app->bind( BackLogQueryServiceInterface::class, FileBackLogQueryService::class ); $this->app->bind( UserStoryRepositoryInterface::class, FileUserStoryRepository::class ); $this->app->bind(FileUserStoryRepository::class); ... } }
  139. 139 class FileUserStoryRepository implements UserStoryRepositoryInterface { use FileRepository; public function

    find(UserStoryId $id): ?UserStory { $story = $this->load($id->getValue()); if (is_null($story)) { return null; } else { return $story; } } public function save(UserStory $userStory): void { $rawId = $userStory->getId()->getValue(); $this->store($rawId, $userStory); } }
  140. 140 class FileUserStoryRepository implements UserStoryRepositoryInterface { use FileRepository; public function

    find(UserStoryId $id): ?UserStory { $story = $this->load($id->getValue()); if (is_null($story)) { return null; } else { return $story; } } public function save(UserStory $userStory): void { $rawId = $userStory->getId()->getValue(); $this->store($rawId, $userStory); } }
  141. 141 trait FileRepository { /** @var FileStore */ private $store;

    /** @var null|string */ protected $identifier = null; public function __construct() { $this->store = new FileStore(); } public function loadAll() { return $this->store->getAll( $this->id() ); } protected function store($key, $data) { $this->store->put($this->id(), $key, $data); } protected function load($key) { return $this->store->get($this->id(), $key); } private function id() { if (is_null($this->identifier)) { return __CLASS__; } else { return $this->identifier; } } }
  142. 142 trait FileRepository { /** @var FileStore */ private $store;

    /** @var null|string */ protected $identifier = null; public function __construct() { $this->store = new FileStore(); } public function loadAll() { return $this->store->getAll( $this->id() ); } protected function store($key, $data) { $this->store->put($this->id(), $key, $data); } protected function load($key) { return $this->store->get($this->id(), $key); } private function id() { if (is_null($this->identifier)) { return __CLASS__; } else { return $this->identifier; } } }
  143. 143

  144. 144

  145. 145 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー

  146. 146 あー モデリングとか コーディングしてたら オブジェクトの データ違ったなー フィールド追加して .dat 消して終わり

  147. 147 Production と Debug で環境を変えられる

  148. None
  149. 149 class UserStory { /** @var UserStoryId */ private $id;

    /** @var string */ private $story; /** @var UserId */ private $author; /** @var string|null */ private $demo; /** @var int|null */ private $estimate; /** @var int|null */ private $seq; public function __construct( UserStoryId $id, string $story, UserId $author, string $demo = null, int $estimate = null, int $seq = null ) { $this->id = $id; $this->story = $story; $this->author = $author; $this->demo = $demo; $this->estimate = $estimate; $this->seq = $seq; } ... }
  150. 150 /** * Class UserStoryDataModel * @package Scrum¥EloquentInfrastructure¥Models * *

    @property integer $id * @property string $story * @property string $author * @property string|null $demo * @property integer|null $estimate * @property integer|null $seq */ class UserStoryDataModel extends Model { protected $table = "user_stories"; public $incrementing = false; protected $keyType = "string"; public $guarded = []; }
  151. 151

  152. 152 UserStory

  153. 153 UserStory UserStory DataModel

  154. 154 UserStory UserStory DataModel

  155. 155 class UserStory extends Model { protected $table = "user_stories";

    public $incrementing = false; protected $keyType = "string"; public $guarded = []; /** @var UserStoryId */ private $id; ... }
  156. 156 class UserStory extends Model { protected $table = "user_stories";

    public $incrementing = false; protected $keyType = "string"; public $guarded = []; /** @var UserStoryId */ private $id; ... } User Story
  157. 157 class UserStory extends Model { protected $table = "user_stories";

    public $incrementing = false; protected $keyType = "string"; public $guarded = []; /** @var UserStoryId */ private $id; ... } User Story
  158. 158 UserStory UserStory DataModel

  159. 159 User Interface Application Domain Infrastructure OK NG MVC Framework

  160. 160 User Interface Application Domain Infrastructure OK NG MVC Framework

    OK?
  161. 161 Infrastructure User Interface Application Domain OK NG

  162. 162 Infrastructure User Interface Application Domain OK NG

  163. 163 Infrastructure User Interface Application Domain OK NG

  164. 164 Infrastructure User Interface Application Domain OK NG

  165. 165 Infrastructure User Interface Application Domain OK NG

  166. 166 Infrastructure User Interface Application Domain OK NG

  167. 167 https://alistair.cockburn.us/hexagonal-architecture/

  168. None
  169. 169 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  170. 170 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  171. 171 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), Auth::user()->getAuthIdentifier(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  172. 172 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), Auth::user()->getAuthIdentifier(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  173. 173 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), Auth::user()->getAuthIdentifier(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  174. 174 interface UserContextInterface { function getId(): ?UserId; }

  175. 175 interface UserContextInterface { function getId(): ?UserId; } class AuthUserContext

    implements UserContextInterface { function getId(): ?UserId { $user = Auth::user(); if (is_null($user)) { return null; } $rawId = $user->getAuthIdentifier(); $id = new UserId($rawId); return $id; } }
  176. 176 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  177. 177 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  178. 178 class BackLogApplicationService { /** @var Transaction */ private $transaction;

    /** @var UserContextInterface */ private $userContext; /** @var UserStoryRepositoryInterface */ private $userStoryRepository; ... public function addUserStory(AddUserStoryCommand $command) { $this->transaction->scope(function () use ($command) { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); }); } }
  179. 179 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    DB::beginTransaction(); try { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); DB::commit(); } catch ($exception) { DB::rollBack(); } } }
  180. 180 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    DB::beginTransaction(); try { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); DB::commit(); } catch ($exception) { DB::rollBack(); } } }
  181. 181 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    DB::beginTransaction(); try { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); DB::commit(); } catch ($exception) { DB::rollBack(); } } }
  182. 182 interface Transaction { /** * @param callable $transactionScope *

    @return mixed */ function scope(callable $transactionScope): ?object; function begin(); function commit(); function rollback(); }
  183. 183 class LaravelDbTransaction implements Transaction { function scope(callable $transactionScope): ?object

    { return DB::transaction($transactionScope); } function begin() { DB::beginTransaction(); } function commit() { DB::commit(); } function rollback() { DB::rollBack(); } }
  184. 184 $this->app->bind(Transaction::class, LaravelDbTransaction::class);

  185. 185 class BackLogApplicationService { ... public function addUserStory(AddUserStoryCommand $command) {

    $this->transaction->begin(); try { $id = new UserStoryId(uniqid()); $story = new UserStory( $id, $command->getStory(), $this->userContext->getId(), $command->getDemo() ); $this->userStoryRepository->save($story); $this->transaction->commit(); } catch ($exception) { $this->transaction->rollback(); } } }
  186. 186 class NopTransaction implements Transaction { function scope(callable $transactionScope): ?object

    { return $transactionScope(); } function begin() { } function commit() { } function rollback() { } }
  187. None
  188. 188 class BackLogController extends Controller { ... public function postAddUserStory(Request

    $request) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService = new BackLogApplicationService( new LaravelDbTransaction(), new AuthUserContext(), new EloquentUserStoryRepository() ); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  189. 189 class BackLogController extends Controller { ... public function postAddUserStory(Request

    $request) { $request->validate([ "story" => "required" ]); $story = $request->input("story"); $command = new AddUserStoryCommand($story); $applicationService = new BackLogApplicationService( new LaravelDbTransaction(), new AuthUserContext(), new EloquentUserStoryRepository() ); $applicationService->addUserStory($command); return redirect()->action([BackLogController::class, "index"]); } }
  190. 190 class UserStory { ... public function __construct( UserStoryId $id,

    string $story, UserId $author, string $demo = null, int $estimate = null, int $seq = null ) { if (strlen($story) == 0) { throw new ¥InvalidArgumentException("story is empty.") } $this->id = $id; $this->story = $story; $this->author = $author; $this->demo = $demo; $this->estimate = $estimate; $this->seq = $seq; } }
  191. 191 class UserStory { ... public function __construct( UserStoryId $id,

    string $story, UserId $author, string $demo = null, int $estimate = null, int $seq = null ) { if (strlen($story) == 0) { throw new ¥InvalidArgumentException("story is empty.") } $this->id = $id; $this->story = $story; $this->author = $author; $this->demo = $demo; $this->estimate = $estimate; $this->seq = $seq; } }
  192. None
  193. 193 Infrastructure User Interface Application Domain OK NG

  194. 194 Infrastructure User Interface Application Domain OK NG

  195. 195 Infrastructure User Interface Application Domain OK NG

  196. 196 Infrastructure User Interface Application Domain OK NG

  197. 197 Infrastructure User Interface Application Domain OK NG

  198. 198 Infrastructure User Interface Application Domain OK NG

  199. 199 Infrastructure User Interface Application Domain OK NG

  200. 200 Infrastructure User Interface Application Domain OK NG

  201. 201 Infrastructure User Interface Application Domain OK NG 1件~100件まで 自由に取れます

  202. 202 Infrastructure User Interface Application Domain OK NG 1件~100件まで 自由に取れます

    ドロップダウンで選択するので 10,30,50,100 のいずれかです
  203. 203 Infrastructure User Interface Application Domain OK NG 1件~100件まで 自由に取れます

    ドロップダウンで選択するので 10,30,50,100 のいずれかです
  204. 204 Infrastructure User Interface Application Domain OK NG Validation Module

    OK
  205. None
  206. 206

  207. 207

  208. 208

  209. 209

  210. 210

  211. 211

  212. 212

  213. 213

  214. 214

  215. 215

  216. 216

  217. 217 ID

  218. 218 ID ID

  219. 219 ID ID

  220. 220 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  221. 221 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  222. 222 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  223. 223 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  224. 224 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  225. 225 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  226. 226 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  227. 227 class UserApplicationService { ... public function create(string $email, string

    $password): UserCreateResult { return $this->transaction->scope(function () use ($email, $password) { $user = $this->userFactory->create($email, $password); $found = $this->userRepository->findByEmail($user->getEmail()); if (!is_null($found)) { return UserCreateResult::fail(UserCreateError::EMAIL_ALREADY_USING); } $this->userRepository->save($user); return UserCreateResult::success($user->getId()); }); } ... }
  228. 228 class AuthController extends Controller { public function postRegister(Request $request,

    UserApplicationService $service) { ... $email = $request->get("email"); $password = $request->get("password"); try { $service->create($email, $password); } catch ($exception) { $result = UserCreateError::EMAIL_ALREADY_USING; } ... } }
  229. 229 class AuthController extends Controller { public function postRegister(Request $request,

    UserApplicationService $service) { ... $email = $request->get(“email”); $password = $request->get(“password”); $result = $service->create($email, $password); ... } }
  230. 230

  231. None
  232. 232

  233. 233

  234. 234

  235. 235

  236. 236

  237. 237 class RequestResponseLogger { public function handle(Request $request, Closure $next)

    { ... Logging Request $response = $next($request); ... Logging Response return $response; } }
  238. 238 class RequestResponseLogger { public function handle(Request $request, Closure $next)

    { ... Logging Request $response = $next($request); ... Logging Response return $response; } }
  239. 239 class RequestResponseLogger { public function handle(Request $request, Closure $next)

    { ... Logging Request $response = $next($request); ... Logging Response return $response; } }
  240. 240 class RequestResponseLogger { public function handle(Request $request, Closure $next)

    { ... Logging Request $response = $next($request); ... Logging Response return $response; } }
  241. 241

  242. 242 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  243. 243 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  244. 244 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  245. 245 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  246. 246 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  247. 247 class BackLogApplicationService { ... public function estimateUserStory(string $aId, int

    $estimation): void { $this->transaction->scope(function () use ($aId, $estimation) { $id = new UserStoryId($aId); $story = $this->userStoryRepository->find($id); if (is_null($story)) { throw new NotFoundException($aId . " not found."); } $story->estimate($estimation); $this->userStoryRepository->save($story); }); } }
  248. 248 class ExceptionResolver { public function handle(Request $request, Closure $next)

    { $response = $next($request); if (!empty($response->exception)) { if ($response->exception instanceof NotFoundException){ return response(view("notfound")); } } return $response; } }
  249. 249

  250. 250 Infrastructure User Interface Application Domain OK NG

  251. 251 2000 2005 2010 2015 2020 SDプラン RSプラン

  252. 252

  253. 253

  254. 254

  255. 10年 先を見据えて作る PHP WEBアプリケーション設計入門

  256. None
  257. 257

  258. 258

  259. 259

  260. 260 class UserApplicationService { /** @var UserRepositoryInterface */ private $userRepository;

    ... public function retrieveById(string $aId): ?User { $id = new UserId($aId); $user = $this->userRepository->find($id); return $user; } }
  261. 261 class AuthenticateService { /** @var UserRepositoryInterface */ private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function authenticate(string $aEmail, string $password): bool { $email = new Email($aEmail); $user = $this->userRepository->findByEmail($email); if (is_null($user)) { return false; } $hasher = new PasswordHasher(); return $hasher->checkByUser($password, $user); } }
  262. 262 class OriginalUserProvider implements UserProvider { /** @var AuthenticateService */

    private $authenticateService; /** @var UserApplicationService */ private $userService; public function __construct( AuthenticateService $authenticateService, UserApplicationService $userService ) { $this->authenticateService = $authenticateService; $this->userService = $userService; } ... public function validateCredentials(Authenticatable $user, array $credentials) { $password = $credentials["password"]; $email = $credentials["email"]; $result = $this->authenticateService->authenticate($email, $password); return $result; } }
  263. 263

  264. 264 Auther Masanobu Naruse YouTube https://www.youtube.com/c/narusemi HomePage https://nrslib.com Twitter @nrslib