SlideShare a Scribd company logo
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.
Ad

More Related Content

What's hot (20)

Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
Roc Boronat
 
Introduction to git flow
Introduction to git flowIntroduction to git flow
Introduction to git flow
Knoldus Inc.
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slides
thinkddd
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
felixbillon
 
ASP.NET Core MVC + Web API with Overview
ASP.NET Core MVC + Web API with OverviewASP.NET Core MVC + Web API with Overview
ASP.NET Core MVC + Web API with Overview
Shahed Chowdhuri
 
Implementing DDD with C#
Implementing DDD with C#Implementing DDD with C#
Implementing DDD with C#
Pascal Laurin
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
Clean architecture
Clean architectureClean architecture
Clean architecture
.NET Crowd
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
Araf Karsh Hamid
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
Flavius Stef
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applications
Fabricio Epaminondas
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
Richard Dingwall
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
Leonardo Proietti
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
habib_786
 
Git n git hub
Git n git hubGit n git hub
Git n git hub
Jiwon Baek
 
Spring Data JPA
Spring Data JPASpring Data JPA
Spring Data JPA
Cheng Ta Yeh
 
Git and Github slides.pdf
Git and Github slides.pdfGit and Github slides.pdf
Git and Github slides.pdf
Tilton2
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
Young-Ho Cho
 
Git and git workflow best practice
Git and git workflow best practiceGit and git workflow best practice
Git and git workflow best practice
Majid Hosseini
 
Introduction to Version Control
Introduction to Version ControlIntroduction to Version Control
Introduction to Version Control
Jeremy Coates
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
Roc Boronat
 
Introduction to git flow
Introduction to git flowIntroduction to git flow
Introduction to git flow
Knoldus Inc.
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slides
thinkddd
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
felixbillon
 
ASP.NET Core MVC + Web API with Overview
ASP.NET Core MVC + Web API with OverviewASP.NET Core MVC + Web API with Overview
ASP.NET Core MVC + Web API with Overview
Shahed Chowdhuri
 
Implementing DDD with C#
Implementing DDD with C#Implementing DDD with C#
Implementing DDD with C#
Pascal Laurin
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
Clean architecture
Clean architectureClean architecture
Clean architecture
.NET Crowd
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
Flavius Stef
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applications
Fabricio Epaminondas
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
Leonardo Proietti
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
habib_786
 
Git and Github slides.pdf
Git and Github slides.pdfGit and Github slides.pdf
Git and Github slides.pdf
Tilton2
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
Young-Ho Cho
 
Git and git workflow best practice
Git and git workflow best practiceGit and git workflow best practice
Git and git workflow best practice
Majid Hosseini
 
Introduction to Version Control
Introduction to Version ControlIntroduction to Version Control
Introduction to Version Control
Jeremy Coates
 

Similar to Hexagonal architecture in PHP (20)

Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
Wildan Maulana
 
Best practices tekx
Best practices tekxBest practices tekx
Best practices tekx
Lorna Mitchell
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo 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 Symfony2
Hugo 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 Jetpack
Ahmad Arif Faizin
 
Gwt.create
Gwt.createGwt.create
Gwt.create
Mauricio (Salaboy) Salatino
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmers
Alexander Varwijk
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web Artisans
Raf 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 generation
Alexander Obukhov
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
Darren 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 4
Darwin Biler
 
Vertx SouJava
Vertx SouJavaVertx SouJava
Vertx SouJava
Claudio Eduardo de Oliveira
 
Vertx daitan
Vertx daitanVertx daitan
Vertx daitan
Claudio Eduardo de Oliveira
 
Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010
Satish Verma
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
Jeremy 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
 
Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
Wildan Maulana
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo 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 Symfony2
Hugo 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 Jetpack
Ahmad Arif Faizin
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmers
Alexander Varwijk
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web Artisans
Raf 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 generation
Alexander Obukhov
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
Darren 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 4
Darwin Biler
 
Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010
Satish Verma
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
Jeremy 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
 
Ad

More from 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
Paulo Victor Gomes
 
PHP as a Service TDC2019
PHP as a Service TDC2019PHP as a Service TDC2019
PHP as a Service TDC2019
Paulo Victor Gomes
 
PHP as a Service
PHP as a ServicePHP as a Service
PHP as a Service
Paulo Victor Gomes
 
Stacks Cloud - Digital Ocean
Stacks Cloud - Digital OceanStacks Cloud - Digital Ocean
Stacks Cloud - Digital Ocean
Paulo Victor Gomes
 
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
Paulo Victor Gomes
 
Essay about event driven architecture
Essay about event driven architectureEssay about event driven architecture
Essay about event driven architecture
Paulo Victor Gomes
 
DDD in PHP
DDD in PHPDDD in PHP
DDD in PHP
Paulo Victor Gomes
 
PHP e Redis
PHP e RedisPHP e Redis
PHP e Redis
Paulo Victor Gomes
 
Domain Driven Design PHP TDC2014
Domain Driven Design PHP TDC2014Domain Driven Design PHP TDC2014
Domain Driven Design PHP TDC2014
Paulo Victor Gomes
 
Ad

Recently uploaded (20)

Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager APIUiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPathCommunity
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Cybersecurity Identity and Access Solutions using Azure AD
Cybersecurity Identity and Access Solutions using Azure ADCybersecurity Identity and Access Solutions using Azure AD
Cybersecurity Identity and Access Solutions using Azure AD
VICTOR MAESTRE RAMIREZ
 
What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...
Vishnu Singh Chundawat
 
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Aqusag Technologies
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.
hpbmnnxrvb
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager APIUiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPathCommunity
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Cybersecurity Identity and Access Solutions using Azure AD
Cybersecurity Identity and Access Solutions using Azure ADCybersecurity Identity and Access Solutions using Azure AD
Cybersecurity Identity and Access Solutions using Azure AD
VICTOR MAESTRE RAMIREZ
 
What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...What is Model Context Protocol(MCP) - The new technology for communication bw...
What is Model Context Protocol(MCP) - The new technology for communication bw...
Vishnu Singh Chundawat
 
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Massive Power Outage Hits Spain, Portugal, and France: Causes, Impact, and On...
Aqusag Technologies
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.
hpbmnnxrvb
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 

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 ◇ [email protected]
  • 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.