Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PHP7 e Rich Domain Model

601 views

Published on

SymfonyDay 2016

Published in: Technology

PHP7 e Rich Domain Model

  1. 1. PHP7 e Rich Domain Model Massimiliano Arione - @garakkio SymfonyDay 2016
  2. 2. about
  3. 3. PHP 7 e Rich Domain Model
  4. 4. PHP 7 e Rich Domain Model Come sono arrivato a Rich Domain Model passando per PHP 7
  5. 5. Non parleremo di... ● quanto è figo PHP 7
  6. 6. Non parleremo di... ● quanto è figo PHP 7 ● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
  7. 7. Non parleremo di... ● quanto è figo PHP 7 ● teoria del Rich Domain Model, pattern e anti-pattern, ecc.
  8. 8. C’era una volta Una classica applicazione Symfony...
  9. 9. Entità class Giocatore { private $squadra; private $nome; private $numeroDiMaglia; }
  10. 10. Mapping class Giocatore { /* @ORMManyToOne(targetEntity=”Squadra”) */ private $squadra; /* @ORMColumn() */ private $nome; /* @ORMColumn(type=”smallint”) */ private $numeroDiMaglia; }
  11. 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. 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. 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. 14. Getters class Giocatore { // ... public function getSquadra() { return $this->squadra; } public function getNome() { return $this->nome; } public function getNumeroDiMaglia() { return $this->numeroDiMaglia; } }
  15. 15. Here comes PHP 7...
  16. 16. Here comes PHP 7... <=>
  17. 17. Here comes PHP 7... ● scalar type hints ● return types
  18. 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. 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. 20. Oops! Fatal error: Uncaught TypeError: Argument 1 passed to setNome() must be an instance of string, null given
  21. 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
  22. 22. Il vero problema Form squadra nome numeroDimaglia Entity squadra nome numeroDimaglia
  23. 23. Il vero problema Form squadra nome numeroDimaglia Entity squadra nome numeroDimaglia table squadra nome numero_di_maglia
  24. 24. DTO class GiocatoreDTO { public $squadra; public $nome; public $numeroDiMaglia; }
  25. 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. 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. 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. 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. 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(), ]); }
  30. 30. ValueObject
  31. 31. ValueObject Un oggetto definito dai suoi attributi
  32. 32. ValueObject Un oggetto definito dai suoi attributi Due ValueObject sono uguali se i loro attributi sono uguali
  33. 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. 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; } // ... }
  35. 35. Vantaggi ● tipo più esplicito
  36. 36. Vantaggi ● tipo più esplicito ● vincoli interni al dominio
  37. 37. Vantaggi ● tipo più esplicito ● vincoli interni al dominio ● entità meno appiattita sulla persistenza
  38. 38. Vantaggi ● tipo più esplicito ● vincoli interni al dominio ● entità meno appiattita sulla persistenza ● entità meno accoppiata al framework
  39. 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
  40. 40. What’s next?
  41. 41. What’s next? ● implementare CQRS con CommandBus
  42. 42. What’s next? ● implementare CQRS con CommandBus ● plus: i Command sono già pronti (sono i nostri DTO)
  43. 43. That’s all!

×