Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Laravelを始めて DDDを実践するまで
Search
Kazuki Ohashi
March 08, 2018
Technology
2
1.9k
Laravelを始めて DDDを実践するまで
Laravelを始めてから、DDDを実践するまでの過程
Kazuki Ohashi
March 08, 2018
Tweet
Share
More Decks by Kazuki Ohashi
See All by Kazuki Ohashi
larave_vue_graphql_supplementation
kzkohashi
1
850
Introduction to using GraphQL for a bit
kzkohashi
0
220
フォロワーがどの雑誌に興味があるのか可視化してみる / magazine-score
kzkohashi
0
670
Amazon Rekognitionを用いてフォロワーの男女比を出す
kzkohashi
1
2.8k
Other Decks in Technology
See All in Technology
about #74462 go/token#FileSet
tomtwinkle
1
270
"複雑なデータ処理 × 静的サイト" を両立させる、楽をするRails運用 / A low-effort Rails workflow that combines “Complex Data Processing × Static Sites”
hogelog
3
1.4k
AI×Data×SaaS×Operation
sansantech
PRO
0
110
Windows で省エネ
murachiakira
0
150
20250929_QaaS_vol20
mura_shin
0
110
FastAPIの魔法をgRPC/Connect RPCへ
monotaro
PRO
1
610
「技術負債にならない・間違えない」 権限管理の設計と実装
naro143
33
10k
BirdCLEF+2025 Noir 5位解法紹介
myso
0
170
【新卒研修資料】LLM・生成AI研修 / Large Language Model・Generative AI
brainpadpr
21
15k
AIが書いたコードをAIが検証する!自律的なモバイルアプリ開発の実現
henteko
1
240
VCC 2025 Write-up
bata_24
0
150
組織観点からIAM Identity CenterとIAMの設計を考える
nrinetcom
PRO
1
130
Featured
See All Featured
Embracing the Ebb and Flow
colly
88
4.8k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
51k
KATA
mclloyd
32
14k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.7k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
3k
Making Projects Easy
brettharned
118
6.4k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Automating Front-end Workflow
addyosmani
1371
200k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
30
2.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
32
2.2k
Code Review Best Practice
trishagee
72
19k
Transcript
-BSBWFMΛ࢝Ίͯ %%%Λ࣮ફ͢Δ·Ͱ Laravel Meetup Tokyo Vol.10 େڮ Ұथ @kzkohashi
େڮҰथ!L[LPIBTIJ w ΠϯϑϧΤϯαʔϚʔέςΟϯά w αʔόαΠυ ϑϩϯτத৺ w -BSBWFM࢝Ίͯ̍͘Β͍ w %%%ษڧ࢝͠Ίͯϲ݄
%%%ͬͯΔ PS %%%࣮ફͯ͠Δํ
ࠓ͓͢͠Δ͜ͱ -BSBWFMͰ%%%Λ࣮ફ͢Δ·Ͱͷաఔ %%%Λ࣮ફ͢Δ͜ͱͰԿ͕มΘͬͨʁ ٯʹฉ͍ͯΈ͍ͨ
-BSBWFM࢝ΊΔ
͍͍ɻΊͪΌ͍͍ɻ w ͙͢ʹؾ࣋ͪΑ͔͚͘Δ w ཉ͍͠ػೳ͕σϑΥϧτͰ͋Δʢ֦ு͍͢͠ʂʂ w ϥΠϒϥϦ๛ w ຊޠॆ࣮
ॻ͖͍͢ɺઃܭΛ͔ͬ͠Γ͠ͱ͖͍ͨ
%%%Λษڧ࢝͠ΊΔ
͍͍ɻΊͪΌ͍͍ɻ w ݱ࣮ͷؔ৺ΛͰ͖Δ͚ͩ։ൃ্ͱͰγϯΫϩͤ͞Δ w υϝΠϯΤΩεύʔτͱΤϯδχΞͷҰॹʹ͠߹ͬͯϞ σϦϯά͍ͯ͘͠ w ڞ௨ݴޠʢϢϏΩλεݴޠʣͷൃ۷ w ͳΜͲมߋɾվળ͍ͯ͘͠ͷ
֓೦ૉΒ͍͠ʂ
Ͱɺ࣮ફํ๏ʁ
࣮ફͷෑډߴ͍ʁ w ຊಡΉ͚ͩ͡ΌΑ͘Θ͔Βͳ͍ w ࣮ફͯ͠ͳ͕Βͬͯͨ΄͏͕Αͦ͞͏ w 8FCʹ࣮ફ͢ΔͨΊͷ৭ʑͳΞʔΩςΫνϟͳͲ͕͋Δ ௐͨͱ͖ʹΑ͘࠾༻͞Ε͍ͯΔ 3FQPTJUPSZύλʔϯΛಋೖ
$POUSPMMFS 4FSWJDF 3FQPTJUPSZ &MPRVFOU3FQPTJUPSZ .PEFM ϓϨθϯςʔγϣϯ ϏδωεϩδοΫ σʔλૢ࡞ ϏδωεϩδοΫ͔Βσʔλૢ࡞ͷॲཧΛΓ͢ ʢ˞ඞͣͦ͠͏Ͱͳ͍ʣ
ͱ͋ΔαʔϏεͷྫ Ϣʔεέʔε w ϝʔΧʔΞΧϯτΛొ͢Δ w ϝʔΧʔΞΧϯτΛෳ࡞ΕΔ Ϟσϧ
interface MakerAccountRepository { public function getLoginAccountByEmail($email); public function findById($id); public
function register($name, $tel, $email, $password); } 3FQPTJUPSZ ར༻͢ΔࡍͷΠϯλʔϑΣʔε
class EloquentMakerAccountRepository implements MakerAccountRepository { /** @var \App\Models\MakerAccount */ protected
$maker_account; public function __construct(MakerAccount $maker_account) { $this->maker_account = $maker_account; } public function getLoginUserByEmail($email) { return $this->maker_account->whereEmail($email) ->with('maker') ->first(); } public function register($maker_id, …) { $data[‘…’] = $maker_id; … return $this->maker_account->create($data); } } &MPRVFOU3FQPTJUPSZ .PEFMΛ%*
class MakerAccountRegisterService { protected $maker_repo; protected $maker_account_repo; public function __construct(
MakerRepository $maker_repo, MakerAccountRepository $maker_account_repo ) { $this->maker_repo = $maker_repo; $this->maker_account_repo = $maker_account_repo; } protected function register($maker_name,…লུ) { return \DB::transaction(function () use (...লུ) { /** @var \App\Models\Maker $maker */ $maker = $this->maker_repo->register($maker_name, $address); $this->maker_account_repo->register( $maker->id, $staff_name, $tel, $email, $password ); }); } } 4FSWJDF ϦϙδτϦʔΛ௨ͯ͠ొ
Կ͔มΘͬͨʁ w ϏδωεϩδοΫͱσʔλૢ࡞ΛେମΓͤͨ w ݁ہฦ͍ͯ͠Δͷ͕&MPRVFOUͷͨΊɺ֎ଆͰૢ࡞Մೳ σʔλૢ࡞͕౷Ұ͞ΕͯΔ෩ͳͷ͚͕ͩͰ͖ͨ
େ͖ͳצҧ͍ %%%ઃܭͱ͍͏ͷΛΕͣʹ
ΤϯδχΞ૿͑ͨ ਓਓ ˞ϝΠϯ࣮ऀͷ͕Ͳ͔ͬʹ͍·͢ !BJJSP
ࠓ࣮ͦ͜ફ w Կ͔Β࢝ΊͨΒ͍͍ʁ w όϦϡʔΦϒδΣΫτ͔Β࢝ΊͨΒΓ͍͢ͱຢฉ͖ !BJJSP
όϦϡʔΦϒδΣΫτͱʁ w ϓϦϛςΟϒܕͰදݱ͍ͯͨ͠ΛΦϒδΣΫτʹ͢Δ w ࣗͷՃɾఆͳͲͷৼΔ͍Λ࣋ͭ w ΠϛϡʔλϒϧͰ͋Δ
$POUSPMMFS 4FSWJDF 3FQPTJUPSZ &MPRVFOU3FQPTJUPSZ .PEFM ෦తʹ7BMVF0CKFDUʹม υϝΠϯʁ 7BMVF0CKFDU
ͱ͋ΔαʔϏεͷྫ Ϣʔεέʔε w ϝʔΧʔΞΧϯτΛొ͢Δ w ొ͞Ε͍ͯΔϝʔϧ͕ϒϥοΫϦετͷ߹YYY͢Δ Ϟσϧ &NBJMΛ7BMVF0CKFDUʹͯ͠ΈΔ
class Email implements \JsonSerializable { protected $value; protected function __construct(string
$value) { $this->value = $value; } public function value(): string { return $this->value; } public function isBlackList(): boolean { return ($this->value === $blacklist) } public function jsonSerialize() { return $this->value; } } 7BMVF0CKFDU ৼΔ͍Λ࣋ͨͤΔ
class MakerAccount extends Model { protected $table = 'maker_accounts'; protected
$hidden = [ 'id', ]; public function toValueObject() { // Πϛϡʔλϒϧʹ͢ΔͨΊɺreplicate()ͨ݁͠ՌΛฦ٫ $replication = $this->replicate(); $replication->email = new Email($this->email); return $replication; } } .PEFM ରͷ7BMVF0CKFDUΛ٧ΊࠐΉ
class MakerAccountRegisterService { protected $maker_account_repo; public function __construct(MakerAccountRepository $maker_account_repo) {
$this->maker_account_repo = $maker_account_repo; } public function activateEmail($email) { $maker_account = $this->maker_account_repo->findByEmail($email); $maker_account = $maker_account->toValueObject(); return $maker_account->email->isBlackList(); } } 4FSWJDF 7BMVF0CKFDUͷৼΔ͍Λར༻
ײ w 7BMVF0CKFDUͷΈͩͱखܰʹ࢝ΊΒΕΔ w ৼΔ͍Λू͢Δ͜ͱͰΘ͔Γ͘͢ͳͬͨ গͣͭ͠%%%ͷԸܙ͕ड͚ΒΕ͖ͯͨɾɾʁ
৽نαʔϏεͷ։ൃ
ϑϧͰ%%%ͷ࣮ફ νϟϯεʂ IUUQTHJUIVCDPNTIJOYMBSBWFMEEETBNQMF ৽ݪ͞ΜͷΊͪΌͪ͘Όࢀߟʹͯ͠·͢
ΤϯςΟςΟͱ w ҰҙʹࣝผՄೳͳΦϒδΣΫτ w ෳͷΦϒδΣΫτৼΔ͍Λ͍࣋ͬͯΔ w ৼΔ͍͕গͳ͍߹ݕ౼͖͢
$POUSPMMFS 6TF$BTF 3FQPTJUPSZ &MPRVFOU3FQPTJUPSZ .PEFM υϝΠϯ &OUJUZΛฦ͢ 7BMVF0CKFDU &OUJUZ
ͱ͋ΔαʔϏεͷྫ Ϣʔεέʔε w ը໘͔ΒϝʔΧʔ͕ ࣗͷ ΞΧϯτҰཡӾཡ͢Δ w ϝʔΧʔͷΞΧϯτͷҰཡΛϖʔδωʔγϣϯͰฦ͢ Ϟσϧ ϞσϧΛ&OUJUZʹͯ͠ΈΔ
class MakerAccount implements \Arrayable { /** @var MakerId */ protected
$maker_id; protected $name; protected $tel; protected $email; protected $password; public function __construct(MakerId $maker_id,…লུ) { $this->maker_id = $maker_id; $this->email = $email; if ($password) { $this->password = MakerAccountPassword::of(\Hash::make($password->value())); } } public function toArray() { $array = []; $class_vars = array_keys(get_class_vars(static::class)); foreach ($class_vars as $var_name) { $array[$var_name] = $this->{$var_name}; } return $array; } } &OUJUZ ֤7BMVF0CKFDUΛ٧ΊࠐΉ
class MakerAccount extends Model implements Domainable { public function maker()
{ return $this->belongsTo(Maker::class); } /** * @return \App\Domains\Entities\MakerAccount */ public function toDomain() { return new Entities\MakerAccount( MakerId::of($this->maker_id), MakerAccountName::of($this->name), MakerAccountTel::of($this->tel), MakerAccountEmail::of($this->email) ); } } .PEFM &OUJUZʹม
class DomainServiceProvider extends ServiceProvider { … protected function collectionMacro() {
Builder::macro('toDomainCollection', function () { /** @noinspection PhpUndefinedMethodInspection */ return $this->get()->map(function (Domainable $model) { return $model->toDomain(); }); }); Collection::macro('toDomainCollection', function () { /** @noinspection PhpUndefinedMethodInspection */ return $this->map(function (Domainable $model) { return $model->toDomain(); }); }); } protected function paginateMacro() { … } } $PMMFDUJPO #VJMEFS͔Β%PNBJOͷྻΛฦ͢.BDSPΛՃ
class FetchMakerAccountList { protected $maker_account_repo; public function __construct(MakerAccountRepository $maker_account_repo) {
$this->maker_account_repo = $maker_account_repo; } protected function common(MakerAccountId $maker_account_id) { return $this->maker_account_repo->findByMakerIdAsModel($maker_id); } public function asCollection(MakerId $maker_id) { return $this->common($maker_id)->toDomainCollection(); } public function asPaginate(MakerId $maker_id) { return $this->common($maker_id)->domainPaginate(); } } 6TF$BTF ೋͭͷৼΔ͍Λ࣋ͨͤͯͨ
class MakerAccountController extends Controller { public function index(FetchMakerAccountList $usecase) {
$maker_accounts = $usecase->asPaginate(MakerId::of(auth()->maker->id())); return response()->json($maker_accounts); } } $POUSPMMFS ར༻
6TF$BTFʹෳͷৼΔ͍ͨͤͯ͠·͍ͬͯΔ 6TF$BTFͷमਖ਼
;Ή;Ή 6TF$BTFͷमਖ਼
class FetchMakerAccountPaginate { protected $maker_account_repo; public function __construct(MakerAccountRepository $maker_account_repo) {
$this->maker_account_repo = $maker_account_repo; } public function __invoke(MakerAccountId $maker_account_id) { return $this->maker_account_repo ->findByMakerIdAsModel($maker_id) ->domainPaginate(); } } 6TF$BTFʢमਖ਼ޙʣ ҰͭͷৼΔ͍ͷΈʹ੍ݶ
class MakerAccountController extends Controller { public function index(FetchMakerAccountList $usecase) {
$maker_accounts = $usecase(MakerId::of(auth()->maker->id())); return response()->json($maker_accounts); } } $POUSPMMFS ར༻
ࠓ͓ͨ͜͠ͱ -BSBWFMͰ%%%Λ࣮ફ͢Δ·Ͱͷաఔ %%%Λ࣮ફ͢Δ͜ͱͰԿ͕มΘͬͨʁ ҰͰແཧͰɺগͣͭ͠ͳΒ࣮ફͰ͖Δ ༷ͷѲ͕͘͢͠ͳͬͨ ϏδωεαΠυͱͷೝ͕ࣝͱΓ͘͢ͳͬͨ ઃܭ ࣮ ྑ͍ϧʔϓ
͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
ฉ͖͍ͨ͜ͱ w &OUJUZ͕&OUJUZΛ࣋ͭ߹ͷύϑΥʔϚϯεͷ w όϦσʔγϣϯͲ͜Ͱ࣋ͨͤΔ͖͔ w ࣮ࡍͬͯΈͯɺԿ͕ྑ͔ͬͨͷ͔