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
Evoluindo sua aplicação - Arquitetura Hexagonal
Search
Hugo Henrique
October 10, 2017
Programming
0
290
Evoluindo sua aplicação - Arquitetura Hexagonal
Apresentado no dia 08/10/2017 no PHPeste em Fortaleza-CE
Hugo Henrique
October 10, 2017
Tweet
Share
More Decks by Hugo Henrique
See All by Hugo Henrique
CommandBus
hugohenrique
0
60
Background Jobs - Ao infinito e além
hugohenrique
1
190
Other Decks in Programming
See All in Programming
コード生成なしでモック処理を実現!ovechkin-dm/mockioで学ぶメタプログラミング
qualiarts
0
200
20251016_Rails News ~Rails 8.1の足音を聴く~
morimorihoge
2
620
When Dependencies Fail: Building Antifragile Applications in a Fragile World
selcukusta
0
110
Swift Concurrency - 状態監視の罠
objectiveaudio
2
550
contribution to astral-sh/uv
shunsock
0
230
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
450
Devoxx BE 2025 Loom lab
josepaumard
0
110
Claude CodeによるAI駆動開発の実践 〜そこから見えてきたこれからのプログラミング〜
iriikeita
0
310
Software Architecture
hschwentner
6
2.3k
Catch Up: Go Style Guide Update
andpad
0
240
スマホから Youtube Shortsを見られないようにする
lemolatoon
27
33k
kiroとCodexで最高のSpec駆動開発を!!数時間で web3ネイティブなミニゲームを作ってみたよ!
mashharuki
0
770
Featured
See All Featured
Rebuilding a faster, lazier Slack
samanthasiow
84
9.2k
Automating Front-end Workflow
addyosmani
1371
200k
Done Done
chrislema
185
16k
Into the Great Unknown - MozCon
thekraken
40
2.1k
Typedesign – Prime Four
hannesfritz
42
2.8k
Designing Experiences People Love
moore
142
24k
How to Ace a Technical Interview
jacobian
280
24k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.7k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.5k
Building Adaptive Systems
keathley
44
2.8k
Why Our Code Smells
bkeepers
PRO
340
57k
Statistics for Hackers
jakevdp
799
220k
Transcript
&70-6*/%046""1-*$"ª§0 "326*5&563")&9"(0/"- !IVHPIFOSJRVF
)6(0)&/3*26& !IVHPIFOSJRVF
"4"1-*$"ª¸&4/03."-.&/5& $0.&ª".&..6/%01&3'&*50
None
$&/¥3*0$0.6.%"$3*"ª§0%&6.40'58"3& 4&(6/%00.6/%0%"445"35614
.7$
None
4$3*15.6*50$0.6.1"3"*/*$*"36.130+&50 %&40'58"3&/0$&/¥3*045"3561 &4$0-)&36.'3".&803, */45"-"36.130+&50&426&-&50 3&.07&3$0*4"4%&%&.0/453"ª§0 $3*"3&/5*%"%&4
"650(&/&3"5& $3*"3$36%$0/530--&3`4 "650(&/&3"5&
1 <?php 2 namespace App\Http; 3 4 use MyLovedFramework\Controller; 5
use MyLovedFramework\Request; 6 7 class BookController extends Controller 8 { 9 // ... 10 public function purchaseAction(Request $request) 11 { 12 if ($bookId = $request->query->get('bookId')) { 13 throw new \InvalidArgumentException(sprintf('The book %s cannot be found', $bookId)); 14 } 15 16 try { 17 $this->entityManager->beginTransaction(); 18 19 $book = $this->bookRepository->find($bookId); 20 21 $buyer = $this->currentSession()->user(); 22 $buyer->purchase($book); 23 24 $this->userRepository->persist($buyer); 25 26 $this->logger->log('info', sprintf('The book %s was purchased by user %s', $bookId, $buyer->getId())); 27 28 $this->mailer->send( 29 $buyer->getEmailAddress(), 30 'Your purchase is being processed', 31 'template_purchase.html' 32 ); 33 34 $this->entityManager->commit(); 35 36 return new Response(200, 'You purchase has been processed!'); 37 } catch (\Exception $e) { 38 $this->entityManager->rollback(); 39 $this->logger->log('error', $e->getMessage()); 40 return new Response(500, 'Problem to processing request'); 41 } 42 } 43 }
$0.1-&9*%"%& "-50"$01-".&/50 .*4563"%&$0/$&*504 %*'°$*-."/65&/*#*-*%"%&
$0/530--&3%3*7&/%&4*(/
5&45&4$0.1-&904&-&/504 10326&04'3".&803,4+¥/§03&40-7&&44&130#-&."
'3".&803,4 &/$"146-".&/50
<?php $content = file_get_contents('php://input'); $contentType = $_SERVER['CONTENT_TYPE']; if ($contentType ===
'application/json') { $data = json_decode($content, true); } else if ($contentType === 'application/xml') { $data = simplexml_load_string($requestContent); } // ... -08-&7&-"1*
<?php $data = $serializer->deserialize( $request->getContent(), $request->getContentType() ); &4$0/%&%&5"-)&4 &7*5"%61-*$*%"%&
-08-&7&-"1* $stmt = $db->prepare('SELECT * FROM Customer c WHERE c.age
>= ?'); $stmt->bindValue(1, 18); $stmt->execute(); $raw = $stmt->fetch(PDO::FETCH_ASSOC); $customer = Customer::fromArray($raw);
&4$0/%&04%&5"-)&4%&*.1-&.&/5"ª§0 $customer = $repository->createQueryBuilder('c') ->where('c.age >= :age') ->setParameter('age', 18) ->getQuery()
->getResult();
&4$0/%&04%&5"-)&4%&*.1-&.&/5"ª§0 $customers = $repository->olderAge();
0'0$0%&7&4&3/"4'6/$*0/"-*%"%&4 $03@*/&44%0."*/
&4$0-)&36.'3".&803, */45"-"36.130+&50&426&-&50 3&.07&3$0*4"4%&%&.0/453"ª§0 $3*"3&/5*%"%&4 "650(&/&3"5&
$3*"3$36%$0/530--&3`4 "650(&/&3"5&
1 <?php 2 namespace App\Http; 3 4 use MyLovedFramework\Controller; 5
use MyLovedFramework\Request; 6 7 class BookController extends Controller 8 { 9 // ... 10 public function purchaseAction(Request $request) 11 { 12 if ($bookId = $request->query->get('bookId')) { 13 throw new \InvalidArgumentException(sprintf('The book %s cannot be found', $bookId)); 14 } 15 16 try { 17 $this->entityManager->beginTransaction(); 18 19 $book = $this->bookRepository->find($bookId); 20 21 $buyer = $this->currentSession()->user(); 22 $buyer->purchase($book); 23 24 $this->userRepository->persist($buyer); 25 26 $this->logger->log('info', sprintf('The book %s was purchased by user %s', $bookId, $buyer->getId())); 27 28 $this->mailer->send( 29 $buyer->getEmailAddress(), 30 'Your purchase is being processed', 31 'template_purchase.html' 32 ); 33 34 $this->entityManager->commit(); 35 36 return new Response(200, 'You purchase has been processed!'); 37 } catch (\Exception $e) { 38 $this->entityManager->rollback(); 39 $this->logger->log('error', $e->getMessage()); 40 return new Response(500, 'Problem to processing request'); 41 } 42 } 43 }
1 <?php 2 namespace App\Http; 3 4 use MyLovedFramework\Controller; 5
use MyLovedFramework\Request; 6 7 class BookController extends Controller 8 { 9 // ... 10 public function purchaseAction(Request $request) 11 { 12 if ($bookId = $request->query->get('bookId')) { 13 throw new \InvalidArgumentException(sprintf('The book %s cannot be found', $bookId)); 14 } 15 16 try { 17 $this->entityManager->beginTransaction(); 18 19 $book = $this->bookRepository->find($bookId); 20 21 $buyer = $this->currentSession()->user(); 22 $buyer->purchase($book); 23 24 $this->userRepository->persist($buyer); 25 26 $this->logger->log('info', sprintf('The book %s was purchased by user %s', $bookId, $buyer->getId())); 27 28 $this->mailer->send( 29 $buyer->getEmailAddress(), 30 'Your purchase is being processed', 31 'template_purchase.html' 32 ); 33 34 $this->entityManager->commit(); 35 36 return new Response(200, 'You purchase has been processed!'); 37 } catch (\Exception $e) { 38 $this->entityManager->rollback(); 39 $this->logger->log('error', $e->getMessage()); 40 return new Response(500, 'Problem to processing request'); 41 } 42 } 43 } $¶%*(0$0.#"*9"$0&4§0&6. "-50"$01-".&/50"0'3".&803,
3&64"#*-*%"%&%&$¶%*(0¬*.1044°7&- 8&# 'VODJPOBMJEBEF $PNQSBSVN-JWSP $-* $PNNBOE-JOF
1 <?php 2 namespace App\Http; 3 4 use MyLovedFramework\Controller; 5
use MyLovedFramework\Request; 6 7 class BookController extends Controller 8 { 9 // ... 10 public function purchaseAction(Request $request) 11 { 12 if ($bookId = $request->query->get('bookId')) { 13 throw new \InvalidArgumentException(sprintf('The book %s cannot be found', $bookId)); 14 } 15 16 try { 17 $this->entityManager->beginTransaction(); 18 19 $book = $this->bookRepository->find($bookId); 20 21 $buyer = $this->currentSession()->user(); 22 $buyer->purchase($book); 23 24 $this->userRepository->persist($buyer); 25 26 $this->logger->log('info', sprintf('The book %s was purchased by user %s', $bookId, $buyer->getId())); 27 28 $this->mailer->send( 29 $buyer->getEmailAddress(), 30 'Your purchase is being processed', 31 'template_purchase.html' 32 ); 33 34 $this->entityManager->commit(); 35 36 return new Response(200, 'You purchase has been processed!'); 37 } catch (\Exception $e) { 38 $this->entityManager->rollback(); 39 $this->logger->log('error', $e->getMessage()); 40 return new Response(500, 'Problem to processing request'); 41 } 42 } #"*9"$0&4§0
4:.'0/: %0$53*/& 3&"$5+4 3"##*5.2 "11-*$"5*0/
&44&/$*"- %&5"-)&4 %&5"-)&4
5)&)&"350'40'58"3&*4*54"#*-*5:5040-7& %0."*/3&-"5&%130#-&.4'03*5464&3z &3*$&7"/4 %0."*/%3*7&/%&4*(/
"11 */'3"4536$563& 8&##3084&3 %"5"#"4& 5&3.*/"- '*-&4:45&. 06530 06530
$"."%"4
$0.6/*$"ª§0 A
.&/4"(&. .6/%0&95&3/0 "11 8&#)5551 305"4 .&/4"(&. "1*3&45'6- .&/4"(&. $-*
.&/4"(&. 8&#)5551 305"4 .&/4"(&. "1*3&45'6- .&/4"(&. $-*
Http Request Controller Form Repository Entity Value Object
l10354"/%"%"15&34z "326*5&563")&9"(0/"-
$0.."/%#64 $0.."/% )"/%-&3
."4"'*/"-026&¬6.$0.."/%
5*104%&.&/4"(&/4 *.1&3"5*7"4 $0.."/% */5&330("5*7" 26&3: */'03."5*7" &7&/5
5*104%&.&/4"(&/4 *.1&3"5*7"4 $0.."/% */5&330("5*7" 26&3: */'03."5*7" &7&/5
6.$0."/%0¬6."4*.1-&4.&/4"(&.*.1&3"5*7" 26&0#3*("503*".&/5&%&7&4&34*.1-&4
6.$0."/%0%&7&*/%*$"30$0.1035".&/5026& 6.646¥3*006$-*&/5&&41&3"%0"1-*$"5*70
3FHJTUFS6TFS 1VSDIBTF#PPL 4UBSU%JTDVTTJPO 4JHO6Q
%&7&$0/5&340.&/5&"4*/'03."ª¸&4 1"3"3&"-*;"346"5"3&'" <?php final class PurchaseBook { private $bookId; private
$readerId; public function __construct(BookId $bookId, ReaderId $readerId) { $this->bookId = $bookId; $this->readerId = $readerId; } }
*.65¥7&- <?php final class PurchaseBook { private $bookId; private $readerId;
public function __construct(BookId $bookId, ReaderId $readerId) { $this->bookId = $bookId; $this->readerId = $readerId; } public function bookId() : BookId { return $this->bookId; } public function readerId() : ReaderId { return $this->readerId; } }
4&3"6507"-*%"%" <?php final class PurchaseBook { private $bookId; private $readerId;
public function __construct(BookId $bookId, ReaderId $readerId) { Assertion::notNull($bookId); Assertion::notNull($readerId); $this->bookId = $bookId; $this->readerId = $readerId; } public function bookId() : BookId { return $this->bookId; } public function readerId() : ReaderId { return $this->readerId; } }
$0.."/%*44*.1-&"%50 %"5"53"/4'&30#+&$5 1 <?php 2 namespace App\Domain\Member; 3 4 class
RegisterMember 5 { 6 private $emailAddress; 7 private $password; 8 9 public function __construct(string $emailAddress, string $password) 10 { 11 $this->emailAddress = $emailAddress; 12 $this->password = $password; 13 } 14 15 public function emailAddress() : string 16 { 17 return $this->emailAddress; 18 } 19 20 public function password() : string 21 { 22 return $this->password; 23 } 24 }
$0.0*/5&313&5"304$0."/%04 $0.."/%)"/%-&3
<?php namespace App\Handler; class PuchaseBookHandler { public function __invoke(PurchaseCommand $command)
: void { try { $this->entityManager->beginTransaction(); $buyer = $this->userRepository->find($command->buyerId()); $book = $this->bookRepository->find($command->bookId()); $buyer->purchase($book); $this->userRepository->persist($buyer); $this->entityManager->commit(); $this->mailer->send( $buyer->getEmailAddress(), 'Your purchase is being processed', 'template_purchase.html' ); // Logs the purchase } catch (\Exception $e) { $this->entityManager->rollback(); // Logs when error is raised } } }
6.$0.."/%4¶10%&4&3"440$*"%0"6.)"/%-&3 6.)"/%-&34¶10%&4&3"440$*"%0"6.$0.."/%
6.)"/%-&3/§0%&7&3&503/"37"-03 4)06-%#&70*%
26"*4"43&"*47"/5"(&/4%&64"3&44""#03%"(&. 10%&4&3&9&$65"%0&.26"-26&31"35&%"46""1-*$"ª§0 8&#$-* /§05&3¥."*4$¶%*(03&1&5*%0 4&6$0/530--&3/§05&3¥3&(3"%&/&(¶$*0 ."*03'"$*-*%"%&1"3"5&45"3
<?php namespace Infrastructure\Command; class RegisterMemberConsoleCommand extends ConsoleCommand { public function
execute(Input $input) { $command = new RegisterMember( $input->getArgument('emailAddress'), $input->getArgument('password') ); $this->commandBus()->handle($command); } }
Http Request Controller Form INFRASTRUCTURE APPLICATION DOMAIN PurchaseCommand PurchaseHandler Entity
Repository
<?php namespace App\Http; use MyLovedFramework\Controller; use MyLovedFramework\Request; class BookController extends
Controller { // ... public function purchaseAction(Request $request) { $userId = $this->session->currentUser()->id(); $bookId = $request->get('bookId'); $command = new PurchaseBook($bookId, $userId); $this->commandBus->handle($command); // ... } }
¼/*$010/50%&&/53"%"1"3"46""1-*$"ª§0 4*/(-&10*/50''"*-63& 410'
"(03"70-5"/%01"3"0)"/%-&3 7".04"/"-*4"3$0.."*4$"65&-"
."4"/5&47".040-)"31"3"6."4*.1-&4 *.1-&.&/5"ª§0%&6.$0.."/%#64
<?php interface CommandBus { public function handle($command) : void; }
<?php class SimpleCommandBus implements CommandBus { private $handlerMap; public function
__construct($handlerMap = []) { $this->handlerMap = $handlerMap; } public function handle($command) : void { // .. $this->handlerMap(get_class($command))->handle($command); // .. } }
$handler = new PurchaseBookHandler(); $handlerMap = [ 'PurchaseCommand' => $handler
]; $command = new PurchaseCommand(); $commandBus = new SimpleCommandBus($handlerMap); $commandBus->handle($command);
<?php namespace App\Book\Application; use App\Book\Domain\PurchaseCommand; class PurchaseBookHandler { public function
__invoke(PurchaseCommand $command) { try { $this->entityManager->beginTransaction(); $buyer = $this->userRepository->find($command->buyerId()); $book = $this->bookRepository->find($command->bookId()); $buyer->purchase($book); $this->userRepository->persist($buyer); $this->entityManager->commit(); $this->mailer->send( $buyer->getEmailAddress(), 'Your purchase is being processed', 'template_purchase.html' ); $this->logger->log('success', 'Your purchase is being processed'); // Logs the purchase } catch (\Exception $e) { $this->entityManager->rollback(); $this->logger->log('error', sprintf('Error to purchase book %s.', $command->bookId())); } } }
."*4&04*/(-&3&410/4*#*-*5:13*/$*1-& 431
.JEEMFXBSF .JEEMFXBSF .JEEMFXBSF $PNNBOE)BOEMFS 3FRVFTU 3FTQPOTF
<?php class AnExampleMiddleware implements Middleware { public function execute($command, callable
$next) { // .. // .. $next($command); } }
<?php namespace League\Tactician\Doctrine\ORM; use Doctrine\ORM\EntityManagerInterface; use League\Tactician\Middleware; class TransactionMiddleware implements
Middleware { public function execute($command, callable $next) { $this->entityManager->beginTransaction(); try { $returnValue = $next($command); $this->entityManager->flush(); $this->entityManager->commit(); } catch (Exception $e) { $this->rollbackTransaction(); throw $e; } catch (Throwable $e) { $this->rollbackTransaction(); throw $e; } return $returnValue; } } $"40%&640 53"/4"ª¸&4$0. %0$53*/&03.
<?php namespace App\Book\Application; use App\Book\Domain\PurchaseCommand; class PurchaseBookHandler { public function
__invoke(PurchaseCommand $command) { try { $buyer = $this->userRepository->find($command->buyerId()); $book = $this->bookRepository->find($command->bookId()); $buyer->purchase($book); $this->userRepository->persist($buyer); $this->mailer->send( $buyer->getEmailAddress(), 'Your purchase is being processed', 'template_purchase.html' ); $this->logger->log('success', 'Your purchase is being processed’); } catch (\Exception $e) { $this->logger->log('error', sprintf('Error to purchase book %s.', $command->bookId())); } } }
<?php namespace League\Tactician\Logger; // .. class LoggerMiddleware implements Middleware {
// ... public function execute($command, callable $next) { $this->formatter->logCommandReceived($this->logger, $command); try { $returnValue = $next($command); } catch (Exception $e) { $this->formatter->logCommandFailed($this->logger, $command, $e); throw $e; } $this->formatter->logCommandSucceeded($this->logger, $command, $returnValue); return $returnValue; } } $"40%&640 -0(4
"(03"10%&.04&9&$65"3 /07"4"ª¸&4"/5&4&%&10*4 %"&9&$6ª§0%&6.$0."/%0
<?php namespace App\Book\Application; use App\Book\Domain\PurchaseCommand; class PurchaseBookHandler { public function
__invoke(PurchaseCommand $command) { try { $buyer = $this->userRepository->find($command->buyerId()); $book = $this->bookRepository->find($command->bookId()); $buyer->purchase($book); $this->userRepository->persist($buyer); $this->mailer->send( $buyer->getEmailAddress(), 'Your purchase is being processed', 'template_purchase.html' ); } catch (\Exception $e) { } } }
$0.640%&.*%%-&8"3&"41044*#*-*%"%&44§0*/¼.&3"4 -0((&3 7"-*%"503 4&$63*5: 1&3'03."/$&.&53*$4 46"/&$&44*%"%&
IUUQTHJUIVCDPN4JNQMF#VT.FTTBHF#VT
IUUQTHJUIVCDPNUIFQIQMFBHVFUBDUJDJBO
7".040-)"30"/5&4&%&10*4
<?php namespace App\Book\Application; use App\Book\Domain\PurchaseCommand; class PurchaseBookHandler { public function
__invoke(PurchaseCommand $command) : void { $buyer = $this->userRepository->find($command->buyerId()); $book = $this->bookRepository->find($command->bookId()); $buyer->purchase($book); $this->userRepository->persist($buyer); $this->mailer->send( $buyer->getEmailAddress(), 'Your purchase is being processed', 'template_purchase.html' ); } } <?php namespace App\Http; use MyLovedFramework\Controller; use MyLovedFramework\Request; class BookController extends Controller { // ... public function purchaseAction(Request $request) { $userId = $this->session->currentUser()->id(); $bookId = $request->get('bookId'); $command = new PurchaseBook($bookId, $userId); $this->commandHandler->handle($command); // ... } }
None
/04*-7&3#6--&5 IUUQXXXJUVELQFPQMFIFTK#461BSUJLMFSOPTJMWFSCVMMJUQEG
IUUQDVMUUUDPNDSFBUJOHVTJOHDPNNBOECVT IUUQTQIQBOETZNGPOZNBUUIJBTOPCBDLOMBXBWFPGDPNNBOECVTFT IUUQTQIQBOETZNGPOZNBUUIJBTOPCBDLOMSFTQPOTJCJMJUJFTPGUIFDPNNBOECVT IUUQTIBXONDDPPMDPNNBOECVT IUUQTHOVHBUHJUIVCJPUPXBSETDRSTDPNNBOECVTIUNM 3FGFSÊODJBT
0#3*("%0