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.

Hexagonal architecture in PHP

  • 1.
    Hexagonal Architecture Paulo Victor Systems Analyst,Open Source Developer, Zend Certified Engineer PHP 5.3. @pv_fusion
  • 2.
  • 3.
    Presentation licensed by Thispresentation 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.
  • 4.
  • 5.
    How? ◇ How canI 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 dowe even talk about Architecture? ◇ High Maintainability ◇ Low Technical Debt ◇ Semantic structure (Layers are responsible for doing what they should do)
  • 7.
    Software Architecture The architectureof 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 orderto 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 Allowan 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".
  • 10.
  • 11.
  • 12.
    <?php namespace DomainCore; interfaceMarketRepository 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; interfaceMarketRepository 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; interfaceMarketRepository 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 toan Application Troubleshoot space and time problems What is the best way to do this? Encapsulating the business rules with layers
  • 17.
    Work with layers “HexagonalArchitecture 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 UserInterface Application Domain Infrastructure
  • 19.
    Coupling between layers UserInterface Application Domain Infrastructure Dependency Inversion Principle
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
    CommandBus Command Handler Command executes( ) handles( ) Fideloper.Hexagonal Architecture CommandBus Use Case Use Case
  • 25.
    <?php namespace HexCommandBus; interfaceCommandInterface {} <?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 { publicfunction 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; classCreateTicketHandler 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
  • 28.
  • 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; classSystemController 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; classSystemController 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
  • 35.
  • 36.
    Thanks! Any questions? You canfind me at: ◇ @pv_fusion ◇ pv.gomes89@gmail.com
  • 37.
    Credits Special thanks toall 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.