SlideShare une entreprise Scribd logo
1  sur  69
Zehreen Soogun / zehreen@extension-interactive.com
Jihad Sahebdin / jihad@extension-interactive.com
S y m f o n y 3
31/03/2017
C Q R S e t E v e n t s o u r c i n g
2
Who Am I
SOOGUN Bibi Zehreen
¬ Chef de Projet Technique
¬ Extension Interactive
Je suis #Zehreen
Find me on :-
https://twitter.com/bzehreens
https://mu.linkedin.com/in/bibi-zehreen-soogun-53115190
3
Speakers / Présentation intervenants
Zehreen
¬ CQRS
¬ ES
Jihad
¬ Cas réel
¬ MEP CQRS et ES dans un projet SF 3.
4
1. CQRS
1. Introduction
2. Avantages
3. Désavantages
4. Utilisation
2. Event Sourcing
3. Architecture
4. Conclusions
5
CQRS / Introduction
Command
Query
Responsibility
Segregation
Pioneer de CQRS
¬ Greg Young
Origine de CQRS
¬ Bertrand Meyer - CQS
6
CQRS / Command
Contexte boutique : Je valide ma commande
Contexte Symfony : Je lance une commande via console
¬ php bin/console c:c
7
CQRS / Command
Nom d’une tâche
¬ Temps impératif
Données requises pour effectuer la tâche
a.k.a
¬ Mutators
¬ Modifiers
Contrast avec CRUD
¬ Point de données
openCustomerAccountCommand
8
CQRS / Query
Types de requêtes classiques
¬ Insert
¬ Select
¬ Update
¬ Delete
ReadOnly
¬ Récupération des données
Constraste avec CRUD
¬ TOUTES les opérations VS Lecture seule
9
CQRS & CQS
Similarités
¬ Utilisation commandes (modification) et requêtes (récupération)
 Différence
¬ Write Model
¬ Read Model
10
CQRS / Avantages
Performance
¬ Plus de lecture que d’écriture
Evolution
11
CQRS / Désavantages
Complexité
Réduction de productivité
12
CQRS / Utilisation
Environnement collaborative
Données en simultanés
Applications haute performance
Système complèxe
¬ Bounded Context
BankSystem
Pas nécessaire d’appliquer CQRS dans
l’intégralité d’un système
13
CQRS / A éviter
Système simple
Système statique
Système non-collaboratif
Système avec zéro logique métier
14
CQRS / Faire notre choix
Découpler Read et Write / Coûteux
Réfléchir en terme de DDD et non CRUD
15
1. CQRS
1. Introduction
2. Avantages
3. Désavantages
4. Utilisation
2. Event Sourcing
3. Architecture
4. Conclusions
16
Event Sourcing
Evènements
¬ a.k.a Domain Event
CustomerAccountOpened
Pas de suppréssion
17
CQRS + Event Sourcing
18
1. Architecture
1. Aperçu
2. Mise en place
3. Bonnes pratiques
4. Sécurité
5. CORS
19
Aperçu
Application de type API/UI
Enregistrement dans 2 bases de données
¬ Write model
¬ Read model
La UI envoie des requêtes sur l’API et récupère les
données depuis Firebase
UI
API Firebase
20
Le Domain Model
Système de gestion:
Une business unit emploie des salaries qui vont travailler
sur des contrats liés à des clients
Business Units
Salariés Contrats
Clients
21
1. Architecture
1. Aperçu
2. Mise en place
3. Bonnes pratiques
4. Sécurité
5. CORS
22
Architecture
23
Bounded context
Le Domain Model s’organise en morceaux
Chaque morceau correspond à:
¬ un métier
¬ Un composant métier
¬ Une problématique métier qu’il propose de solutionner
Morceau = Bounded Context
Exemple:
¬ Un context RH qui s’occupe de gérer les employés
¬ Un context Contrat qui s’occupe de gérer ses clients et ses
ressources
24
Bounded context / Composants autonomes
Un bounded context peut être composé d’un ou de
plusieurs composants autonomes.
Les composants apportent une solution aux
problématiques identifiés dans un bounded context.
Exemple:
¬ On va s’occuper de la gestion des business units dans le
composant Business Units management
25
Bounded context / Composants autonomes
3 bounded contexts:
¬ Business units
¬ Human Resource
¬ Contracts
Business Unit
Human
Resource
Contract
26
Bounded context / Composants autonomes
Fonctionnement
¬ Un composant reçoit des messages en provenance du
MessageBus:
- Soit par l’intermédiaire de ses CommandHandlers s’il s’agit de
commandes
- Soit par l’intermédiaire de ses ProcessManagers s’il s’agit
d’évènements
27
Bounded context / Structure
28
Commands
Commands:
¬ Les ordres données au Domain Model
¬ Sources diverses:
- Application web
- Application mobile
- Ligne de commandes
¬ Format json
¬ Construction d’un objet Command à partir des données
Domain
Model
Application
Web
Application
mobile
Ligne de
commande
29
Commands
Exemple:
¬ La classe HireEmployeeCommand
class HireEmployeeCommand
{
public $employeeId;
public $employerId;
public $employeeFirstName;
public $employeeLastName;
public $employeeCivility;
public $employeeJobTitle;
public $employeeEmail;
public $requestedBy;
}
30
Commands
Controller:
¬ HRManagementController
- hireEmployeeAction
use pathtoCommandingCommandsHireEmployeeCommand;
class HRManagementController extends Controller
{
/**
* @Route("/hire-employee", name="hire_employee")
*/
public function hireEmployeeAction(Request $request)
{
$commandBus = $this->get('command_bus');
$hireEmployeeCommand = new HireEmployeeCommand();
//Populate command data
$commandBus->handle($hireEmployeeCommand);
return new Response("Employee hired");
}
}
31
SimpleBus bundle
http://simplebus.github.io/SymfonyBridge/
Auteur: Matthias Noback
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
...
new SimpleBusSymfonyBridgeSimpleBusEventBusBundle()
)
...
}
...
}
32
Command Handlers
HireEmployeeCommandHandler
¬ Handle
Service
hire_employee_command_handler:
class: pathtoCommandingCommandHandlersHireEmployeeCommandHandler
tags:
- {
name: command_handler,
handles: pathtoCommandingCommandsHireEmployeeCommand
}
namespace pathtoCommandingCommandHandlers;
class HireEmployeeCommandHandler
{
public function handle(HireEmployeeCommand $command)
{
33
Command Handlers
Reconstruction de l’agrégat à partir de son historique
Enregistrement des évènements
public function handle(HireEmployeeCommand $command)
{
$employeeId = $command->employeeId;
$history = $this->eventStore->getHistoryFor($employeeId);
$employeeAggregate = employeeAggregate::reconstituteFrom($employeeId, $history);
34
Command Handlers
On passe les données à l’agrégat
$employeeAggregate->hireEmployee(
$command->employeeId,
$command->employerId,
$command->employeeFirstName,
$command->employeeLastName,
$command->employeeCivility,
$command->employeeJobTitle,
$command->employeeEmail,
$command->requestedBy,
$command->requestedOn
);
35
Command Handlers
Enregistrement des évènements
Dispatch de l’évènement
foreach ($events as $event) {
$this->eventBus->handle($event);
}
$events = $this->eventStore->save($employeeAggregate);
36
Agrégats
Contient la logique du Domain model
Validation sémantique des commandes
Reçoit les commandes du MessageBus
Emet un ou plusieurs évènements relatant l’opération
qu’il vient d’executer
¬ employeeHiredEvent
37
Agrégats
Validation des commandes
¬ Un agrégat peut réfuser d’éxécuter une commande
- Exemple:
› Par exemple, si HRManagementAggregate reçoit la commande
HireEmployeeCommand pour une BU donnée, si la BU n’existe pas, il doit
renvoyer une exception
class HRManagementAggregate
{
public function hireEmployee($employeeId, $employerId, $employeeFirstName, $employeeLastName)
{
$this->isBusinessUnitIdValid($employerId);
$this->recordThat(new EmployeeHiredEvent($employeeId, $employerId, $employeeFirstName,
$employeeLastName));
}
private function isBusinessUnitIdValid($businessUnit)
{
if (!$businessUnit instanceof BusinessUnit) {
throw new BusinessUnitIdIsNotValidException('This business Unit is not valid');
}
return;
}
}
38
Domain Events
Domain Events
¬ Les évènements métiers produits par les aggrégats
¬ Exemple:
- L’évènement EmployeeHiredEvent émis par l’agrégat
HRManagementAggregate
namespace pathtoAggregatesDomainEvents;
class EmployeeHiredEvent
{
/**
* @Type("string")
*/
private $employeeId;
public function __construct($employeeId)
{
$this->employeeId = $employeeId;
}
public function getEmployeeId()
{
return $this->employeeId;
}
}
39
Bounded context / Récapitulatif
Récapitulatif:
¬ On a donc réussi à construire une commande à partir d’une
requête venant de l’extérieur
¬ Le command handler s’est chargé de le communiquer à
l’agrégat
¬ L’agrégat valide la commande, l’éxécute et génère un
évènement
¬ L’évènement est stocké dans l’event store puis dispatché a
l’event bus
40
Bounded context / Suite
L’évènement peut alors être:
¬ Propagé dans la UI par le biais des denormalizers
¬ Capté par les process managers.
41
Denormalizers
42
Denormalizers
Problème
¬ Données pas exploitable pour la UI
{
"employee_id":"4731ab33-1db8-4570-bc27-e3f4ec0f4feb",
"employer_id":"123a3256-2345-1243-a231-a123c1567b12",
"employee_first_name":"Jihad",
"employee_last_name":"Sahebdin",
"employee_civility":"M",
"employee_job_title":"Developer",
"employee_email":"jihad@sahebdin.com",
"requested_by":"f54d197b-9647-47f8-bfa6-d3acedd54556",
"requested_on":"20170222 18:40:41 +0400"
}
43
Firebase
https://console.firebase.google.com
44
Firebase
Avantages
¬ L’authentification est gérée ‘in-built’ par Google
¬ Base de données en temps réel
¬ Firebase et Angular JS
¬ Permet de déployer une application (UI) par ligne de commande
- > firebase deploy
Inconvenients
¬ On fait confiance à Google concernant la securité des données
45
Firebase
Utilisation dans symfony
¬ Bundle
- https://github.com/ktamas77/firebase-php
¬ Utilisation
const DEFAULT_URL = 'https://kidsplace.firebaseio.com/';
const DEFAULT_TOKEN = 'MqL0c8tKCtheLSYcygYNtGhU8Z2hULOFs9OKPdEp';
const DEFAULT_PATH = '/firebase/example';
$firebase = new FirebaseFirebaseLib(DEFAULT_URL, DEFAULT_TOKEN);
// --- storing an array ---
$test = array(
"foo" => "bar",
"i_love" => "lamp",
"id" => 42
);
$dateTime = new DateTime();
$firebase->set(DEFAULT_PATH . '/' . $dateTime->format('c'), $test);
46
Firebase
Utilisation dans symfony
¬ Evènement EmployeeHiredEvent
class UpdateEmployeesListDenormalizer
{
public function notify(EmployeeHiredEvent $event)
{
$path = '/users/list/'.$event->getEmployeeId();
$firebase->set($path.'/buId', $event->getEmployerId());
$firebase->set($path.'/id', $event->getEmployeeId());
$firebase->set($path.'/civility', $event->getEmployeeCivility());
$firebase->set($path.'/email', $event->getEmployeeEmail());
$firebase->set($path.'/firstname', $event->getEmployeeFirstName());
$firebase->set($path.'/lastname', $event->getEmployeeLastName());
$firebase->set($path.'/job_title', $event->getEmployeeJobTitle());
}
}
47
Firebase
Utilisation dans symfony
¬ Evènement EmployeeHiredEvent
¬ Service
- Un denormalizer va souscrire à l’évènement
update_employees_list_denormalizer:
class: pathtoDenormalizersUpdateEmployeesListDenormalizer
tags:
- { name: event_subscriber,
subscribes_to: pathtoAggregatesDomainEventsEmployeeHiredEvent,
method: notify }
48
Process Managers
a.k.a Saga
Ecoute des évènements et dispatch de nouvelles
commandes
Utile pour coordonner les actions entre les bounded
contexts
Exemple
¬ HRManagement et BusinessUnitManagement
¬ Combien de salariés possède une BU?
- Informer l’agrégat BU pour qu’il incrémente/décrémente son
nombre de salariés à chaque fois qu’une personne est embauche
pour cette BU.
- Solution: Création d’un service qui souscrit à l’évènement
EmployeeHiredEvent
49
Process Managers
Exemple (suite)
¬ ChangeNumberOfEmployeesInBusinessUnitCommand
¬ AddEmployeeToBusinessUnitSaga
class changeNumberOfEmployeesInBusinessUnitCommand
{
public $businessUnitId;
}
class AddEmployeeToBusinessUnitSaga
{
public function notify(EmployeeHiredEvent $event)
{
$command = new changeNumberOfEmployeesInBusinessUnitCommand();
$command->businessUnitId = $event->getEmployerId();
$this->commandBus->handle($command);
}
}
50
Conclusion
Complexe à mettre en oeuvre
Difficile à faire en CRUD
¬ Opérations de lecture et d’écriture sont dissosiées
¬ Pas de conflits dans le cas où plusieurs utilisateurs mettent à jour
le même objet
¬ Enregistrement des actions et des données sur une entité
¬ Historique des évènements possible
¬ Restauration du read model à partir du write model
+ Restauration à partir d’un évènement
¬ Séparation de l’implementation plus facile
51
1. Architecture
1. Aperçu
2. Mise en place
3. Bonnes pratiques
4. Sécurité
5. CORS
52
Bonnes pratiques
Le nom des méthodes est important
¬ Le nom doit reflécter au maximum l’objectif ce que
l’utilisateur veut faire
¬ Exemple:
- HireEmployeeCommand
- EmployeeHiredEvent
- EmployeeLastNameChanged
- ContractTransferredToOtherDirectorEvent
- RessourceAddedToContractEvent
- AccountUpdated / AccountModified
Les commandes sont au présent, les évènements sont
au passé
53
Bonnes pratiques
Un évènement ne peut/doit pas être modifié
¬ Pas de setters dans les classes Event
Un évènement est idempotent
¬ Exemple:
- FireEmployeeCommand sur une même personne n fois
- L’état de l’agrégat ne changera pas après la première fois
- L’agrégat de contentera d’ignorer la commande (et ne pas
renvoyer d’exception)
Valider les commandes
54
Bonnes pratiques
Les bounded contexts doivent être identifiés dès le
début
¬ Division du problème initial en sous-problèmes (bounded
contexts)
¬ Division des bounded contexts en composants autonomes
Identifier le langage du domain expert
Personne
Employé
(RH)
Ressource
(Contrat)
Collaborateur
(Business Unit)
55
1. Architecture
1. Aperçu
2. Mise en place
3. Bonnes pratiques
4. Sécurité
5. CORS
56
Sécurité
Restriction sur la méthode
¬ Autoriser uniquement les POST
¬ MethodListener
app.method_listener:
class: AppBundleListenerMethodListener
arguments: ['POST']
tags:
- { name: kernel.event_listener,
event: kernel.controller,
method: onKernelController,
}
57
Sécurité
Restriction sur la méthode (suite)
¬ Autoriser uniquement les POST
¬ onKernelController
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if ($controller[0] instanceof Controller){
$request = $event->getRequest()->getMethod();
if (!in_array($request, $this->method)){
$event->stopPropagation();
throw new MethodNotAllowedHttpException(
array('POST'),
'Method Not Allowed‘
);
}
}
}
58
Sécurité
Authentifier les requêtes grâce aux headers
d’authentificatiom
JWT = Json Web Token
¬ Encodage de la requête et insertion dans le header
¬ Composé de troix parties
- header
- payload
- signature
59
Sécurité / JWT
Header
¬ Type
¬ Algorithme de cryptage
¬ Base64
{
"typ": "JWT",
"alg": "HS256"
}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
60
Sécurité / JWT
Payload
{
"employee_id":"4731ab33-1db8-4570-bc27-e3f4ec0f4feb",
"employer_id":"123a3256-2345-1243-a231-a123c1567b12",
"employee_first_name":"Jihad",
"employee_last_name":"Sahebdin",
"employee_civility":"M",
"employee_job_title":"Developer",
"employee_email":"jihad@sahebdin.com",
"requested_by":"f54d197b-9647-47f8-bfa6-d3acedd54556",
"requested_on":"20170222 18:40:41 +0400"
}
61
Sécurité / JWT
Signature
¬ Header
¬ Payload
¬ Crypter en HMAC256 avec un secret
var encodedString = base64UrlEncode(header) + "." +
base64UrlEncode(payload);
HMACSHA256(encodedString, 'secret');
62
Sécurité
Côté API
¬ TokenListener
¬ Récupération du header
¬ Décryptage du token
app.token.token_listener:
class: AppBundleListenerTokenListener
arguments: ['@app.token_authenticator']
tags:
- { name: kernel.event_listener, event: kernel.request,
method: onKernelRequest }
$header = $request->headers->get('authorization');
try {
$decoded = JWT::decode($token, $secret, array('HS256'));
}
catch (Exception $e) {
return Response::HTTP_FORBIDDEN;
}
63
Sécurité / Nonce
Nonce = Number used ONCE
Insertion dans la requête pour l’encodage
Vérification de l’unicité du nonce avec les nonces déjà
utilisés
64
Sécurité / UUID
UUID = Universally Unique Identifier
Utilisé comme:
¬ identifiant d’une entité
¬ nonce
Version 4
¬ Génère une uuid aléatoire
¬ 123e4567-e89b-12d3-a456-426655440000
65
1. Architecture
1. Aperçu
2. Mise en place
3. Bonnes pratiques
4. Sécurité
5. CORS
66
Sécurité / CORS
Modification de la request
¬ Dans un event listener: onKernelRequest
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if ($request->headers->has("Access-Control-Request-Headers")
&& $request->headers->has("Access-Control-Request-Method"))
{
$response = new Response();
//enable CORS - return the requested methods as allowed
$response->headers->add(
array(
'Access-Control-Allow-Headers' => $request->headers->get("Access-
Control-Request-Headers"),
'Access-Control-Allow-Methods' => $request->headers->get("Access-
Control-Request-Method"),
'Access-Control-Allow-Origin' => '*'));
$event->setResponse($response);
}
67
Un mot sur la UI
Données stockés sur Firebase
¬ Correspondance entre l’arborescence des données et les urls
(pages) de la UI
¬ Utilisation d’un resolve avant le chargement de la page
resolve: {
listEmployees : function(firebaseService) {
return firebaseService.get('/users/list');
},
68
Références
Bundles existants
¬ Broadway
- https://github.com/broadway/broadway
¬ LiteCqrs
- https://github.com/beberlei/litecqrs-php
Auteurs
¬ Gregory Young
- Simple CQRS example: https://github.com/gregoryyoung/m-r
¬ Matthias Noback
- https://php-and-symfony.matthiasnoback.nl/
¬ Benjamin Eberlei
- https://beberlei.de/
¬ Martin Fowler
- https://martinfowler.com/bliki/CQRS.html
¬ Daniel Whittaker
- http://danielwhittaker.me/
extension interactive
14, avenue des Lataniers
72238 Quatre Bornes
Merci

Contenu connexe

Tendances

Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech daysJean-Pierre Vincent
 
Introduction à Angular JS
Introduction à Angular JSIntroduction à Angular JS
Introduction à Angular JSAntoine Rey
 
php2 : formulaire-session-PDO
php2 : formulaire-session-PDOphp2 : formulaire-session-PDO
php2 : formulaire-session-PDOAbdoulaye Dieng
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptMicrosoft Technet France
 
Php mysql cours
Php mysql coursPhp mysql cours
Php mysql courszan
 
Python avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementiellePython avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementielleECAM Brussels Engineering School
 
Trucs et astuces PHP et MySQL
Trucs et astuces PHP et MySQLTrucs et astuces PHP et MySQL
Trucs et astuces PHP et MySQLDamien Seguy
 
Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Engineor
 
JavaScript prise en main et fondamentaux
JavaScript prise en main et fondamentauxJavaScript prise en main et fondamentaux
JavaScript prise en main et fondamentauxVincent Petetin
 
Formation PHP avancé - Cake PHP
Formation PHP avancé - Cake PHPFormation PHP avancé - Cake PHP
Formation PHP avancé - Cake PHPkemenaran
 
Formulaires Symfony2 - Cas pratiques et explications
Formulaires Symfony2 - Cas pratiques et explicationsFormulaires Symfony2 - Cas pratiques et explications
Formulaires Symfony2 - Cas pratiques et explicationsAlexandre Salomé
 
Bases de PHP - Partie 1
Bases de PHP - Partie 1Bases de PHP - Partie 1
Bases de PHP - Partie 1Régis Lutter
 
Cours php & Mysql - 5éme partie
Cours php & Mysql - 5éme partieCours php & Mysql - 5éme partie
Cours php & Mysql - 5éme partiekadzaki
 
Sécurité et Quaité de code PHP
Sécurité et Quaité de code PHPSécurité et Quaité de code PHP
Sécurité et Quaité de code PHPJean-Marie Renouard
 
Cours php & Mysql - 4éme partie
Cours php & Mysql - 4éme partieCours php & Mysql - 4éme partie
Cours php & Mysql - 4éme partiekadzaki
 

Tendances (20)

Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech days
 
Introduction à Angular JS
Introduction à Angular JSIntroduction à Angular JS
Introduction à Angular JS
 
SQL et MySQL
SQL et MySQLSQL et MySQL
SQL et MySQL
 
php2 : formulaire-session-PDO
php2 : formulaire-session-PDOphp2 : formulaire-session-PDO
php2 : formulaire-session-PDO
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScript
 
Javascript et JQuery
Javascript et JQueryJavascript et JQuery
Javascript et JQuery
 
Php mysql cours
Php mysql coursPhp mysql cours
Php mysql cours
 
Python avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementiellePython avancé : Interface graphique et programmation évènementielle
Python avancé : Interface graphique et programmation évènementielle
 
Trucs et astuces PHP et MySQL
Trucs et astuces PHP et MySQLTrucs et astuces PHP et MySQL
Trucs et astuces PHP et MySQL
 
Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !
 
JavaScript prise en main et fondamentaux
JavaScript prise en main et fondamentauxJavaScript prise en main et fondamentaux
JavaScript prise en main et fondamentaux
 
Formation PHP avancé - Cake PHP
Formation PHP avancé - Cake PHPFormation PHP avancé - Cake PHP
Formation PHP avancé - Cake PHP
 
PHP 5 et la programmation objet
PHP 5 et la programmation objetPHP 5 et la programmation objet
PHP 5 et la programmation objet
 
Formulaires Symfony2 - Cas pratiques et explications
Formulaires Symfony2 - Cas pratiques et explicationsFormulaires Symfony2 - Cas pratiques et explications
Formulaires Symfony2 - Cas pratiques et explications
 
Bases de PHP - Partie 1
Bases de PHP - Partie 1Bases de PHP - Partie 1
Bases de PHP - Partie 1
 
Cours php & Mysql - 5éme partie
Cours php & Mysql - 5éme partieCours php & Mysql - 5éme partie
Cours php & Mysql - 5éme partie
 
Héritage et redéfinition de méthode
Héritage et redéfinition de méthodeHéritage et redéfinition de méthode
Héritage et redéfinition de méthode
 
Sécurité et Quaité de code PHP
Sécurité et Quaité de code PHPSécurité et Quaité de code PHP
Sécurité et Quaité de code PHP
 
Cours php & Mysql - 4éme partie
Cours php & Mysql - 4éme partieCours php & Mysql - 4éme partie
Cours php & Mysql - 4éme partie
 
Corrige tp java
Corrige tp javaCorrige tp java
Corrige tp java
 

Similaire à Symfony CQRS and _event_sourcing

Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: AngularHabib Ayad
 
Université de la performance - Devoxx France
Université de la performance - Devoxx FranceUniversité de la performance - Devoxx France
Université de la performance - Devoxx FranceMarc Bojoly
 
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuXebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuPublicis Sapient Engineering
 
Paris ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesParis ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesGuillaume Gérard
 
4_Architectures_de_SI.pdf
4_Architectures_de_SI.pdf4_Architectures_de_SI.pdf
4_Architectures_de_SI.pdfharizi riadh
 
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...ENSET, Université Hassan II Casablanca
 
Britair mdday2010
Britair mdday2010Britair mdday2010
Britair mdday2010MD DAY
 
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...Arcbees
 
L’atout cartographie en mobilité : implémentation pratique et cas concrets
L’atout cartographie en mobilité : implémentation pratique et cas concretsL’atout cartographie en mobilité : implémentation pratique et cas concrets
L’atout cartographie en mobilité : implémentation pratique et cas concretsMicrosoft
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniterAtsé François-Xavier KOBON
 
ait_mlouk_addi_presentation_pfe
ait_mlouk_addi_presentation_pfeait_mlouk_addi_presentation_pfe
ait_mlouk_addi_presentation_pfeAddi Ait-Mlouk
 
Université de la performance
Université de la performanceUniversité de la performance
Université de la performancepkernevez
 
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...MIM Synchronization Services 2016 -> une solution économique pour créer, modi...
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...Identity Days
 
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetite
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetiteGab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetite
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetiteAZUG FR
 

Similaire à Symfony CQRS and _event_sourcing (20)

Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: Angular
 
Perf university
Perf universityPerf university
Perf university
 
Université de la performance - Devoxx France
Université de la performance - Devoxx FranceUniversité de la performance - Devoxx France
Université de la performance - Devoxx France
 
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuXebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
 
Paris ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesParis ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websites
 
4_Architectures_de_SI.pdf
4_Architectures_de_SI.pdf4_Architectures_de_SI.pdf
4_Architectures_de_SI.pdf
 
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
 
Britair mdday2010
Britair mdday2010Britair mdday2010
Britair mdday2010
 
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
 
L’atout cartographie en mobilité : implémentation pratique et cas concrets
L’atout cartographie en mobilité : implémentation pratique et cas concretsL’atout cartographie en mobilité : implémentation pratique et cas concrets
L’atout cartographie en mobilité : implémentation pratique et cas concrets
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
 
Projet Airbus A380-800: Visite Virtuelle
Projet Airbus A380-800: Visite VirtuelleProjet Airbus A380-800: Visite Virtuelle
Projet Airbus A380-800: Visite Virtuelle
 
Formation Agile Scrum
Formation Agile ScrumFormation Agile Scrum
Formation Agile Scrum
 
ait_mlouk_addi_presentation_pfe
ait_mlouk_addi_presentation_pfeait_mlouk_addi_presentation_pfe
ait_mlouk_addi_presentation_pfe
 
Azure Serverless C2S
Azure Serverless C2SAzure Serverless C2S
Azure Serverless C2S
 
Université de la performance
Université de la performanceUniversité de la performance
Université de la performance
 
I3M- Airbus Visite Virtuelle
I3M- Airbus Visite VirtuelleI3M- Airbus Visite Virtuelle
I3M- Airbus Visite Virtuelle
 
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...MIM Synchronization Services 2016 -> une solution économique pour créer, modi...
MIM Synchronization Services 2016 -> une solution économique pour créer, modi...
 
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetite
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetiteGab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetite
Gab17 lyon-rex build dev ops sur une infra iaas-paas multisite-by-matthieupetite
 
Projet Airbus : Visite Virtuelle
Projet Airbus : Visite VirtuelleProjet Airbus : Visite Virtuelle
Projet Airbus : Visite Virtuelle
 

Symfony CQRS and _event_sourcing

  • 1. Zehreen Soogun / zehreen@extension-interactive.com Jihad Sahebdin / jihad@extension-interactive.com S y m f o n y 3 31/03/2017 C Q R S e t E v e n t s o u r c i n g
  • 2. 2 Who Am I SOOGUN Bibi Zehreen ¬ Chef de Projet Technique ¬ Extension Interactive Je suis #Zehreen Find me on :- https://twitter.com/bzehreens https://mu.linkedin.com/in/bibi-zehreen-soogun-53115190
  • 3. 3 Speakers / Présentation intervenants Zehreen ¬ CQRS ¬ ES Jihad ¬ Cas réel ¬ MEP CQRS et ES dans un projet SF 3.
  • 4. 4 1. CQRS 1. Introduction 2. Avantages 3. Désavantages 4. Utilisation 2. Event Sourcing 3. Architecture 4. Conclusions
  • 5. 5 CQRS / Introduction Command Query Responsibility Segregation Pioneer de CQRS ¬ Greg Young Origine de CQRS ¬ Bertrand Meyer - CQS
  • 6. 6 CQRS / Command Contexte boutique : Je valide ma commande Contexte Symfony : Je lance une commande via console ¬ php bin/console c:c
  • 7. 7 CQRS / Command Nom d’une tâche ¬ Temps impératif Données requises pour effectuer la tâche a.k.a ¬ Mutators ¬ Modifiers Contrast avec CRUD ¬ Point de données openCustomerAccountCommand
  • 8. 8 CQRS / Query Types de requêtes classiques ¬ Insert ¬ Select ¬ Update ¬ Delete ReadOnly ¬ Récupération des données Constraste avec CRUD ¬ TOUTES les opérations VS Lecture seule
  • 9. 9 CQRS & CQS Similarités ¬ Utilisation commandes (modification) et requêtes (récupération)  Différence ¬ Write Model ¬ Read Model
  • 10. 10 CQRS / Avantages Performance ¬ Plus de lecture que d’écriture Evolution
  • 12. 12 CQRS / Utilisation Environnement collaborative Données en simultanés Applications haute performance Système complèxe ¬ Bounded Context BankSystem Pas nécessaire d’appliquer CQRS dans l’intégralité d’un système
  • 13. 13 CQRS / A éviter Système simple Système statique Système non-collaboratif Système avec zéro logique métier
  • 14. 14 CQRS / Faire notre choix Découpler Read et Write / Coûteux Réfléchir en terme de DDD et non CRUD
  • 15. 15 1. CQRS 1. Introduction 2. Avantages 3. Désavantages 4. Utilisation 2. Event Sourcing 3. Architecture 4. Conclusions
  • 16. 16 Event Sourcing Evènements ¬ a.k.a Domain Event CustomerAccountOpened Pas de suppréssion
  • 17. 17 CQRS + Event Sourcing
  • 18. 18 1. Architecture 1. Aperçu 2. Mise en place 3. Bonnes pratiques 4. Sécurité 5. CORS
  • 19. 19 Aperçu Application de type API/UI Enregistrement dans 2 bases de données ¬ Write model ¬ Read model La UI envoie des requêtes sur l’API et récupère les données depuis Firebase UI API Firebase
  • 20. 20 Le Domain Model Système de gestion: Une business unit emploie des salaries qui vont travailler sur des contrats liés à des clients Business Units Salariés Contrats Clients
  • 21. 21 1. Architecture 1. Aperçu 2. Mise en place 3. Bonnes pratiques 4. Sécurité 5. CORS
  • 23. 23 Bounded context Le Domain Model s’organise en morceaux Chaque morceau correspond à: ¬ un métier ¬ Un composant métier ¬ Une problématique métier qu’il propose de solutionner Morceau = Bounded Context Exemple: ¬ Un context RH qui s’occupe de gérer les employés ¬ Un context Contrat qui s’occupe de gérer ses clients et ses ressources
  • 24. 24 Bounded context / Composants autonomes Un bounded context peut être composé d’un ou de plusieurs composants autonomes. Les composants apportent une solution aux problématiques identifiés dans un bounded context. Exemple: ¬ On va s’occuper de la gestion des business units dans le composant Business Units management
  • 25. 25 Bounded context / Composants autonomes 3 bounded contexts: ¬ Business units ¬ Human Resource ¬ Contracts Business Unit Human Resource Contract
  • 26. 26 Bounded context / Composants autonomes Fonctionnement ¬ Un composant reçoit des messages en provenance du MessageBus: - Soit par l’intermédiaire de ses CommandHandlers s’il s’agit de commandes - Soit par l’intermédiaire de ses ProcessManagers s’il s’agit d’évènements
  • 27. 27 Bounded context / Structure
  • 28. 28 Commands Commands: ¬ Les ordres données au Domain Model ¬ Sources diverses: - Application web - Application mobile - Ligne de commandes ¬ Format json ¬ Construction d’un objet Command à partir des données Domain Model Application Web Application mobile Ligne de commande
  • 29. 29 Commands Exemple: ¬ La classe HireEmployeeCommand class HireEmployeeCommand { public $employeeId; public $employerId; public $employeeFirstName; public $employeeLastName; public $employeeCivility; public $employeeJobTitle; public $employeeEmail; public $requestedBy; }
  • 30. 30 Commands Controller: ¬ HRManagementController - hireEmployeeAction use pathtoCommandingCommandsHireEmployeeCommand; class HRManagementController extends Controller { /** * @Route("/hire-employee", name="hire_employee") */ public function hireEmployeeAction(Request $request) { $commandBus = $this->get('command_bus'); $hireEmployeeCommand = new HireEmployeeCommand(); //Populate command data $commandBus->handle($hireEmployeeCommand); return new Response("Employee hired"); } }
  • 31. 31 SimpleBus bundle http://simplebus.github.io/SymfonyBridge/ Auteur: Matthias Noback class AppKernel extends Kernel { public function registerBundles() { $bundles = array( ... new SimpleBusSymfonyBridgeSimpleBusEventBusBundle() ) ... } ... }
  • 32. 32 Command Handlers HireEmployeeCommandHandler ¬ Handle Service hire_employee_command_handler: class: pathtoCommandingCommandHandlersHireEmployeeCommandHandler tags: - { name: command_handler, handles: pathtoCommandingCommandsHireEmployeeCommand } namespace pathtoCommandingCommandHandlers; class HireEmployeeCommandHandler { public function handle(HireEmployeeCommand $command) {
  • 33. 33 Command Handlers Reconstruction de l’agrégat à partir de son historique Enregistrement des évènements public function handle(HireEmployeeCommand $command) { $employeeId = $command->employeeId; $history = $this->eventStore->getHistoryFor($employeeId); $employeeAggregate = employeeAggregate::reconstituteFrom($employeeId, $history);
  • 34. 34 Command Handlers On passe les données à l’agrégat $employeeAggregate->hireEmployee( $command->employeeId, $command->employerId, $command->employeeFirstName, $command->employeeLastName, $command->employeeCivility, $command->employeeJobTitle, $command->employeeEmail, $command->requestedBy, $command->requestedOn );
  • 35. 35 Command Handlers Enregistrement des évènements Dispatch de l’évènement foreach ($events as $event) { $this->eventBus->handle($event); } $events = $this->eventStore->save($employeeAggregate);
  • 36. 36 Agrégats Contient la logique du Domain model Validation sémantique des commandes Reçoit les commandes du MessageBus Emet un ou plusieurs évènements relatant l’opération qu’il vient d’executer ¬ employeeHiredEvent
  • 37. 37 Agrégats Validation des commandes ¬ Un agrégat peut réfuser d’éxécuter une commande - Exemple: › Par exemple, si HRManagementAggregate reçoit la commande HireEmployeeCommand pour une BU donnée, si la BU n’existe pas, il doit renvoyer une exception class HRManagementAggregate { public function hireEmployee($employeeId, $employerId, $employeeFirstName, $employeeLastName) { $this->isBusinessUnitIdValid($employerId); $this->recordThat(new EmployeeHiredEvent($employeeId, $employerId, $employeeFirstName, $employeeLastName)); } private function isBusinessUnitIdValid($businessUnit) { if (!$businessUnit instanceof BusinessUnit) { throw new BusinessUnitIdIsNotValidException('This business Unit is not valid'); } return; } }
  • 38. 38 Domain Events Domain Events ¬ Les évènements métiers produits par les aggrégats ¬ Exemple: - L’évènement EmployeeHiredEvent émis par l’agrégat HRManagementAggregate namespace pathtoAggregatesDomainEvents; class EmployeeHiredEvent { /** * @Type("string") */ private $employeeId; public function __construct($employeeId) { $this->employeeId = $employeeId; } public function getEmployeeId() { return $this->employeeId; } }
  • 39. 39 Bounded context / Récapitulatif Récapitulatif: ¬ On a donc réussi à construire une commande à partir d’une requête venant de l’extérieur ¬ Le command handler s’est chargé de le communiquer à l’agrégat ¬ L’agrégat valide la commande, l’éxécute et génère un évènement ¬ L’évènement est stocké dans l’event store puis dispatché a l’event bus
  • 40. 40 Bounded context / Suite L’évènement peut alors être: ¬ Propagé dans la UI par le biais des denormalizers ¬ Capté par les process managers.
  • 42. 42 Denormalizers Problème ¬ Données pas exploitable pour la UI { "employee_id":"4731ab33-1db8-4570-bc27-e3f4ec0f4feb", "employer_id":"123a3256-2345-1243-a231-a123c1567b12", "employee_first_name":"Jihad", "employee_last_name":"Sahebdin", "employee_civility":"M", "employee_job_title":"Developer", "employee_email":"jihad@sahebdin.com", "requested_by":"f54d197b-9647-47f8-bfa6-d3acedd54556", "requested_on":"20170222 18:40:41 +0400" }
  • 44. 44 Firebase Avantages ¬ L’authentification est gérée ‘in-built’ par Google ¬ Base de données en temps réel ¬ Firebase et Angular JS ¬ Permet de déployer une application (UI) par ligne de commande - > firebase deploy Inconvenients ¬ On fait confiance à Google concernant la securité des données
  • 45. 45 Firebase Utilisation dans symfony ¬ Bundle - https://github.com/ktamas77/firebase-php ¬ Utilisation const DEFAULT_URL = 'https://kidsplace.firebaseio.com/'; const DEFAULT_TOKEN = 'MqL0c8tKCtheLSYcygYNtGhU8Z2hULOFs9OKPdEp'; const DEFAULT_PATH = '/firebase/example'; $firebase = new FirebaseFirebaseLib(DEFAULT_URL, DEFAULT_TOKEN); // --- storing an array --- $test = array( "foo" => "bar", "i_love" => "lamp", "id" => 42 ); $dateTime = new DateTime(); $firebase->set(DEFAULT_PATH . '/' . $dateTime->format('c'), $test);
  • 46. 46 Firebase Utilisation dans symfony ¬ Evènement EmployeeHiredEvent class UpdateEmployeesListDenormalizer { public function notify(EmployeeHiredEvent $event) { $path = '/users/list/'.$event->getEmployeeId(); $firebase->set($path.'/buId', $event->getEmployerId()); $firebase->set($path.'/id', $event->getEmployeeId()); $firebase->set($path.'/civility', $event->getEmployeeCivility()); $firebase->set($path.'/email', $event->getEmployeeEmail()); $firebase->set($path.'/firstname', $event->getEmployeeFirstName()); $firebase->set($path.'/lastname', $event->getEmployeeLastName()); $firebase->set($path.'/job_title', $event->getEmployeeJobTitle()); } }
  • 47. 47 Firebase Utilisation dans symfony ¬ Evènement EmployeeHiredEvent ¬ Service - Un denormalizer va souscrire à l’évènement update_employees_list_denormalizer: class: pathtoDenormalizersUpdateEmployeesListDenormalizer tags: - { name: event_subscriber, subscribes_to: pathtoAggregatesDomainEventsEmployeeHiredEvent, method: notify }
  • 48. 48 Process Managers a.k.a Saga Ecoute des évènements et dispatch de nouvelles commandes Utile pour coordonner les actions entre les bounded contexts Exemple ¬ HRManagement et BusinessUnitManagement ¬ Combien de salariés possède une BU? - Informer l’agrégat BU pour qu’il incrémente/décrémente son nombre de salariés à chaque fois qu’une personne est embauche pour cette BU. - Solution: Création d’un service qui souscrit à l’évènement EmployeeHiredEvent
  • 49. 49 Process Managers Exemple (suite) ¬ ChangeNumberOfEmployeesInBusinessUnitCommand ¬ AddEmployeeToBusinessUnitSaga class changeNumberOfEmployeesInBusinessUnitCommand { public $businessUnitId; } class AddEmployeeToBusinessUnitSaga { public function notify(EmployeeHiredEvent $event) { $command = new changeNumberOfEmployeesInBusinessUnitCommand(); $command->businessUnitId = $event->getEmployerId(); $this->commandBus->handle($command); } }
  • 50. 50 Conclusion Complexe à mettre en oeuvre Difficile à faire en CRUD ¬ Opérations de lecture et d’écriture sont dissosiées ¬ Pas de conflits dans le cas où plusieurs utilisateurs mettent à jour le même objet ¬ Enregistrement des actions et des données sur une entité ¬ Historique des évènements possible ¬ Restauration du read model à partir du write model + Restauration à partir d’un évènement ¬ Séparation de l’implementation plus facile
  • 51. 51 1. Architecture 1. Aperçu 2. Mise en place 3. Bonnes pratiques 4. Sécurité 5. CORS
  • 52. 52 Bonnes pratiques Le nom des méthodes est important ¬ Le nom doit reflécter au maximum l’objectif ce que l’utilisateur veut faire ¬ Exemple: - HireEmployeeCommand - EmployeeHiredEvent - EmployeeLastNameChanged - ContractTransferredToOtherDirectorEvent - RessourceAddedToContractEvent - AccountUpdated / AccountModified Les commandes sont au présent, les évènements sont au passé
  • 53. 53 Bonnes pratiques Un évènement ne peut/doit pas être modifié ¬ Pas de setters dans les classes Event Un évènement est idempotent ¬ Exemple: - FireEmployeeCommand sur une même personne n fois - L’état de l’agrégat ne changera pas après la première fois - L’agrégat de contentera d’ignorer la commande (et ne pas renvoyer d’exception) Valider les commandes
  • 54. 54 Bonnes pratiques Les bounded contexts doivent être identifiés dès le début ¬ Division du problème initial en sous-problèmes (bounded contexts) ¬ Division des bounded contexts en composants autonomes Identifier le langage du domain expert Personne Employé (RH) Ressource (Contrat) Collaborateur (Business Unit)
  • 55. 55 1. Architecture 1. Aperçu 2. Mise en place 3. Bonnes pratiques 4. Sécurité 5. CORS
  • 56. 56 Sécurité Restriction sur la méthode ¬ Autoriser uniquement les POST ¬ MethodListener app.method_listener: class: AppBundleListenerMethodListener arguments: ['POST'] tags: - { name: kernel.event_listener, event: kernel.controller, method: onKernelController, }
  • 57. 57 Sécurité Restriction sur la méthode (suite) ¬ Autoriser uniquement les POST ¬ onKernelController public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); if ($controller[0] instanceof Controller){ $request = $event->getRequest()->getMethod(); if (!in_array($request, $this->method)){ $event->stopPropagation(); throw new MethodNotAllowedHttpException( array('POST'), 'Method Not Allowed‘ ); } } }
  • 58. 58 Sécurité Authentifier les requêtes grâce aux headers d’authentificatiom JWT = Json Web Token ¬ Encodage de la requête et insertion dans le header ¬ Composé de troix parties - header - payload - signature
  • 59. 59 Sécurité / JWT Header ¬ Type ¬ Algorithme de cryptage ¬ Base64 { "typ": "JWT", "alg": "HS256" } eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • 61. 61 Sécurité / JWT Signature ¬ Header ¬ Payload ¬ Crypter en HMAC256 avec un secret var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); HMACSHA256(encodedString, 'secret');
  • 62. 62 Sécurité Côté API ¬ TokenListener ¬ Récupération du header ¬ Décryptage du token app.token.token_listener: class: AppBundleListenerTokenListener arguments: ['@app.token_authenticator'] tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } $header = $request->headers->get('authorization'); try { $decoded = JWT::decode($token, $secret, array('HS256')); } catch (Exception $e) { return Response::HTTP_FORBIDDEN; }
  • 63. 63 Sécurité / Nonce Nonce = Number used ONCE Insertion dans la requête pour l’encodage Vérification de l’unicité du nonce avec les nonces déjà utilisés
  • 64. 64 Sécurité / UUID UUID = Universally Unique Identifier Utilisé comme: ¬ identifiant d’une entité ¬ nonce Version 4 ¬ Génère une uuid aléatoire ¬ 123e4567-e89b-12d3-a456-426655440000
  • 65. 65 1. Architecture 1. Aperçu 2. Mise en place 3. Bonnes pratiques 4. Sécurité 5. CORS
  • 66. 66 Sécurité / CORS Modification de la request ¬ Dans un event listener: onKernelRequest public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if ($request->headers->has("Access-Control-Request-Headers") && $request->headers->has("Access-Control-Request-Method")) { $response = new Response(); //enable CORS - return the requested methods as allowed $response->headers->add( array( 'Access-Control-Allow-Headers' => $request->headers->get("Access- Control-Request-Headers"), 'Access-Control-Allow-Methods' => $request->headers->get("Access- Control-Request-Method"), 'Access-Control-Allow-Origin' => '*')); $event->setResponse($response); }
  • 67. 67 Un mot sur la UI Données stockés sur Firebase ¬ Correspondance entre l’arborescence des données et les urls (pages) de la UI ¬ Utilisation d’un resolve avant le chargement de la page resolve: { listEmployees : function(firebaseService) { return firebaseService.get('/users/list'); },
  • 68. 68 Références Bundles existants ¬ Broadway - https://github.com/broadway/broadway ¬ LiteCqrs - https://github.com/beberlei/litecqrs-php Auteurs ¬ Gregory Young - Simple CQRS example: https://github.com/gregoryyoung/m-r ¬ Matthias Noback - https://php-and-symfony.matthiasnoback.nl/ ¬ Benjamin Eberlei - https://beberlei.de/ ¬ Martin Fowler - https://martinfowler.com/bliki/CQRS.html ¬ Daniel Whittaker - http://danielwhittaker.me/
  • 69. extension interactive 14, avenue des Lataniers 72238 Quatre Bornes Merci

Notes de l'éditeur

  1. Introduction / C’est quoi Avantages / Pourquoi l’utiliser Désavantages / Pourquoi ne pas l’utiliser Utilisation / Quand l’utiliser Case Study par Jihad
  2. CQRS C’est un concept intéressant qui a la responsabilité de séparer la commande et la requête. - Pioneer Greg Young - premier à avoir parlé sur le CQRS Origine CQRS applique le principe CQS, dévéloppé par Bertrand Meyer. Une méthode doit être soit une commande ou une requête
  3. C’est quoi une commande ? Dans un context boutique, on utilise ce mot quand on valide notre commande, par exemple. Dans le context d’un projet Symfony, on lance des commande, par ex. Pour supprimer le cache on lancer un php bin/console cache:clear
  4. Dans le context CQRS, une commande c’est un objet simple avec le nom d’une operation et les données qu’on aura besoin pour effectuer l’opération. A noter que le nom de la commande doit toujours être dans le temps impératif. Ceci montre que l’application peut valider ou refuser la commande. Une commande est aussi connu comme des “mutators” / “modifiers” car cela va modifier l’état d’un système. En comparaison avec l’architecture classqiue, une commande renvoi uniquement les données requises pour traiter la tache tandis que dans le CRUD, on envoie toutes les données de l’objet Ex, openCust….
  5. Quand on parle de requête, très souvent on fait référence aux mots comme SELECT, INSERT, UPDATE, DELETE. Dans le context de CQRS, une requête renvoi des résultats et à aucun moment, la requête peut modifier l’état du système. En comparison avec l’architecture classique, une requête fera uniquement la lecture dans la BdD tandis que dans le CRUD, une requête peut faire toutes les operations (sauvegarde / mise à jour / récupération des informations)
  6. CQRS applique la notion de CQS en utilisant des objets Command et Query séparés pour modifier et récupérer les données respectivement. CQRS utilise un modèle différent pour mettre à jour les informations et un autre modèle pour lire les informations, ce qu’on appelle le Write Model et le Read Model
  7. Voici quelques points forts de ce design pattern : - Performance On gagne plus en performance. En general, on fait plus de lecture dans une BdD que d’écriture. Et souvent des fois, la volumétrie des données renvoyées est conséquente. Du point de vue utilisateur, le temps d’atttente de réponse devrait être minime. Le fait qu’on a dissocié le Read Model permet d’avoir un temps de chargement rapide. Evolution On a plus de flexibilité pour faire évoluer le système
  8. Dans le cas ou on applique CQRS sur un domaine qui ne correspond pas, on rajoute plus de compléxité et de risques et conséquemment cela va réduire la productivité.
  9. Quand peut-on utiliser CQRS ? CQRS sera plus approprié quand on a un système collaboratif ou les utilisateurs peuvent opérer sur les données simultanément Dans le cas ou on a un gros système qui requiert une haute performance Un système complèxe qu’on peut decomposer en plusieurs morceaux autonomes Jihad reviendra la dessus avec plus de détail Un exemple serait un système bancaire. On a beaucoup de transactions, beaucoup de données qui seront impactées et tous les utilisateurs devraient avoir données synchronisées et non des données obsoletes. Un point à faire ressortir, c’est qu’on peut utiliser CQRS dans une partie de notre système et pas necessaire de l’appliquer sur l’ensemble de l’application.
  10. Dans les cas suivants, on evite d’utiliser CQRS
  11. Séparer la Read et la Write Model est un processus couteux en terme de prix et de temps. En terme de cout, l’implementation de CQRS dans un projet doit être égale ou inférieure à celui d’un projet classique Il fauut prendre du temps pour sortir d’un projet classique en CRUD pour y aller sur du Domain Driven Design. Reflechir en tant que domaine et non en tant que BdD est une étape très importante pour faire notre choix et pour ensuite l’appliquer Si on arrive à bien identifier le domain, c’est qu’on peut implementer le CQRS dans notre projet
  12. Event Sourcing par Greg Young Event Sourcing c’est la notion de rejouer les évènements pour arriver à l’état actuel du système. C’est quoi Un Domaine Event : On a effectué une action dans le passé et donc générer un événement. Ex. custAccOpe On peut voir qu’on a segmenté le Select du CRUD dans le Read Model du CQRS Le Insert et Update du CRUD dans le Write Model du CQRS Mais qu’est ce qui se passe pour le Delete du CRUD ??? C’est simple, on ne fait pas de suppression dans le CQRS, c’est une étape supplementaire qui se rajoute.
  13. Pour simplifier, on part donc de 3 bounded context (BU, RH, Contrats) composé chacun d’un seul composant autonome.
  14. Commands : les ordres données au Domain Model CommandHandlers: passe les commandes à l’agrégat L’agrégat valide la sémantique de la commande, l’éxécute et génère un évènement Le denormalizer reconstruit les données à partir des données de l’évènement Le process manager lance de nouvelles commandes à partir d’un évènement
  15. Puisque la requête arrive par un POST sur une url, on définit donc une action dans un controller. ‘command_bus’ est un service qui va faire le lien (en quelques sortes) entre la commande et son handler.
  16. Toute la logique métier du Domain Model doit être traitée au sein des agrégats C’est aux agrégats que les commandHandlers adressent les commandes qu’ils ont reçu du MessageBus
  17. !!!: Pas de setters puisqu’un évènement ne peut pas être modifié, ça s’est produit, on ne peut pas revenir en arrière.
  18. Encoder en base 64