SlideShare uma empresa Scribd logo
1 de 37
Hexagonal
Architecture
Paulo Victor
Systems Analyst, Open
Source Developer, Zend
Certified Engineer PHP
5.3.
@pv_fusion
VOUCHER: php_conf2015
Presentation licensed by
This presentation is free to use under Creative Commons Attribution license. If you use the content
and graphic assets (photos, icons, typographies) provided with this presentation you must keep the
Credits slide.
Beginnings...
How?
◇ How can I separate Domain from Framework?
◇ How can I decouple the libraries?
◇ How can I make communication between layers?
◇ How can I make a semantic structure?
You need to think about
Software Architecture
Software Architecture
Why do we even talk about Architecture?
◇ High Maintainability
◇ Low Technical Debt
◇ Semantic structure (Layers are
responsible for doing what they
should do)
Software Architecture
The architecture of a software system is a
metaphor, analogous to the architecture of a
building.
Perry, D. E.; Wolf, A. L. (1992). "Foundations for the study of software
architecture".
1
#weareallhexagons
WhatWhy How
Architectural Styles
In order to be able to build complex applications,
one of the key aspects is having an architecture
design that fits the application needs.
Buenosvinos, C., Soronellas C. Akbary K. (2015) "Domain-Driven
Design in PHP"
2
#weareallhexagons
WhatWhy How
Hexagonal Architecture3
#weareallhexagons
WhatWhy How
Allow an application to equally be driven by users,
programs, automated test or batch scripts, and to
be developed and tested in isolation from its
eventual run-time devices and databases.
Cockburn, A. (2008). "Hexagonal architecture".
Domain
#weareallhexagons
Ports and Adapters
<?php namespace DomainCore;
interface MarketRepository extends RepositoryInterface
{
/**
* Find Market By KeyName
* @param $keyName
* @return Market
*/
public function byKeyName($keyName);
/**
* Find Market By KeyName and token
* @param $keyName
* @param $token
* @return Market
*/
public function byKeyNameAndToken($keyName, $token);
/**
* Create an Market
* @param Market $market
* @return Market
*/
public function add(Market $market);
}
<?php namespace AppBundleInfrastructureCore;
class MarketRepository extends PDORepository implements
DomainCoreMarketRepository
{
public function byKeyName($keyName)
{
$sql = "select * from market where key_name = $keyName";
return $this->map($this->getRepository()
->query($sql));
}
public function byKeyNameAndToken($keyName, $token)
{
$sql = <<<SQL
select * from market
where key_name = $keyName
and access_token = $token
SQL;
return $this->map($this->getRepository()
->query($sql));
}
...
}
PDO Adapter Port
<?php namespace DomainCore;
interface MarketRepository extends RepositoryInterface
{
/**
* Find Market By KeyName
* @param $keyName
* @return Market
*/
public function byKeyName($keyName);
/**
* Find Market By KeyName and token
* @param $keyName
* @param $token
* @return Market
*/
public function byKeyNameAndToken($keyName, $token);
/**
* Create an Market
* @param Market $market
* @return Market
*/
public function add(Market $market);
}
<?php namespace AppBundleInfrastructureCore;
class MarketRepository extends EntityRepository implements
DomainCoreMarketRepository
{
/**
* {@inheritdoc}
*/
public function byKeyName($keyName)
{
return $this->getRepository()
->findOneByKeyName($keyName);
}
public function byKeyNameAndToken($keyName, $token)
{
return $this->getRepository()
->findOneBy(['keyName' => $keyName, 'accessToken' => $token]);
}
public function add(DomainCoreMarket $market)
{
$this->getEntityManager()->persist($market);
$this->getEntityManager()->flush();
}
}
Doctrine Adapter Port
<?php namespace DomainCore;
interface MarketRepository extends RepositoryInterface
{
/**
* Find Market By KeyName
* @param $keyName
* @return Market
*/
public function byKeyName($keyName);
/**
* Find Market By KeyName and token
* @param $keyName
* @param $token
* @return Market
*/
public function byKeyNameAndToken($keyName,
$token);
/**
* Create an Market
* @param Market $market
* @return Market
*/
public function add(Market $market);
}
<?php namespace AppBundleInfrastructureCore;
class MarketRepository extends SolrRepository implements
DomainCoreMarketRepository
{
public function byKeyName($keyName)
{
$marketId = $this->elasticSearchRepository()->search('mkt', [$keyName]);
$market = new Market();
$market->setId($marketId);
$market->setName($this->redisRepository()->get('mkt':'.$keyName.':name'));
$market->setKeyName($this->redisRepository()->get('mkt':'.$keyName.':keyname'));
$market->setAccessToken($this->redisRepository()->get('mkt':'.$keyName.':token'));
return $market;
}
public function byKeyNameAndToken($keyName, $token)
{
$marketId = $this->elasticSearchRepository()->search('mkt', [$keyName, $token]);
$market = new Market();
$market->setId($marketId);
$market->setName($this->redisRepository()->get('mkt':'.$keyName.':name'));
$market->setKeyName($this->redisRepository()->get('mkt':'.$keyName.':keyname'));
$market->setAccessToken($this->redisRepository()->get('mkt':'.$keyName.':token'));
return $market;
}
}
Redis and Solr Adapter Port
“
Domain Driven Design (DDD)
Do you know DDD ?
DDD is about placing our attention at the
heart of the application, focusing on the
complexity that is intrinsic to the business
domain itself.
The reason to an
Application
Troubleshoot space and time
problems
What is the best
way to do this?
Encapsulating the business
rules with layers
Work with layers
“Hexagonal Architecture defines
conceptual layers of code
responsibility, and then points
out ways to decouple code
between those layers. It's helped
clarify when, how and why we
use interfaces (among other
ideas)”
Fideloper
Coupling between layers
User Interface
Application
Domain
Infrastructure
Coupling between layers
User Interface
Application
Domain
Infrastructure
Dependency Inversion Principle
Decoupling between layers
Core
Domain
Domain
Application
Infrastructure
S
Q
L
Dependencies
Core
Domain
Domain
Application
Infrastructure
S
Q
L
Boundaries
Core
Domain
Domain
Application
Infrastructure
S
Q
L
Communication Between
Layers: Boundaries
Use Case Bus Handle
CommandBus
Command
Handler
Command
executes( )
handles( )
Fideloper. Hexagonal Architecture
CommandBus
Use Case
Use Case
<?php namespace HexCommandBus;
interface CommandInterface {}
<?php namespace HexTicketsCommands;
use HexCommandBusCommandInterface;
class CreateTicketCommand implements CommandInterface {
/**
* @var array
*/
public $data;
public function __construct(Array $data)
{
$this->data = $data;
}
public function __get($property)
{
if( isset($this->data[$property]) )
{
return $this->data[$property];
}
return null;
}
}
https://github.com/fideloper/hexagonal-php
https://github.com/fideloper/hexagonal-php
interface CommandBusInterface {
public function execute(CommandInterface $command);
}
class CommandBus implements CommandBusInterface {
private $container;
private $inflector;
public function __construct(Container $container, CommandNameInflector
$inflector)
{
$this->container = $container;
$this->inflector = $inflector;
}
public function execute(CommandInterface $command)
{
return $this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
return $this->container->make( $this->inflector->getHandler($command) );
}
}
<?php namespace HexTicketsHandlers;
class CreateTicketHandler implements HandlerInterface {
private $validator;
private $repository;
private $dispatcher;
public function __construct(CreateTicketValidator $validator, TicketRepositoryInterface $repository, Dispatcher $dispatcher)
{
// set attributes
}
public function handle(CommandInterface $command)
{
$this->validator->validate($command);
$this->save($command);
}
protected function save($command)
{
$message = new Message;
$message->message = $command->message;
$ticket = new Ticket;
$ticket->subject = $command->subject;
$ticket->name = $command->name;
$ticket->email = $command->email;
$ticket->setCategory( Category::find($command->category_id) ); // Need repo
$ticket->setStaffer( Staffer::find($command->staffer_id) ); // Need repo
$ticket->addMessage( $message );
$this->repository->save($ticket);
$this->dispatcher->dispatch( $ticket->flushEvents() );
}
}
https://github.com/fideloper/hexagonal-php
Structure
Core
Domain
Domain
Application
Infrastructure
S
Q
L
Biso
Symfony 2
FriendsOfSym
fony
{
"name": "Symfony2Biso",
"type": "project",
"require": {
"php": ">=5.3.9",
"friendsofsymfony/rest-bundle": "1.7.*",
"predis/predis": "1.0.*",
"biso": "dev-master"
},
"repositories": [
{
"type": "package",
"package": {
"name": "biso",
"version": "dev-master",
"source": {
"url": "https://github.com/pvgomes/biso",
"type": "git",
"reference": "origin/master"
},
"autoload": {
"psr-0": { "Domain": "src" }
}
}
}
],
}
<?php
namespace Domain;
interface Command {
public function repositories();
public function eventName();
public function eventNameError();
}
<?php namespace AppBundleApplicationCore;
use AppBundleInfrastructureCoreConfiguration;
use Domain;
class CreateConfigurationCommand implements DomainCommand
{
public $data;
private $configuration;
private $eventName;
public function __construct($marketKey, $key, $value)
{
$this->eventName = DomainCoreEvents::MARKET_CREATE_CONFIGURATION;
$this->configuration = new Configuration();
$this->data = ['marketKey' => $marketKey, 'key' => $key, 'value' => $value];
}
public function __get($property)
{
$value = null;
if( isset($this->data[$property]) ) {
$value = $this->data[$property];
}
return $value;
}
...
Create Configuration Command
<?php
namespace Domain;
interface CommandBus {
public function execute(Command $command);
}
<?php namespace AppBundleApplicationCommandBus;
class CommandBus implements DomainCommandBus
{
private $container;
private $eventDispatcher;
private $inflector;
private $applicationEvent;
public function __construct(ContainerInterface $container, CommandNameInflector $inflector)
{
$this->container = $container;
$this->inflector = $inflector;
$this->eventDispatcher = $container->get('event_dispatcher');
$this->applicationEvent = new ApplicationEvent();
}
public function execute(DomainCommand $command)
{
try {
$this->applicationEvent->setCommand($command);
$response = $this->getHandler($command)->handle($command);
$this->eventDispatcher->dispatch($command->eventName(), $this->applicationEvent);
} catch (Exception $exception) {
$this->applicationEvent->setException($exception);
$this->eventDispatcher->dispatch($command->eventNameError(), $this-
>applicationEvent);
throw $exception;
}
return $response;
Command Bus
<?php
namespace Domain;
interface Handler {
public function handle(Command $command);
}
<?php namespace DomainCore;
class CreateConfigurationHandler implements Handler {
private $configurationRepository;
private $market;
public function __construct(Market $market)
{
$this->market = $market;
}
public function handle(Command $command)
{
return $this->save($command);
}
protected function save(Command $command)
{
$configuration = $command->configurationEntity();
if (!$configuration instanceof Configuration) {
throw new DomainException("Invalid configuration");
}
$configuration->setMarket($this->market);
$configuration->setKey($command->key);
$configuration->setValue($command->value);
$this->configurationRepository->add($configuration);
return $configuration->getId();
}
...
Command Handler
<?php namespace AppBundleApplicationControllerWeb;
class SystemController extends Controller {
/**
* @Route("/system/configuration", name="configuration_list")
* @param Request $request
* @return SymfonyComponentHttpFoundationResponse
*/
public function configurationAction(Request $request)
{
$form = $this->createFormBuilder([])->add('key', 'text')->add('value', 'textarea')->getForm();
if ($request->isMethod('POST')) {
$form->handleRequest($request);
$data = $form->getData();
try {
$createConfigurationCommand = new CreateConfigurationCommand($this->getUser()->getMarket()->getKeyName(), $data['key'], $data['value']);
$this->get("command_bus")->execute($createConfigurationCommand);
$flashMsg = "Chave gravada.";
$flashMsgType = "success";
} catch (DomainException $e) {
$flashMsg = $e->getMessage();
$flashMsgType = "warning";
} catch (Exception $e) {
$flashMsg = "Erro ao inserir a chave de configuração.";
$flashMsgType = "warning";
}
$this->addFlash($flashMsgType , $flashMsg);
}
$viewVars['form'] = $form->createView();
return $this->render('web/system/configuration.html.twig', $viewVars);
}
Create Config Usage | Browser
<?php namespace AppBundleApplicationApiv1Controller;
class SystemController extends ApiController implements TokenAuthentication {
use JsonValidator;
public function configurationCreate()
{
$request = $this->get('request');
$marketKey = $request->headers->get('key');
$requestContent = json_decode($$request->getContent());
$jsonResponse = new JsonResponse();
try {
if (!$this->isValidJson($this->loadConfigurationCreateSchema(), $requestContent)) {
throw new HttpException(400, $this->getJsonErrors());
}
$createConfigurationCommand = new CreateConfigurationCommand($marketKey, $requestContent->key, $requestContent->value);
$this->get("command_bus")>execute($createConfigurationCommand);
$jsonResponse->setStatusCode(204);
} catch (DomainException $exception) {
$contentError['description'] = $exception->getMessage();
$jsonResponse->setStatusCode(400);
$jsonResponse->setData($contentError);
} catch (Exception $exception) {
$contentError['description'] = $exception->getMessage();
$jsonResponse->setStatusCode(500);
$jsonResponse->setData($contentError);
}
return $jsonResponse;
}
...
Create Config Usage | API
/pvgomes/symfony2biso
Thanks!
Any questions?
You can find me at:
◇ @pv_fusion
◇ pv.gomes89@gmail.com
Credits
Special thanks to all the people who made and released
these awesome resources for free:
◇ Contents of this presentation Paulo Victor Gomes
◇ Presentation template by SlidesCarnival
◇ Photographs by Unsplash
References
❖ BROOKS, FREDERICK. The Design of Design: Essays from a Computer Scientist.
❖ BUENOSVINOS, CARLOS. SORONELLA, CHRISTIAN. AKBARY, KEYVAN. Domain Driven Design in PHP.
❖ COCKBURN, ALISTAIR. Hexagonal Architecture.
❖ VERNON, VAUGHN - Implementing Domain-Driven Design.
❖ EVANS, ERICK. Domain Driven Design: Tackling Complexity in the Heart of Software.

Mais conteúdo relacionado

Mais procurados

Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass SlidesNir Kaufman
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Hitesh-Java
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introductionRasheed Waraich
 
Spring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutesSpring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutesVMware Tanzu
 
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...Edureka!
 
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafSpring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafThymeleaf
 
Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API07.pallav
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean ArchitectureRoc Boronat
 
State management in react applications (Statecharts)
State management in react applications (Statecharts)State management in react applications (Statecharts)
State management in react applications (Statecharts)Tomáš Drenčák
 
Modern Java web applications with Spring Boot and Thymeleaf
Modern Java web applications with Spring Boot and ThymeleafModern Java web applications with Spring Boot and Thymeleaf
Modern Java web applications with Spring Boot and ThymeleafLAY Leangsros
 

Mais procurados (20)

Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans
 
Introduction to spring boot
Introduction to spring bootIntroduction to spring boot
Introduction to spring boot
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Rest web services
Rest web servicesRest web services
Rest web services
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Spring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutesSpring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutes
 
From Zero to Docker
From Zero to DockerFrom Zero to Docker
From Zero to Docker
 
Spring Data JPA
Spring Data JPASpring Data JPA
Spring Data JPA
 
Reactjs
Reactjs Reactjs
Reactjs
 
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...
React Components Lifecycle | React Tutorial for Beginners | ReactJS Training ...
 
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafSpring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
 
React - Introdução
React - IntroduçãoReact - Introdução
React - Introdução
 
Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
 
Express js
Express jsExpress js
Express js
 
RESTful API - Best Practices
RESTful API - Best PracticesRESTful API - Best Practices
RESTful API - Best Practices
 
State management in react applications (Statecharts)
State management in react applications (Statecharts)State management in react applications (Statecharts)
State management in react applications (Statecharts)
 
Spring boot jpa
Spring boot jpaSpring boot jpa
Spring boot jpa
 
Modern Java web applications with Spring Boot and Thymeleaf
Modern Java web applications with Spring Boot and ThymeleafModern Java web applications with Spring Boot and Thymeleaf
Modern Java web applications with Spring Boot and Thymeleaf
 

Semelhante a Hexagonal architecture in PHP

Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's CodeWildan Maulana
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
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 Symfony2Hugo Hamon
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)James Titcumb
 
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition! Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition! Michel Schudel
 
The Best Way to Become an Android Developer Expert with Android Jetpack
The Best Way to Become an Android Developer Expert  with Android JetpackThe Best Way to Become an Android Developer Expert  with Android Jetpack
The Best Way to Become an Android Developer Expert with Android JetpackAhmad Arif Faizin
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmersAlexander Varwijk
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web ArtisansRaf Kewl
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 3camp
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationAlexander Obukhov
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 
Building Large Scale PHP Web Applications with Laravel 4
Building Large Scale PHP Web Applications with Laravel 4Building Large Scale PHP Web Applications with Laravel 4
Building Large Scale PHP Web Applications with Laravel 4Darwin Biler
 
Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010Satish Verma
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to DomainJeremy Cook
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)James Titcumb
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)Jose Manuel Pereira Garcia
 

Semelhante a Hexagonal architecture in PHP (20)

Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
 
Best practices tekx
Best practices tekxBest practices tekx
Best practices tekx
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
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
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
 
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition! Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
Battle Of The Microservice Frameworks: Micronaut versus Quarkus edition!
 
The Best Way to Become an Android Developer Expert with Android Jetpack
The Best Way to Become an Android Developer Expert  with Android JetpackThe Best Way to Become an Android Developer Expert  with Android Jetpack
The Best Way to Become an Android Developer Expert with Android Jetpack
 
Gwt.create
Gwt.createGwt.create
Gwt.create
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmers
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web Artisans
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generation
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Building Large Scale PHP Web Applications with Laravel 4
Building Large Scale PHP Web Applications with Laravel 4Building Large Scale PHP Web Applications with Laravel 4
Building Large Scale PHP Web Applications with Laravel 4
 
Vertx daitan
Vertx daitanVertx daitan
Vertx daitan
 
Vertx SouJava
Vertx SouJavaVertx SouJava
Vertx SouJava
 
Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 

Mais de Paulo Victor Gomes

Mais de Paulo Victor Gomes (9)

Functional as a service TDC 2020
Functional as a service TDC 2020Functional as a service TDC 2020
Functional as a service TDC 2020
 
PHP as a Service TDC2019
PHP as a Service TDC2019PHP as a Service TDC2019
PHP as a Service TDC2019
 
PHP as a Service
PHP as a ServicePHP as a Service
PHP as a Service
 
Stacks Cloud - Digital Ocean
Stacks Cloud - Digital OceanStacks Cloud - Digital Ocean
Stacks Cloud - Digital Ocean
 
O mundo do e commerce visto pela ótica do PHP
O mundo do e commerce visto pela ótica do PHPO mundo do e commerce visto pela ótica do PHP
O mundo do e commerce visto pela ótica do PHP
 
Essay about event driven architecture
Essay about event driven architectureEssay about event driven architecture
Essay about event driven architecture
 
DDD in PHP
DDD in PHPDDD in PHP
DDD in PHP
 
PHP e Redis
PHP e RedisPHP e Redis
PHP e Redis
 
Domain Driven Design PHP TDC2014
Domain Driven Design PHP TDC2014Domain Driven Design PHP TDC2014
Domain Driven Design PHP TDC2014
 

Último

Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 

Último (20)

Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 

Hexagonal architecture in PHP

  • 1. Hexagonal Architecture Paulo Victor Systems Analyst, Open Source Developer, Zend Certified Engineer PHP 5.3. @pv_fusion
  • 3. Presentation licensed by This presentation is free to use under Creative Commons Attribution license. If you use the content and graphic assets (photos, icons, typographies) provided with this presentation you must keep the Credits slide.
  • 5. How? ◇ How can I separate Domain from Framework? ◇ How can I decouple the libraries? ◇ How can I make communication between layers? ◇ How can I make a semantic structure? You need to think about Software Architecture
  • 6. Software Architecture Why do we even talk about Architecture? ◇ High Maintainability ◇ Low Technical Debt ◇ Semantic structure (Layers are responsible for doing what they should do)
  • 7. Software Architecture The architecture of a software system is a metaphor, analogous to the architecture of a building. Perry, D. E.; Wolf, A. L. (1992). "Foundations for the study of software architecture". 1 #weareallhexagons WhatWhy How
  • 8. Architectural Styles In order to be able to build complex applications, one of the key aspects is having an architecture design that fits the application needs. Buenosvinos, C., Soronellas C. Akbary K. (2015) "Domain-Driven Design in PHP" 2 #weareallhexagons WhatWhy How
  • 9. Hexagonal Architecture3 #weareallhexagons WhatWhy How Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases. Cockburn, A. (2008). "Hexagonal architecture".
  • 12. <?php namespace DomainCore; interface MarketRepository extends RepositoryInterface { /** * Find Market By KeyName * @param $keyName * @return Market */ public function byKeyName($keyName); /** * Find Market By KeyName and token * @param $keyName * @param $token * @return Market */ public function byKeyNameAndToken($keyName, $token); /** * Create an Market * @param Market $market * @return Market */ public function add(Market $market); } <?php namespace AppBundleInfrastructureCore; class MarketRepository extends PDORepository implements DomainCoreMarketRepository { public function byKeyName($keyName) { $sql = "select * from market where key_name = $keyName"; return $this->map($this->getRepository() ->query($sql)); } public function byKeyNameAndToken($keyName, $token) { $sql = <<<SQL select * from market where key_name = $keyName and access_token = $token SQL; return $this->map($this->getRepository() ->query($sql)); } ... } PDO Adapter Port
  • 13. <?php namespace DomainCore; interface MarketRepository extends RepositoryInterface { /** * Find Market By KeyName * @param $keyName * @return Market */ public function byKeyName($keyName); /** * Find Market By KeyName and token * @param $keyName * @param $token * @return Market */ public function byKeyNameAndToken($keyName, $token); /** * Create an Market * @param Market $market * @return Market */ public function add(Market $market); } <?php namespace AppBundleInfrastructureCore; class MarketRepository extends EntityRepository implements DomainCoreMarketRepository { /** * {@inheritdoc} */ public function byKeyName($keyName) { return $this->getRepository() ->findOneByKeyName($keyName); } public function byKeyNameAndToken($keyName, $token) { return $this->getRepository() ->findOneBy(['keyName' => $keyName, 'accessToken' => $token]); } public function add(DomainCoreMarket $market) { $this->getEntityManager()->persist($market); $this->getEntityManager()->flush(); } } Doctrine Adapter Port
  • 14. <?php namespace DomainCore; interface MarketRepository extends RepositoryInterface { /** * Find Market By KeyName * @param $keyName * @return Market */ public function byKeyName($keyName); /** * Find Market By KeyName and token * @param $keyName * @param $token * @return Market */ public function byKeyNameAndToken($keyName, $token); /** * Create an Market * @param Market $market * @return Market */ public function add(Market $market); } <?php namespace AppBundleInfrastructureCore; class MarketRepository extends SolrRepository implements DomainCoreMarketRepository { public function byKeyName($keyName) { $marketId = $this->elasticSearchRepository()->search('mkt', [$keyName]); $market = new Market(); $market->setId($marketId); $market->setName($this->redisRepository()->get('mkt':'.$keyName.':name')); $market->setKeyName($this->redisRepository()->get('mkt':'.$keyName.':keyname')); $market->setAccessToken($this->redisRepository()->get('mkt':'.$keyName.':token')); return $market; } public function byKeyNameAndToken($keyName, $token) { $marketId = $this->elasticSearchRepository()->search('mkt', [$keyName, $token]); $market = new Market(); $market->setId($marketId); $market->setName($this->redisRepository()->get('mkt':'.$keyName.':name')); $market->setKeyName($this->redisRepository()->get('mkt':'.$keyName.':keyname')); $market->setAccessToken($this->redisRepository()->get('mkt':'.$keyName.':token')); return $market; } } Redis and Solr Adapter Port
  • 15. “ Domain Driven Design (DDD) Do you know DDD ? DDD is about placing our attention at the heart of the application, focusing on the complexity that is intrinsic to the business domain itself.
  • 16. The reason to an Application Troubleshoot space and time problems What is the best way to do this? Encapsulating the business rules with layers
  • 17. Work with layers “Hexagonal Architecture defines conceptual layers of code responsibility, and then points out ways to decouple code between those layers. It's helped clarify when, how and why we use interfaces (among other ideas)” Fideloper
  • 18. Coupling between layers User Interface Application Domain Infrastructure
  • 19. Coupling between layers User Interface Application Domain Infrastructure Dependency Inversion Principle
  • 24. CommandBus Command Handler Command executes( ) handles( ) Fideloper. Hexagonal Architecture CommandBus Use Case Use Case
  • 25. <?php namespace HexCommandBus; interface CommandInterface {} <?php namespace HexTicketsCommands; use HexCommandBusCommandInterface; class CreateTicketCommand implements CommandInterface { /** * @var array */ public $data; public function __construct(Array $data) { $this->data = $data; } public function __get($property) { if( isset($this->data[$property]) ) { return $this->data[$property]; } return null; } } https://github.com/fideloper/hexagonal-php
  • 26. https://github.com/fideloper/hexagonal-php interface CommandBusInterface { public function execute(CommandInterface $command); } class CommandBus implements CommandBusInterface { private $container; private $inflector; public function __construct(Container $container, CommandNameInflector $inflector) { $this->container = $container; $this->inflector = $inflector; } public function execute(CommandInterface $command) { return $this->getHandler($command)->handle($command); } private function getHandler($command) { return $this->container->make( $this->inflector->getHandler($command) ); } }
  • 27. <?php namespace HexTicketsHandlers; class CreateTicketHandler implements HandlerInterface { private $validator; private $repository; private $dispatcher; public function __construct(CreateTicketValidator $validator, TicketRepositoryInterface $repository, Dispatcher $dispatcher) { // set attributes } public function handle(CommandInterface $command) { $this->validator->validate($command); $this->save($command); } protected function save($command) { $message = new Message; $message->message = $command->message; $ticket = new Ticket; $ticket->subject = $command->subject; $ticket->name = $command->name; $ticket->email = $command->email; $ticket->setCategory( Category::find($command->category_id) ); // Need repo $ticket->setStaffer( Staffer::find($command->staffer_id) ); // Need repo $ticket->addMessage( $message ); $this->repository->save($ticket); $this->dispatcher->dispatch( $ticket->flushEvents() ); } } https://github.com/fideloper/hexagonal-php
  • 29. { "name": "Symfony2Biso", "type": "project", "require": { "php": ">=5.3.9", "friendsofsymfony/rest-bundle": "1.7.*", "predis/predis": "1.0.*", "biso": "dev-master" }, "repositories": [ { "type": "package", "package": { "name": "biso", "version": "dev-master", "source": { "url": "https://github.com/pvgomes/biso", "type": "git", "reference": "origin/master" }, "autoload": { "psr-0": { "Domain": "src" } } } } ], }
  • 30. <?php namespace Domain; interface Command { public function repositories(); public function eventName(); public function eventNameError(); } <?php namespace AppBundleApplicationCore; use AppBundleInfrastructureCoreConfiguration; use Domain; class CreateConfigurationCommand implements DomainCommand { public $data; private $configuration; private $eventName; public function __construct($marketKey, $key, $value) { $this->eventName = DomainCoreEvents::MARKET_CREATE_CONFIGURATION; $this->configuration = new Configuration(); $this->data = ['marketKey' => $marketKey, 'key' => $key, 'value' => $value]; } public function __get($property) { $value = null; if( isset($this->data[$property]) ) { $value = $this->data[$property]; } return $value; } ... Create Configuration Command
  • 31. <?php namespace Domain; interface CommandBus { public function execute(Command $command); } <?php namespace AppBundleApplicationCommandBus; class CommandBus implements DomainCommandBus { private $container; private $eventDispatcher; private $inflector; private $applicationEvent; public function __construct(ContainerInterface $container, CommandNameInflector $inflector) { $this->container = $container; $this->inflector = $inflector; $this->eventDispatcher = $container->get('event_dispatcher'); $this->applicationEvent = new ApplicationEvent(); } public function execute(DomainCommand $command) { try { $this->applicationEvent->setCommand($command); $response = $this->getHandler($command)->handle($command); $this->eventDispatcher->dispatch($command->eventName(), $this->applicationEvent); } catch (Exception $exception) { $this->applicationEvent->setException($exception); $this->eventDispatcher->dispatch($command->eventNameError(), $this- >applicationEvent); throw $exception; } return $response; Command Bus
  • 32. <?php namespace Domain; interface Handler { public function handle(Command $command); } <?php namespace DomainCore; class CreateConfigurationHandler implements Handler { private $configurationRepository; private $market; public function __construct(Market $market) { $this->market = $market; } public function handle(Command $command) { return $this->save($command); } protected function save(Command $command) { $configuration = $command->configurationEntity(); if (!$configuration instanceof Configuration) { throw new DomainException("Invalid configuration"); } $configuration->setMarket($this->market); $configuration->setKey($command->key); $configuration->setValue($command->value); $this->configurationRepository->add($configuration); return $configuration->getId(); } ... Command Handler
  • 33. <?php namespace AppBundleApplicationControllerWeb; class SystemController extends Controller { /** * @Route("/system/configuration", name="configuration_list") * @param Request $request * @return SymfonyComponentHttpFoundationResponse */ public function configurationAction(Request $request) { $form = $this->createFormBuilder([])->add('key', 'text')->add('value', 'textarea')->getForm(); if ($request->isMethod('POST')) { $form->handleRequest($request); $data = $form->getData(); try { $createConfigurationCommand = new CreateConfigurationCommand($this->getUser()->getMarket()->getKeyName(), $data['key'], $data['value']); $this->get("command_bus")->execute($createConfigurationCommand); $flashMsg = "Chave gravada."; $flashMsgType = "success"; } catch (DomainException $e) { $flashMsg = $e->getMessage(); $flashMsgType = "warning"; } catch (Exception $e) { $flashMsg = "Erro ao inserir a chave de configuração."; $flashMsgType = "warning"; } $this->addFlash($flashMsgType , $flashMsg); } $viewVars['form'] = $form->createView(); return $this->render('web/system/configuration.html.twig', $viewVars); } Create Config Usage | Browser
  • 34. <?php namespace AppBundleApplicationApiv1Controller; class SystemController extends ApiController implements TokenAuthentication { use JsonValidator; public function configurationCreate() { $request = $this->get('request'); $marketKey = $request->headers->get('key'); $requestContent = json_decode($$request->getContent()); $jsonResponse = new JsonResponse(); try { if (!$this->isValidJson($this->loadConfigurationCreateSchema(), $requestContent)) { throw new HttpException(400, $this->getJsonErrors()); } $createConfigurationCommand = new CreateConfigurationCommand($marketKey, $requestContent->key, $requestContent->value); $this->get("command_bus")>execute($createConfigurationCommand); $jsonResponse->setStatusCode(204); } catch (DomainException $exception) { $contentError['description'] = $exception->getMessage(); $jsonResponse->setStatusCode(400); $jsonResponse->setData($contentError); } catch (Exception $exception) { $contentError['description'] = $exception->getMessage(); $jsonResponse->setStatusCode(500); $jsonResponse->setData($contentError); } return $jsonResponse; } ... Create Config Usage | API
  • 36. Thanks! Any questions? You can find me at: ◇ @pv_fusion ◇ pv.gomes89@gmail.com
  • 37. Credits Special thanks to all the people who made and released these awesome resources for free: ◇ Contents of this presentation Paulo Victor Gomes ◇ Presentation template by SlidesCarnival ◇ Photographs by Unsplash References ❖ BROOKS, FREDERICK. The Design of Design: Essays from a Computer Scientist. ❖ BUENOSVINOS, CARLOS. SORONELLA, CHRISTIAN. AKBARY, KEYVAN. Domain Driven Design in PHP. ❖ COCKBURN, ALISTAIR. Hexagonal Architecture. ❖ VERNON, VAUGHN - Implementing Domain-Driven Design. ❖ EVANS, ERICK. Domain Driven Design: Tackling Complexity in the Heart of Software.