SlideShare a Scribd company logo
PHP7 e Rich Domain Model
Massimiliano Arione - @garakkio
SymfonyDay 2016
about
PHP 7 e Rich Domain Model
PHP 7 e Rich Domain Model
Come sono arrivato a Rich Domain Model passando
per PHP 7
Non parleremo di...
● quanto è figo PHP 7
Non parleremo di...
● quanto è figo PHP 7
● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
Non parleremo di...
● quanto è figo PHP 7
● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
C’era una volta
Una classica applicazione Symfony...
Entità
class Giocatore {
private $squadra;
private $nome;
private $numeroDiMaglia;
}
Mapping
class Giocatore {
/* @ORMManyToOne(targetEntity=”Squadra”) */
private $squadra;
/* @ORMColumn() */
private $nome;
/* @ORMColumn(type=”smallint”) */
private $numeroDiMaglia;
}
Validazione
class Giocatore {
/* @ORMManyToOne(targetEntity=”Squadra”)
@AssertNotNull() */
private $squadra;
/* @ORMColumn()
@AssertNotBlank() */
private $nome;
/* @ORMColumn(type=”smallint”)
@AssertNotNull()
@AssertType(type=”integer”)
@AssertRange(min=0,max=99 */
private $numeroDiMaglia;
}
Form
class GiocatoreType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('squadra')
->add('nome')
->add('numeroDiMaglia', IntegerType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => Giocatore::class,
]);
}
}
Setters
class Giocatore {
public function setSquadra(Squadra $squadra) {
$this->squadra = $squadra;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function setNumeroDiMaglia($numero) {
$this->numeroDiMaglia = $numero;
}
// ...
}
Getters
class Giocatore {
// ...
public function getSquadra() {
return $this->squadra;
}
public function getNome() {
return $this->nome;
}
public function getNumeroDiMaglia() {
return $this->numeroDiMaglia;
}
}
Here comes PHP 7...
Here comes PHP 7...
<=>
Here comes PHP 7...
● scalar type hints
● return types
Setters (tipizzati)
class Giocatore {
public function setSquadra(Squadra $squadra) {
$this->squadra = $squadra;
}
public function setNome(string $nome) {
$this->nome = $nome;
}
public function setNumeroDiMaglia(int $numero) {
$this->numeroDiMaglia = $numero;
}
// ...
}
Getters (tipizzati)
class Giocatore {
// ...
public function getSquadra(): Squadra {
return $this->squadra;
}
public function getNome(): string {
return $this->nome;
}
public function getNumeroDiMaglia(): int {
return $this->numeroDiMaglia;
}
}
Oops!
Fatal error: Uncaught TypeError: Argument 1 passed to
setNome() must be an instance of string, null given
Oops2
!
Fatal error: Uncaught TypeError: Argument 1 passed to
setNome() must be an instance of string, null given
Fatal error: Uncaught TypeError: Return value of getNome()
must be an instance of string, null returned
Il vero problema
Form
squadra
nome
numeroDimaglia
Entity
squadra
nome
numeroDimaglia
Il vero problema
Form
squadra
nome
numeroDimaglia
Entity
squadra
nome
numeroDimaglia
table
squadra
nome
numero_di_maglia
DTO
class GiocatoreDTO {
public $squadra;
public $nome;
public $numeroDiMaglia;
}
Form
class GiocatoreType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('squadra')
->add('nome')
->add('numeroDiMaglia', IntegerType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => GiocatoreDTO::class,
]);
}
}
Action
public function nuovoAction(Request $request) {
$giocatore = new Giocatore();
$form = $this->createForm(GiocatoreType::class, $giocatore);
if ($form->handleRequest($request)->isValid()) {
$this->getDoctrine()->getManager()->persist($giocatore);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('giocatori');
}
return $this->render('giocatore/nuovo.html.twig', [
'form' => $form->createView(),
]);
}
Action
public function nuovoAction(Request $request)
{
$dto = new GiocatoreDTO();
$form = $this->createForm(GiocatoreType::class, $dto);
if ($form->handleRequest($request)->isValid()) {
$giocatore = new Giocatore();
// ...
$this->getDoctrine()->getManager()->persist($giocatore);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('giocatori');
}
return $this->render('giocatore/nuovo.html.twig', [
'form' => $form->createView(),
]);
}
No more Setters
class Giocatore {
public function __construct(Squadra $squadra, string $nome, int $numero) {
$this->squadra = $squadra;
$this->nome = $nome;
$this->numeroDiMaglia = $numero;
}
// ...
}
Action
public function nuovoAction(Request $request) {
$dto = new GiocatoreDTO();
$form = $this->createForm(GiocatoreType::class, $dto);
if ($form->handleRequest($request)->isValid()) {
$giocatore = new Giocatore($dto->squadra, $dto->nome, $dto->numeroDiMaglia);
$this->getDoctrine()->getManager()->persist($giocatore);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('giocatori');
}
return $this->render('giocatore/nuovo.html.twig', [
'form' => $form->createView(),
]);
}
ValueObject
ValueObject
Un oggetto definito dai suoi attributi
ValueObject
Un oggetto definito dai suoi attributi
Due ValueObject sono uguali se i loro attributi sono uguali
NumeroDiMaglia
class NumeroDimaglia() {
private $numero;
public function __construct(int $numero) {
if ($numero < 0 || $numero > 99) {
throw new DomainException('Il numero deve esere tra 0 e 99');
}
$this->numero = $numero;
}
public function __toString() {
return (string) $this->numero;
}
}
Entity con ValueObject
class Giocatore {
/* @ORMEmbedded(class=”NumeroDimaglia”) */
private $numeroDiMaglia;
public function __construct(
Squadra $squadra,
string $nome,
NumeroDiMaglia $numero
) {
$this->squadra = $squadra;
$this->nome = $nome;
$this->numeroDiMaglia = $numero;
}
// ...
}
Vantaggi
● tipo più esplicito
Vantaggi
● tipo più esplicito
● vincoli interni al dominio
Vantaggi
● tipo più esplicito
● vincoli interni al dominio
● entità meno appiattita sulla persistenza
Vantaggi
● tipo più esplicito
● vincoli interni al dominio
● entità meno appiattita sulla persistenza
● entità meno accoppiata al framework
Configurazione
doctrine:
orm:
auto_mapping: false
mappings:
Entity:
type: xml
prefix: SportModelEntity
dir: "%kernel.root_dir%/config/doctrine/Entity"
is_bundle: false
ValueObject:
type: xml
prefix: SportModelValueObject
dir: "%kernel.root_dir%/config/doctrine/ValueObject"
is_bundle: false
What’s next?
What’s next?
● implementare CQRS con CommandBus
What’s next?
● implementare CQRS con CommandBus
● plus: i Command sono già pronti (sono i nostri DTO)
That’s all!

More Related Content

Viewers also liked

A new way to develop with WordPress!
A new way to develop with WordPress!A new way to develop with WordPress!
A new way to develop with WordPress!
David Sanchez
 
PHP7 Presentation
PHP7 PresentationPHP7 Presentation
PHP7 Presentation
David Sanchez
 
Migrating to php7
Migrating to php7Migrating to php7
Migrating to php7
Richard Prillwitz
 
PHP7 is coming
PHP7 is comingPHP7 is coming
PHP7 is coming
julien pauli
 
PHP 7
PHP 7PHP 7
reveal.js 3.0.0
reveal.js 3.0.0reveal.js 3.0.0
reveal.js 3.0.0
Hakim El Hattab
 
Creating HTML Pages
Creating HTML PagesCreating HTML Pages
Creating HTML Pages
Mike Crabb
 
Top Insights from SaaStr by Leading Enterprise Software Experts
Top Insights from SaaStr by Leading Enterprise Software ExpertsTop Insights from SaaStr by Leading Enterprise Software Experts
Top Insights from SaaStr by Leading Enterprise Software Experts
OpenView
 
Test Automation - Principles and Practices
Test Automation - Principles and PracticesTest Automation - Principles and Practices
Test Automation - Principles and Practices
Anand Bagmar
 
CSS Grid Layout for Topconf, Linz
CSS Grid Layout for Topconf, LinzCSS Grid Layout for Topconf, Linz
CSS Grid Layout for Topconf, Linz
Rachel Andrew
 
New Amazing Things about AngularJS 2.0
New Amazing Things about AngularJS 2.0New Amazing Things about AngularJS 2.0
New Amazing Things about AngularJS 2.0
Mike Taylor
 
Node.js and The Internet of Things
Node.js and The Internet of ThingsNode.js and The Internet of Things
Node.js and The Internet of Things
Losant
 
The Future of Real-Time in Spark
The Future of Real-Time in SparkThe Future of Real-Time in Spark
The Future of Real-Time in Spark
Reynold Xin
 
Introduction to Information Architecture
Introduction to Information ArchitectureIntroduction to Information Architecture
Introduction to Information Architecture
Mike Crabb
 
Testing at Spotify
Testing at SpotifyTesting at Spotify
Testing at Spotify
Andrii Dzynia
 
Launching a Rocketship Off Someone Else's Back
Launching a Rocketship Off Someone Else's BackLaunching a Rocketship Off Someone Else's Back
Launching a Rocketship Off Someone Else's Back
joshelman
 
Nine Pages You Should Optimize on Your Blog and How
Nine Pages You Should Optimize on Your Blog and HowNine Pages You Should Optimize on Your Blog and How
Nine Pages You Should Optimize on Your Blog and How
Leslie Samuel
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
kenbot
 
Introduction to Development for the Internet
Introduction to Development for the InternetIntroduction to Development for the Internet
Introduction to Development for the Internet
Mike Crabb
 

Viewers also liked (19)

A new way to develop with WordPress!
A new way to develop with WordPress!A new way to develop with WordPress!
A new way to develop with WordPress!
 
PHP7 Presentation
PHP7 PresentationPHP7 Presentation
PHP7 Presentation
 
Migrating to php7
Migrating to php7Migrating to php7
Migrating to php7
 
PHP7 is coming
PHP7 is comingPHP7 is coming
PHP7 is coming
 
PHP 7
PHP 7PHP 7
PHP 7
 
reveal.js 3.0.0
reveal.js 3.0.0reveal.js 3.0.0
reveal.js 3.0.0
 
Creating HTML Pages
Creating HTML PagesCreating HTML Pages
Creating HTML Pages
 
Top Insights from SaaStr by Leading Enterprise Software Experts
Top Insights from SaaStr by Leading Enterprise Software ExpertsTop Insights from SaaStr by Leading Enterprise Software Experts
Top Insights from SaaStr by Leading Enterprise Software Experts
 
Test Automation - Principles and Practices
Test Automation - Principles and PracticesTest Automation - Principles and Practices
Test Automation - Principles and Practices
 
CSS Grid Layout for Topconf, Linz
CSS Grid Layout for Topconf, LinzCSS Grid Layout for Topconf, Linz
CSS Grid Layout for Topconf, Linz
 
New Amazing Things about AngularJS 2.0
New Amazing Things about AngularJS 2.0New Amazing Things about AngularJS 2.0
New Amazing Things about AngularJS 2.0
 
Node.js and The Internet of Things
Node.js and The Internet of ThingsNode.js and The Internet of Things
Node.js and The Internet of Things
 
The Future of Real-Time in Spark
The Future of Real-Time in SparkThe Future of Real-Time in Spark
The Future of Real-Time in Spark
 
Introduction to Information Architecture
Introduction to Information ArchitectureIntroduction to Information Architecture
Introduction to Information Architecture
 
Testing at Spotify
Testing at SpotifyTesting at Spotify
Testing at Spotify
 
Launching a Rocketship Off Someone Else's Back
Launching a Rocketship Off Someone Else's BackLaunching a Rocketship Off Someone Else's Back
Launching a Rocketship Off Someone Else's Back
 
Nine Pages You Should Optimize on Your Blog and How
Nine Pages You Should Optimize on Your Blog and HowNine Pages You Should Optimize on Your Blog and How
Nine Pages You Should Optimize on Your Blog and How
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
 
Introduction to Development for the Internet
Introduction to Development for the InternetIntroduction to Development for the Internet
Introduction to Development for the Internet
 

Similar to PHP7 e Rich Domain Model

PHP Template Engine (introduzione)
PHP Template Engine (introduzione)PHP Template Engine (introduzione)
PHP Template Engine (introduzione)
Asmir Mustafic
 
Acadevmy - TypeScript Overview
Acadevmy - TypeScript OverviewAcadevmy - TypeScript Overview
Acadevmy - TypeScript Overview
Francesco Sciuti
 
Case study: un approccio modulare in un progetto legacy
Case study: un approccio modulare in un progetto legacyCase study: un approccio modulare in un progetto legacy
Case study: un approccio modulare in un progetto legacy
Mariano Fiorentino
 
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
Codemotion
 
Gianfrasoft Corso Di Php Parte 2
Gianfrasoft   Corso Di Php   Parte 2Gianfrasoft   Corso Di Php   Parte 2
Gianfrasoft Corso Di Php Parte 2Gianfranco Fedele
 
Web Performance Optimization
Web Performance OptimizationWeb Performance Optimization
Web Performance Optimization
Alessandro Martin
 
Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)
Davide Cerbo
 
Javascript
JavascriptJavascript
Entity Framework 6 for developers, Code-First!
Entity Framework 6 for developers, Code-First!Entity Framework 6 for developers, Code-First!
Entity Framework 6 for developers, Code-First!
Michael Denny
 
Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1
Steve Maraspin
 
(My) Best Practices in Symfony
(My) Best Practices in Symfony(My) Best Practices in Symfony
(My) Best Practices in Symfony
inmarelibero
 
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...Francesco Cirillo
 
Write less do more...with jQuery
Write less do more...with jQueryWrite less do more...with jQuery
Write less do more...with jQuery
XeDotNet
 
Luca Masini: Introduzione a GWT 2.0
Luca Masini: Introduzione a GWT 2.0Luca Masini: Introduzione a GWT 2.0
Luca Masini: Introduzione a GWT 2.0
firenze-gtug
 
Funzioni anonime in PHP 5.3
Funzioni anonime in PHP 5.3Funzioni anonime in PHP 5.3
Funzioni anonime in PHP 5.3
Zend by Rogue Wave Software
 
JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)jampslide
 
Hexagonal architecture ita
Hexagonal architecture itaHexagonal architecture ita
Hexagonal architecture ita
Alessandro Minoccheri
 
jQuery e i suoi plugin
jQuery e i suoi pluginjQuery e i suoi plugin
jQuery e i suoi plugin
Pasquale Puzio
 
Django
DjangoDjango
Django
GDG Bologna
 

Similar to PHP7 e Rich Domain Model (20)

PHP Template Engine (introduzione)
PHP Template Engine (introduzione)PHP Template Engine (introduzione)
PHP Template Engine (introduzione)
 
Acadevmy - TypeScript Overview
Acadevmy - TypeScript OverviewAcadevmy - TypeScript Overview
Acadevmy - TypeScript Overview
 
Case study: un approccio modulare in un progetto legacy
Case study: un approccio modulare in un progetto legacyCase study: un approccio modulare in un progetto legacy
Case study: un approccio modulare in un progetto legacy
 
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
Enrico Zimuel - PUG Milano meetup - Codemotion Milan 2017
 
Gianfrasoft Corso Di Php Parte 2
Gianfrasoft   Corso Di Php   Parte 2Gianfrasoft   Corso Di Php   Parte 2
Gianfrasoft Corso Di Php Parte 2
 
Web Performance Optimization
Web Performance OptimizationWeb Performance Optimization
Web Performance Optimization
 
Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)
 
Javascript
JavascriptJavascript
Javascript
 
Entity Framework 6 for developers, Code-First!
Entity Framework 6 for developers, Code-First!Entity Framework 6 for developers, Code-First!
Entity Framework 6 for developers, Code-First!
 
Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1
 
(My) Best Practices in Symfony
(My) Best Practices in Symfony(My) Best Practices in Symfony
(My) Best Practices in Symfony
 
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...
20050621 Ridurre il Costo del Cambiamento Applicando il Design Object Oriente...
 
Write less do more...with jQuery
Write less do more...with jQueryWrite less do more...with jQuery
Write less do more...with jQuery
 
Luca Masini: Introduzione a GWT 2.0
Luca Masini: Introduzione a GWT 2.0Luca Masini: Introduzione a GWT 2.0
Luca Masini: Introduzione a GWT 2.0
 
Pillole di C++
Pillole di C++Pillole di C++
Pillole di C++
 
Funzioni anonime in PHP 5.3
Funzioni anonime in PHP 5.3Funzioni anonime in PHP 5.3
Funzioni anonime in PHP 5.3
 
JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)
 
Hexagonal architecture ita
Hexagonal architecture itaHexagonal architecture ita
Hexagonal architecture ita
 
jQuery e i suoi plugin
jQuery e i suoi pluginjQuery e i suoi plugin
jQuery e i suoi plugin
 
Django
DjangoDjango
Django
 

More from Massimiliano Arione

Typed models pug roma febbraio 2020
Typed models   pug roma febbraio 2020Typed models   pug roma febbraio 2020
Typed models pug roma febbraio 2020
Massimiliano Arione
 
Pipelines!
Pipelines! Pipelines!
Pipelines!
Massimiliano Arione
 
Il nostro amico Stan
Il nostro amico Stan   Il nostro amico Stan
Il nostro amico Stan
Massimiliano Arione
 
PSR7 - interoperabilità HTTP
PSR7 - interoperabilità HTTPPSR7 - interoperabilità HTTP
PSR7 - interoperabilità HTTP
Massimiliano Arione
 
Disinstallare fos user bundle e vivere felici
Disinstallare fos user bundle e vivere feliciDisinstallare fos user bundle e vivere felici
Disinstallare fos user bundle e vivere felici
Massimiliano Arione
 
MAGA - PUG Roma giugno 2017
MAGA - PUG Roma giugno 2017MAGA - PUG Roma giugno 2017
MAGA - PUG Roma giugno 2017
Massimiliano Arione
 
PHP on the desktop
PHP on the desktopPHP on the desktop
PHP on the desktop
Massimiliano Arione
 
Scrivere e leggere log con elastic
Scrivere e leggere log con elasticScrivere e leggere log con elastic
Scrivere e leggere log con elastic
Massimiliano Arione
 
The metrics
The metricsThe metrics
The metrics
Massimiliano Arione
 
Managing frontend libs in your Symfony project
Managing frontend libs in your Symfony projectManaging frontend libs in your Symfony project
Managing frontend libs in your Symfony project
Massimiliano Arione
 
Translating symfony docs
Translating symfony docsTranslating symfony docs
Translating symfony docs
Massimiliano Arione
 
Managing frontend libs in your php project
Managing frontend libs in your php projectManaging frontend libs in your php project
Managing frontend libs in your php project
Massimiliano Arione
 
Gestire librerie di frontend in php
Gestire librerie di frontend in phpGestire librerie di frontend in php
Gestire librerie di frontend in php
Massimiliano Arione
 
PHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggioPHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggio
Massimiliano Arione
 
Gestione delle dipendenze con Composer
Gestione delle dipendenze con ComposerGestione delle dipendenze con Composer
Gestione delle dipendenze con Composer
Massimiliano Arione
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
Massimiliano Arione
 
Case study OmniAuto.it
Case study OmniAuto.itCase study OmniAuto.it
Case study OmniAuto.it
Massimiliano Arione
 
Symfony: un framework per il web
Symfony: un framework per il webSymfony: un framework per il web
Symfony: un framework per il web
Massimiliano Arione
 
Paypal + symfony
Paypal + symfonyPaypal + symfony
Paypal + symfony
Massimiliano Arione
 
Sviluppo rapido di applicazioni con PHP
Sviluppo rapido di applicazioni con PHPSviluppo rapido di applicazioni con PHP
Sviluppo rapido di applicazioni con PHP
Massimiliano Arione
 

More from Massimiliano Arione (20)

Typed models pug roma febbraio 2020
Typed models   pug roma febbraio 2020Typed models   pug roma febbraio 2020
Typed models pug roma febbraio 2020
 
Pipelines!
Pipelines! Pipelines!
Pipelines!
 
Il nostro amico Stan
Il nostro amico Stan   Il nostro amico Stan
Il nostro amico Stan
 
PSR7 - interoperabilità HTTP
PSR7 - interoperabilità HTTPPSR7 - interoperabilità HTTP
PSR7 - interoperabilità HTTP
 
Disinstallare fos user bundle e vivere felici
Disinstallare fos user bundle e vivere feliciDisinstallare fos user bundle e vivere felici
Disinstallare fos user bundle e vivere felici
 
MAGA - PUG Roma giugno 2017
MAGA - PUG Roma giugno 2017MAGA - PUG Roma giugno 2017
MAGA - PUG Roma giugno 2017
 
PHP on the desktop
PHP on the desktopPHP on the desktop
PHP on the desktop
 
Scrivere e leggere log con elastic
Scrivere e leggere log con elasticScrivere e leggere log con elastic
Scrivere e leggere log con elastic
 
The metrics
The metricsThe metrics
The metrics
 
Managing frontend libs in your Symfony project
Managing frontend libs in your Symfony projectManaging frontend libs in your Symfony project
Managing frontend libs in your Symfony project
 
Translating symfony docs
Translating symfony docsTranslating symfony docs
Translating symfony docs
 
Managing frontend libs in your php project
Managing frontend libs in your php projectManaging frontend libs in your php project
Managing frontend libs in your php project
 
Gestire librerie di frontend in php
Gestire librerie di frontend in phpGestire librerie di frontend in php
Gestire librerie di frontend in php
 
PHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggioPHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggio
 
Gestione delle dipendenze con Composer
Gestione delle dipendenze con ComposerGestione delle dipendenze con Composer
Gestione delle dipendenze con Composer
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Case study OmniAuto.it
Case study OmniAuto.itCase study OmniAuto.it
Case study OmniAuto.it
 
Symfony: un framework per il web
Symfony: un framework per il webSymfony: un framework per il web
Symfony: un framework per il web
 
Paypal + symfony
Paypal + symfonyPaypal + symfony
Paypal + symfony
 
Sviluppo rapido di applicazioni con PHP
Sviluppo rapido di applicazioni con PHPSviluppo rapido di applicazioni con PHP
Sviluppo rapido di applicazioni con PHP
 

PHP7 e Rich Domain Model

  • 1. PHP7 e Rich Domain Model Massimiliano Arione - @garakkio SymfonyDay 2016
  • 3. PHP 7 e Rich Domain Model
  • 4. PHP 7 e Rich Domain Model Come sono arrivato a Rich Domain Model passando per PHP 7
  • 5. Non parleremo di... ● quanto è figo PHP 7
  • 6. Non parleremo di... ● quanto è figo PHP 7 ● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
  • 7. Non parleremo di... ● quanto è figo PHP 7 ● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
  • 8. C’era una volta Una classica applicazione Symfony...
  • 9. Entità class Giocatore { private $squadra; private $nome; private $numeroDiMaglia; }
  • 10. Mapping class Giocatore { /* @ORMManyToOne(targetEntity=”Squadra”) */ private $squadra; /* @ORMColumn() */ private $nome; /* @ORMColumn(type=”smallint”) */ private $numeroDiMaglia; }
  • 11. Validazione class Giocatore { /* @ORMManyToOne(targetEntity=”Squadra”) @AssertNotNull() */ private $squadra; /* @ORMColumn() @AssertNotBlank() */ private $nome; /* @ORMColumn(type=”smallint”) @AssertNotNull() @AssertType(type=”integer”) @AssertRange(min=0,max=99 */ private $numeroDiMaglia; }
  • 12. Form class GiocatoreType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('squadra') ->add('nome') ->add('numeroDiMaglia', IntegerType::class) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Giocatore::class, ]); } }
  • 13. Setters class Giocatore { public function setSquadra(Squadra $squadra) { $this->squadra = $squadra; } public function setNome($nome) { $this->nome = $nome; } public function setNumeroDiMaglia($numero) { $this->numeroDiMaglia = $numero; } // ... }
  • 14. Getters class Giocatore { // ... public function getSquadra() { return $this->squadra; } public function getNome() { return $this->nome; } public function getNumeroDiMaglia() { return $this->numeroDiMaglia; } }
  • 16. Here comes PHP 7... <=>
  • 17. Here comes PHP 7... ● scalar type hints ● return types
  • 18. Setters (tipizzati) class Giocatore { public function setSquadra(Squadra $squadra) { $this->squadra = $squadra; } public function setNome(string $nome) { $this->nome = $nome; } public function setNumeroDiMaglia(int $numero) { $this->numeroDiMaglia = $numero; } // ... }
  • 19. Getters (tipizzati) class Giocatore { // ... public function getSquadra(): Squadra { return $this->squadra; } public function getNome(): string { return $this->nome; } public function getNumeroDiMaglia(): int { return $this->numeroDiMaglia; } }
  • 20. Oops! Fatal error: Uncaught TypeError: Argument 1 passed to setNome() must be an instance of string, null given
  • 21. Oops2 ! Fatal error: Uncaught TypeError: Argument 1 passed to setNome() must be an instance of string, null given Fatal error: Uncaught TypeError: Return value of getNome() must be an instance of string, null returned
  • 24. DTO class GiocatoreDTO { public $squadra; public $nome; public $numeroDiMaglia; }
  • 25. Form class GiocatoreType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('squadra') ->add('nome') ->add('numeroDiMaglia', IntegerType::class) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => GiocatoreDTO::class, ]); } }
  • 26. Action public function nuovoAction(Request $request) { $giocatore = new Giocatore(); $form = $this->createForm(GiocatoreType::class, $giocatore); if ($form->handleRequest($request)->isValid()) { $this->getDoctrine()->getManager()->persist($giocatore); $this->getDoctrine()->getManager()->flush(); return $this->redirectToRoute('giocatori'); } return $this->render('giocatore/nuovo.html.twig', [ 'form' => $form->createView(), ]); }
  • 27. Action public function nuovoAction(Request $request) { $dto = new GiocatoreDTO(); $form = $this->createForm(GiocatoreType::class, $dto); if ($form->handleRequest($request)->isValid()) { $giocatore = new Giocatore(); // ... $this->getDoctrine()->getManager()->persist($giocatore); $this->getDoctrine()->getManager()->flush(); return $this->redirectToRoute('giocatori'); } return $this->render('giocatore/nuovo.html.twig', [ 'form' => $form->createView(), ]); }
  • 28. No more Setters class Giocatore { public function __construct(Squadra $squadra, string $nome, int $numero) { $this->squadra = $squadra; $this->nome = $nome; $this->numeroDiMaglia = $numero; } // ... }
  • 29. Action public function nuovoAction(Request $request) { $dto = new GiocatoreDTO(); $form = $this->createForm(GiocatoreType::class, $dto); if ($form->handleRequest($request)->isValid()) { $giocatore = new Giocatore($dto->squadra, $dto->nome, $dto->numeroDiMaglia); $this->getDoctrine()->getManager()->persist($giocatore); $this->getDoctrine()->getManager()->flush(); return $this->redirectToRoute('giocatori'); } return $this->render('giocatore/nuovo.html.twig', [ 'form' => $form->createView(), ]); }
  • 31. ValueObject Un oggetto definito dai suoi attributi
  • 32. ValueObject Un oggetto definito dai suoi attributi Due ValueObject sono uguali se i loro attributi sono uguali
  • 33. NumeroDiMaglia class NumeroDimaglia() { private $numero; public function __construct(int $numero) { if ($numero < 0 || $numero > 99) { throw new DomainException('Il numero deve esere tra 0 e 99'); } $this->numero = $numero; } public function __toString() { return (string) $this->numero; } }
  • 34. Entity con ValueObject class Giocatore { /* @ORMEmbedded(class=”NumeroDimaglia”) */ private $numeroDiMaglia; public function __construct( Squadra $squadra, string $nome, NumeroDiMaglia $numero ) { $this->squadra = $squadra; $this->nome = $nome; $this->numeroDiMaglia = $numero; } // ... }
  • 36. Vantaggi ● tipo più esplicito ● vincoli interni al dominio
  • 37. Vantaggi ● tipo più esplicito ● vincoli interni al dominio ● entità meno appiattita sulla persistenza
  • 38. Vantaggi ● tipo più esplicito ● vincoli interni al dominio ● entità meno appiattita sulla persistenza ● entità meno accoppiata al framework
  • 39. Configurazione doctrine: orm: auto_mapping: false mappings: Entity: type: xml prefix: SportModelEntity dir: "%kernel.root_dir%/config/doctrine/Entity" is_bundle: false ValueObject: type: xml prefix: SportModelValueObject dir: "%kernel.root_dir%/config/doctrine/ValueObject" is_bundle: false
  • 41. What’s next? ● implementare CQRS con CommandBus
  • 42. What’s next? ● implementare CQRS con CommandBus ● plus: i Command sono già pronti (sono i nostri DTO)