SlideShare une entreprise Scribd logo
1  sur  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.

Contenu connexe

Tendances

C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26Yoshihisa Ozaki
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean ArchitectureMattia Battiston
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean ArchitectureBadoo
 
Coding standards for java
Coding standards for javaCoding standards for java
Coding standards for javamaheshm1206
 
Hexagonal architecture: how, why and when
Hexagonal architecture: how, why and whenHexagonal architecture: how, why and when
Hexagonal architecture: how, why and whenXoubaman
 
Hexagonal Architecture
Hexagonal ArchitectureHexagonal Architecture
Hexagonal ArchitectureMarcelo Cure
 
Onion Architecture
Onion ArchitectureOnion Architecture
Onion Architecturematthidinger
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean ArchitectureRoc Boronat
 
SOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureSOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureMohamed Galal
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applicationsFabricio Epaminondas
 
JSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIJSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIOctavian Nadolu
 
Domain-Driven Design
Domain-Driven DesignDomain-Driven Design
Domain-Driven DesignAndriy Buday
 
CQRS and Event Sourcing
CQRS and Event Sourcing CQRS and Event Sourcing
CQRS and Event Sourcing Inho Kang
 
Micro frontend: The microservices puzzle extended to frontend
Micro frontend: The microservices puzzle  extended to frontendMicro frontend: The microservices puzzle  extended to frontend
Micro frontend: The microservices puzzle extended to frontendAudrey Neveu
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry Sheiko
 
知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について健一 辰濱
 

Tendances (20)

C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 
Introducción a microservicios
Introducción a microserviciosIntroducción a microservicios
Introducción a microservicios
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Coding standards for java
Coding standards for javaCoding standards for java
Coding standards for java
 
Typescript ppt
Typescript pptTypescript ppt
Typescript ppt
 
Hexagonal architecture: how, why and when
Hexagonal architecture: how, why and whenHexagonal architecture: how, why and when
Hexagonal architecture: how, why and when
 
Hexagonal Architecture
Hexagonal ArchitectureHexagonal Architecture
Hexagonal Architecture
 
Onion Architecture
Onion ArchitectureOnion Architecture
Onion Architecture
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
 
TypeScript
TypeScriptTypeScript
TypeScript
 
SOLID Principles and The Clean Architecture
SOLID Principles and The Clean ArchitectureSOLID Principles and The Clean Architecture
SOLID Principles and The Clean Architecture
 
Dot Net Core
Dot Net CoreDot Net Core
Dot Net Core
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applications
 
JSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIJSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPI
 
Domain-Driven Design
Domain-Driven DesignDomain-Driven Design
Domain-Driven Design
 
CQRS and Event Sourcing
CQRS and Event Sourcing CQRS and Event Sourcing
CQRS and Event Sourcing
 
Micro frontend: The microservices puzzle extended to frontend
Micro frontend: The microservices puzzle  extended to frontendMicro frontend: The microservices puzzle  extended to frontend
Micro frontend: The microservices puzzle extended to frontend
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について知っておきたいFirebase の色んな上限について
知っておきたいFirebase の色んな上限について
 

Similaire à 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
 

Similaire à 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 SouJava
Vertx SouJavaVertx SouJava
Vertx SouJava
 
Vertx daitan
Vertx daitanVertx daitan
Vertx daitan
 
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)
 

Plus de Paulo Victor Gomes

Plus 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
 

Dernier

Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusZilliz
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
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
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 

Dernier (20)

Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
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...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
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...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 

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.