PHP7 e Rich Domain Model
-
Upload
massimiliano-arione -
Category
Technology
-
view
390 -
download
0
Transcript of PHP7 e Rich Domain Model
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.
Mappingclass Giocatore { /* @ORM\ManyToOne(targetEntity=”Squadra”) */ private $squadra; /* @ORM\Column() */ private $nome; /* @ORM\Column(type=”smallint”) */ private $numeroDiMaglia;}
Validazioneclass Giocatore { /* @ORM\ManyToOne(targetEntity=”Squadra”) @AssertNotNull() */ private $squadra; /* @ORM\Column() @Assert\NotBlank() */ private $nome; /* @ORM\Column(type=”smallint”) @Assert\NotNull() @Assert\Type(type=”integer”) @Assert\Range(min=0,max=99 */ private $numeroDiMaglia;}
Formclass 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,
]);
}
}
Settersclass 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;
}
}
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
Formsquadra
nomenumeroDimaglia
Entitysquadra
nomenumeroDimaglia
tablesquadra
nomenumero_di_maglia
Formclass 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,
]);
}
}
Actionpublic 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(),
]);
}
Actionpublic 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 Settersclass Giocatore {
public function __construct(Squadra $squadra, string $nome, int $numero) {
$this->squadra = $squadra;
$this->nome = $nome;
$this->numeroDiMaglia = $numero;
}
// ...
}
Actionpublic 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
Un oggetto definito dai suoi attributi
Due ValueObject sono uguali se i loro attributi sono uguali
NumeroDiMagliaclass 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 ValueObjectclass Giocatore {
/* @ORM\Embedded(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● vincoli interni al dominio● entità meno appiattita sulla persistenza● entità meno accoppiata al framework
Configurazionedoctrine:
orm:
auto_mapping: false
mappings:
Entity:
type: xml
prefix: Sport\Model\Entity
dir: "%kernel.root_dir%/config/doctrine/Entity"
is_bundle: false
ValueObject:
type: xml
prefix: Sport\Model\ValueObject
dir: "%kernel.root_dir%/config/doctrine/ValueObject"
is_bundle: false
What’s next?
● implementare CQRS con CommandBus● plus: i Command sono già pronti (sono i nostri DTO)