SlideShare uma empresa Scribd logo
1 de 87
Baixar para ler offline
Laravel
PHP Conference Fukuoka 2019
@okashoi WILLGATE, Inc.
•
• 🙆
•
• #phpconfuk #hall_fu
2
• 2
• 3
• 5
• 10
• 3
• 2
3
• 2
• 3
• 5
• 10
• 3
• 2
4
🏁
•
•
• Laravel


5
🙅
• Laravel
•
6
• 2
• 3
• 5
• 10
• 3
• 2
7
8
2017 2018
”The Clean Architecture - The Clean Code Blog”,
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
9
• 

•
•
10
•
•
•
※ PHP
11
“ 

”
12
• 2
• 3
• 5
• 10
• 3
• 2
13
14
15
16
🙅
17
18
•
•
•
•
19
20
21
↑
22
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
23
package bar;
class Bar {
function process() {
// do something...
}
}
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
24
package bar;
class Bar {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
25
package bar;
class Bar {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
26
package bar;
class Bar {
function process() {
// do something...
}
}
foo → bar
foo → bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
27
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
28
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
29
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
30
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
bar foo = foo ← bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
31
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
foo → bar
foo ← bar
“ 



”
32
• 

➡ 

33
34
UI
• 2
• 3
• 5
• 10
• 3
• 2
35
CleanArchitecture
Clean Architecture
Kindle No. 3228/6016 36
•
• https://github.com/okashoi/laravel-clean-
architecture
•
•
37
38
•
•
ID 

39
readme
40
•
•
• POPO Plain Old PHP Object
➡
41
• PHP
42
<?php
namespace MyAppComponentsTasksEntities;
use DatetimeImmutable;
/**
* Class Inbox
* @package MyAppComponentsTasksEntities
*/
final class Inbox extends Task
{
/**
* @var EstimatedTime|null
*/
private $estimatedTime;
•
•
43
/**
* @test
* @expectedException MyAppComponentsTasksEntitiesEstimatedTimeNotSet
*/
public function 「Inbox」に対して「見積もり時間」が未設定のまま「着手日」を設定できないこと()
{
$id = Mockery::mock(Id::class);
$name = new Name('test');
$inbox = new Inbox($id, $name);
$startDate = new StartDate(new DateTimeImmutable('tomorrow'));
$inbox->convertToScheduled($startDate);
}
44
45
•
• 

• 

46
InputBoundary / OutputBoundary
• 

47
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
/**
* Interface InputBoundary
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
interface InputBoundary
{
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void;
}
InputBoundary / OutputBoundary
• 

48
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
/**
* Interface NormalOutputBoundary
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
interface NormalOutputBoundary
{
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void;
}
Interactor
49
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
Interactor
50
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
InputBoundary
Interactor
51
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
DI
※ 

Interactor
52
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task


Interactor::__invoke()


53
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()


54
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()


55
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()
OutputBoundary 

56
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
57
•
• Repository
• 🙆
• Eloquent
58
Web UI
59
Web UI
•
• Controller 

void
• 

60
Controller
61
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Controller
62
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Laravel HttpControllers
Controller
63
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
HTTP
Controller
64
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
InputBoundary Interactor
Controller
65
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Presenter
•
66
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
Presenter
•
67
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
Interactor ViewModel
Presenter
•
68
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
View
※ Controller 

void ……🙇
•
• ServiceProvider
69
70
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
use MyAppComponentsTasksUseCasesCreateInboxInteractor;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
use MyAppComponentsTasksUseCasesIdProvider;
use MyAppComponentsTasksUseCasesTaskRepository as TaskRepositoryInterface;
use MyAppDatabaseRepositoriesAutoIncrementTaskIdProvider;
use MyAppDatabaseRepositoriesTaskRepository;
use MyAppWebPresentersCreateInboxPresenter;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(IdProvider::class, AutoIncrementTaskIdProvider::class);
$this->app->bind(TaskRepositoryInterface::class, TaskRepository::class);
$this->app->bind(InputBoundary::class, Interactor::class);
$this->app->bind(NormalOutputBoundary::class, Presenter::class);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
Laravel
• Laravel
• DI ServiceContainer
• 

ServiceProvider
• 

71
@Laravel JP Conference 2019
https://speakerdeck.com/mikakane/laravel-package-
development 72
73
74
packages 

75


76




77
web routes 

views
• 2
• 3
• 5
• 10
• 3
• 2
78
79
UI
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
80
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
🏁
•
•
• Laravel


81
• 2
• 3
• 5
• 10
• 3
• 2
82
/
@okashoi
@okashoi
83
• Hacker’s GATE
84
• Oysters
85
• Laravel JP Conference 2020
86https://conference2020.laravel.jp/
Ask the Speaker 

😂
87

Mais conteúdo relacionado

Mais procurados

言語の設計判断
言語の設計判断言語の設計判断
言語の設計判断
nishio
 

Mais procurados (20)

C#実装から見るDDD(ドメイン駆動設計)
C#実装から見るDDD(ドメイン駆動設計)C#実装から見るDDD(ドメイン駆動設計)
C#実装から見るDDD(ドメイン駆動設計)
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方
 
Harbor RegistryのReplication機能
Harbor RegistryのReplication機能Harbor RegistryのReplication機能
Harbor RegistryのReplication機能
 
グラフモデルとSoEとGraphQL データ指向アプリケーションデザインから見るGraphQL
グラフモデルとSoEとGraphQL データ指向アプリケーションデザインから見るGraphQLグラフモデルとSoEとGraphQL データ指向アプリケーションデザインから見るGraphQL
グラフモデルとSoEとGraphQL データ指向アプリケーションデザインから見るGraphQL
 
ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
組み込みLinuxでのGolangのススメ
組み込みLinuxでのGolangのススメ組み込みLinuxでのGolangのススメ
組み込みLinuxでのGolangのススメ
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
並列プログラミング 入門!&おさらい!
並列プログラミング入門!&おさらい!並列プログラミング入門!&おさらい!
並列プログラミング 入門!&おさらい!
 
Goでこれどうやるの? 入門
Goでこれどうやるの? 入門Goでこれどうやるの? 入門
Goでこれどうやるの? 入門
 
データ可視化勉強会
データ可視化勉強会データ可視化勉強会
データ可視化勉強会
 
Rails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) APIRails解説セミナー: Rails国際化 (I18n) API
Rails解説セミナー: Rails国際化 (I18n) API
 
The only one big thing every programmer should know
The only one big thing every programmer should knowThe only one big thing every programmer should know
The only one big thing every programmer should know
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
PHP の GC の話
PHP の GC の話PHP の GC の話
PHP の GC の話
 
言語の設計判断
言語の設計判断言語の設計判断
言語の設計判断
 
私とOSSの25年
私とOSSの25年私とOSSの25年
私とOSSの25年
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
ビジネスルールの複雑さに立ち向かう
ビジネスルールの複雑さに立ち向かうビジネスルールの複雑さに立ち向かう
ビジネスルールの複雑さに立ち向かう
 

Semelhante a Laravel でやってみるクリーンアーキテクチャ #phpconfuk

2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku
ronnywang_tw
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
Iftekhar Eather
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
rajivmordani
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡
Wei Jen Lu
 

Semelhante a Laravel でやってみるクリーンアーキテクチャ #phpconfuk (20)

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumaiクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondoクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
 
New in php 7
New in php 7New in php 7
New in php 7
 
2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
The Beauty of Java Script
The Beauty of Java ScriptThe Beauty of Java Script
The Beauty of Java Script
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 

Mais de Shohei Okada

Mais de Shohei Okada (20)

「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話
 
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようPHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
 
PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!
 
自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
 
スペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリアスペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリア
 
PHP でも活用できる Makefile
PHP でも活用できる MakefilePHP でも活用できる Makefile
PHP でも活用できる Makefile
 
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよはじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
 
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
 
働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード
 
Laravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならLaravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するなら
 
Laravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミLaravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミ
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
 
2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~
 
Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話
 
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみたLaravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
 
チームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組みチームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組み
 
プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
 

Último

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Último (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 

Laravel でやってみるクリーンアーキテクチャ #phpconfuk

  • 1. Laravel PHP Conference Fukuoka 2019 @okashoi WILLGATE, Inc.
  • 3. • 2 • 3 • 5 • 10 • 3 • 2 3
  • 4. • 2 • 3 • 5 • 10 • 3 • 2 4
  • 7. • 2 • 3 • 5 • 10 • 3 • 2 7
  • 9. ”The Clean Architecture - The Clean Code Blog”, https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 9
  • 13. • 2 • 3 • 5 • 10 • 3 • 2 13
  • 14. 14
  • 15. 15
  • 17. 17
  • 18. 18
  • 20. 20
  • 22. 22
  • 23. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 23 package bar; class Bar { function process() { // do something... } }
  • 24. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 24 package bar; class Bar { function process() { // do something... } } foo bar = foo → bar
  • 25. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 25 package bar; class Bar { function process() { // do something... } } foo bar = foo → bar
  • 26. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 26 package bar; class Bar { function process() { // do something... } } foo → bar foo → bar
  • 27. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 27 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 28. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 28 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 29. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 29 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } foo bar = foo → bar
  • 30. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 30 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } bar foo = foo ← bar
  • 31. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 31 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } foo → bar foo ← bar
  • 34. 34 UI
  • 35. • 2 • 3 • 5 • 10 • 3 • 2 35
  • 38. 38
  • 41. • • • POPO Plain Old PHP Object ➡ 41
  • 42. • PHP 42 <?php namespace MyAppComponentsTasksEntities; use DatetimeImmutable; /** * Class Inbox * @package MyAppComponentsTasksEntities */ final class Inbox extends Task { /** * @var EstimatedTime|null */ private $estimatedTime;
  • 43. • • 43 /** * @test * @expectedException MyAppComponentsTasksEntitiesEstimatedTimeNotSet */ public function 「Inbox」に対して「見積もり時間」が未設定のまま「着手日」を設定できないこと() { $id = Mockery::mock(Id::class); $name = new Name('test'); $inbox = new Inbox($id, $name); $startDate = new StartDate(new DateTimeImmutable('tomorrow')); $inbox->convertToScheduled($startDate); }
  • 44. 44
  • 45. 45
  • 47. InputBoundary / OutputBoundary • 
 47 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; /** * Interface InputBoundary * @package MyAppComponentsTasksUseCasesCreateInbox */ interface InputBoundary { /** * @param InputData $input */ public function __invoke(InputData $input): void; }
  • 48. InputBoundary / OutputBoundary • 
 48 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; /** * Interface NormalOutputBoundary * @package MyAppComponentsTasksUseCasesCreateInbox */ interface NormalOutputBoundary { /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void; }
  • 49. Interactor 49 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task
  • 50. Interactor 50 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task InputBoundary
  • 51. Interactor 51 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task DI ※ 

  • 52. Interactor 52 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task 

  • 53. Interactor::__invoke() 
 53 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 54. Interactor::__invoke() 
 54 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 55. Interactor::__invoke() 
 55 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 56. Interactor::__invoke() OutputBoundary 
 56 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 57. 57
  • 60. Web UI • • Controller 
 void • 
 60
  • 61. Controller 61 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } }
  • 62. Controller 62 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } Laravel HttpControllers
  • 63. Controller 63 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } HTTP
  • 64. Controller 64 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } InputBoundary Interactor
  • 65. Controller 65 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } }
  • 66. Presenter • 66 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } }
  • 67. Presenter • 67 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } } Interactor ViewModel
  • 68. Presenter • 68 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } } View ※ Controller 
 void ……🙇
  • 70. 70 <?php namespace AppProviders; use IlluminateSupportServiceProvider; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; use MyAppComponentsTasksUseCasesCreateInboxInteractor; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; use MyAppComponentsTasksUseCasesIdProvider; use MyAppComponentsTasksUseCasesTaskRepository as TaskRepositoryInterface; use MyAppDatabaseRepositoriesAutoIncrementTaskIdProvider; use MyAppDatabaseRepositoriesTaskRepository; use MyAppWebPresentersCreateInboxPresenter; class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { $this->app->bind(IdProvider::class, AutoIncrementTaskIdProvider::class); $this->app->bind(TaskRepositoryInterface::class, TaskRepository::class); $this->app->bind(InputBoundary::class, Interactor::class); $this->app->bind(NormalOutputBoundary::class, Presenter::class); } /** * Bootstrap any application services. * * @return void */ public function boot() { // } }
  • 71. Laravel • Laravel • DI ServiceContainer • 
 ServiceProvider • 
 71
  • 72. @Laravel JP Conference 2019 https://speakerdeck.com/mikakane/laravel-package- development 72
  • 73. 73
  • 78. • 2 • 3 • 5 • 10 • 3 • 2 78
  • 79. 79 UI
  • 80. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 80 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 82. • 2 • 3 • 5 • 10 • 3 • 2 82
  • 86. • Laravel JP Conference 2020 86https://conference2020.laravel.jp/
  • 87. Ask the Speaker 
 😂 87