PraktykiImplementacji
ValueObjectów


Kuba Werłos

Wiele osób wierzy, że stosuje DDD,
ponieważ jeden z katalogów nazwali „Domain”.

Jeśli używamy powszechnie znanego konceptu,
to przestrzegajmy jego zasad.


                    <?php
                    final class Person
                    {
                        public float $height;
                        public float $weight;
                    }
                
Lego
int $dayOfMonth

   42
float $distance

-1.5
string $forenameX Æ A-12

                    $ php -a
                    Interactive shell

                    php > var_export(0.1 + 0.2 === 0.3);

                    bool(false)
                

                    $ php -a
                    Interactive shell

                    php > var_dump(0.1 + 0.2);

                    float(0.30000000000000004)
                

0.30000000000000004.com

Value Object to jeden z najważniejszych
elementów Domain-Driven Design.


Value Object może być używany
bez korzystania z Domain-Driven Design.

Value object


  • zmierzona/wyliczona/opisana wartość
  • pieniądze
  • zakres dat
  • identyfikator
  • imię
  • nazwisko
  • adres

Value object


  • zmierzona/wyliczona/opisana wartość
  • poprawność

poprawność



                    <?php

                    $point = new Point();
                    // invalid state
                    $point->x = 2;
                    $point->y = 3;
                

poprawność




                    <?php

                    $point = new Point(2, 3);
                

Value object


  • zmierzona/wyliczona/opisana wartość
  • poprawność
  • brak tożsamości

brak tożsamości



                    <?php
                    final class DateRange
                    {
                        public function __construct(
                            public string $uuid,
                            public DateTimeInterface $from,
                            public DateTimeInterface $to,
                        ) {}
                    }
                

brak tożsamości



                    <?php
                    final class DateRange
                    {
                        public function __construct(
                            public DateTimeInterface $from,
                            public DateTimeInterface $to,
                        ) {}
                    }
                

Value object


  • zmierzona/wyliczona/opisana wartość
  • poprawność
  • brak tożsamości
  • równość opiera się na równości stanów

równość stanów



                    <?php

                    $name1 = new Name('Alex');
                    $name2 = new Name('Alex');

                    assert($name1 === $name2); // false
                

równość stanów



                    <?php

                    $name1 = new Name('Alex');
                    $name2 = new Name('Alex');

                    assert($name1 == $name2); // true

                    assert($name1->equals($name2)); // true
                

Value object


  • zmierzona/wyliczona/opisana wartość
  • poprawność
  • brak tożsamości
  • równość opiera się na równości stanów
  • niezmienność

niezmienność



                    <?php

                    $point = new Point(2, 3);

                    $point->setX(4);

                    echo $point->toString();
                    // (x: 4, y: 3)
                

niezmienność



                    <?php

                    $point = new Point(2, 3);

                    $new = $point->setX(4);

                    echo $point->toString();
                    // (x: 2, y: 3)
                    echo $new->toString();
                    // (x: 4, y: 3)
                

niezmienność




                    <?php

                    $point = new Point(2, 3);
                    $point->__construct(7, 8);
                

niezmienność



                    <?php

                    readonly class Point
                    {
                        public function __construct(
                            public int $x,
                            public int $y,
                        ) {}
                    }
                

niezmienność



                    <?php
                    class Point
                    {
                        public static function create(int $x, int $y)
                        {
                            return new self($x, $y);
                        }

                        private function __construct(
                            public int $x,
                            public int $y,
                        ) {}
                    }
                

Named Constructors in PHP

When to Use Static Methods

Value object


  • zmierzona/wyliczona/opisana wartość
  • poprawność
  • brak tożsamości
  • równość opiera się na równości stanów
  • niezmienność
  • ma reguły i zachowania

reguły



                    <?php

                    $dateRange = new DateRange(
                        new DateTime('today'),
                        new DateTime('yesterday'),
                    );

                    // Exception: start cannot be after end
                

zachowania



                    <?php

                    $dateRange = new DateRange($d1, $d2);

                    echo $dateRange->isShorterThanWeek();

                    // true / false
                

Entity vs Value Object

  • tożsamość
  • zasady równości
  • niezmienność

Zapisywanie


                    <?php

                    #[Embeddable]
                    class Address
                    {
                        #[Column(type: 'string')]
                        private string $street;

                        #[Column(type: 'string')]
                        private string $city;

                        #[Column(type: 'string')]
                        private string $country;
                    }
                

Zapisywanie


                    <?php

                    #[Entity]
                    class User
                    {
                        #[ORM\Id]
                        #[ORM\Column(type: 'uuid', unique: true)]
                        #[ORM\GeneratedValue(strategy: 'CUSTOM')]
                        #[ORM\CustomIdGenerator(class: UuidGenerator::class)]
                        private UuidInterface $id;

                        #[Embedded(class: Address::class)]
                        public Address $address;
                    }
                

Zapisywanie


                    <?php

                    $user = $repository->findOneBy(['address.country' => 'PL']);

                    $user->address = new Address(
                        'Podwale 37/38',
                        'Wrocław',
                        'PL',
                    );
                

Pytania?

Dziękuję za uwagę


werlos@gmail.com


GitHubkubawerlosGitter

https://kubawerlos.github.io/slides