{"id":411799,"date":"2024-06-29T22:10:45","date_gmt":"2024-06-29T22:10:45","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=411799"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=411799","title":{"rendered":"<span>\u041e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u0410\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Doctrine<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e DDD \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0441\u0451 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c. \u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044e \u0441 \u0435\u0451 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c\u0438, \u043f\u043b\u044e\u0441\u0430\u043c\u0438 \u0438 \u043c\u0438\u043d\u0443\u0441\u0430\u043c\u0438. \u042f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0430\u0441\u044c \u043d\u0430\u0448\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0438 \u043d\u0430 PHP, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0438 Data Mapper\u2019\u0430 <a href=\"https:\/\/www.doctrine-project.org\" rel=\"noopener noreferrer nofollow\">Doctrine ORM<\/a>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0434\u043e\u043d\u0435\u0441\u0442\u0438 \u043d\u0430\u0448\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0432\u0441\u0435\u043c  \u0410\u0433\u0440\u0435\u0433\u0430\u0442 \u0417\u0430\u043a\u0430\u0437\u0430 (Order) \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430 (OrderLine), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438 Dortrine ORM. \u0422\u0430\u043a \u0436\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442, \u0447\u0442\u043e\u0431\u044b \u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435. \u0418 \u0442\u0430\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c!<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0448 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u0437\u0430\u043a\u0430\u0437\u0430:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use App\\Shared\\Domain\\AggregateRoot; use Doctrine\\Common\\Collections\\Collection; use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"orders\")  *\/ class Order extends AggregateRoot {     private const STATUS_NEW = 'new';     private const STATUS_CLOSED = 'closed';      \/**      * @ORM\\Id      * @ORM\\Column(type=\"guid\")      *\/     private string $id;     \/**      * @ORM\\Column(type=\"string\")      *\/     private string $status;     \/**      * @var OrderLine[]|Collection      * @ORM\\OneToMany(targetEntity=\"OrderLine\", mappedBy=\"order\", orphanRemoval=true, cascade={\"persist\"})      *\/     private Collection $items;      public function __construct(string $id, Collection $lineItems)     {         if ($lineItems->isEmpty()) {             throw new \\DomainException('\u041f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442.');         }         $this->id = $id;         $this->items = $lineItems;         $this->status = self::STATUS_NEW;     }        public function close(): void     {         $this->status = self::STATUS_CLOSED;     }      public function addLine(Line $line): void     {         $this->items->add(new OrderLine($this, $line));     }      public function getId(): string     {         return $this->id;     }      public function getStatus(): string     {         return $this->status;     }      \/**      * @return OrderLine[]      *\/     public function getItems(): array     {         return $this->items->toArray();     } }<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use Doctrine\\ORM\\Mapping as ORM; use Ramsey\\Uuid\\Uuid;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"order_lines\")  *\/ class OrderLine {     \/**      * @ORM\\Id      * @ORM\\Column(type=\"guid\")      *\/     private string $id;     \/**      * @ORM\\ManyToOne(targetEntity=\"Order\", inversedBy=\"orderLines\")      * @ORM\\JoinColumn(name=\"order_id\")      *\/     private Order $order;     \/**      * @ORM\\Embedded(class=\"Line\")      *\/     private Line $line;      public function __construct(Order $order, Line $line)     {         $this->id = Uuid::uuid4()->toString();         $this->order = $order;         $this->line = $line;     }      public function getId(): string     {         return $this->id;     }      public function getOrder(): Order     {         return $this->order;     }      public function getLine(): Line     {         return $this->line;     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0437\u0430\u043a\u0430\u0437\u0430 \u0432\u044b\u043d\u0435\u0441\u043b\u0438 \u0438\u0437 \u043d\u0435\u0433\u043e Line \u0432 Value Object:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Embeddable  *\/ final class Line {     \/**      * @var string      *      * @ORM\\Column(type=\"string\")      *\/     private $name;     \/**      * @var int      *      * @ORM\\Column(type=\"integer\")      *\/     private $quantity;     \/**      * @ORM\\Column(type=\"float\")      *\/     private $price;      public function __construct(string $name, int $quantity, float $price)     {         $this->name = $name;         $this->quantity = $quantity;         $this->price = $price;     }      public function getQuantity(): int     {         return $this->quantity;     }      public function getName(): string     {         return $this->name;     }      public function getPrice(): float     {         return $this->price;     } }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e \u0432\u0441\u0435\u0445 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430\u0445 \u0432\u043e\u0437\u043d\u0438\u043a\u0448\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u2014 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 <code>AggregateRoot<\/code>:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace Atiline\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateRoot {     \/**      * @var DomainEvent[]      *\/     private array $recordedEvents = [];      abstract public function getId();      protected function recordEvent(DomainEvent $event): void     {         $this->recordedEvents[] = $event;     }      public function releaseEvents(): array     {         $events = $this->recordedEvents;         $this->recordedEvents = [];         return $events;     } }<\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 Data Mapper&#8217;\u0430 \u043c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 <a href=\"https:\/\/www.doctrine-project.org\" rel=\"noopener noreferrer nofollow\">Doctrine ORM<\/a>, \u0430 \u0434\u043b\u044f \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-annotations\/en\/1.13\/index.html\" rel=\"noopener noreferrer nofollow\">Doctrine Annotations<\/a>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 Entity \u0438 Value Object \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438.<\/p>\n<h2>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u0443\u0442\u0435\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0430 \u0438 \u043e\u0442\u043a\u0430\u0442\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. Doctrine <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-orm\/en\/2.9\/reference\/transactions-and-concurrency.html#optimistic-locking\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442<\/a> \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043f\u0443\u0442\u0451\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>$version<\/code> \u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@ORM\\Version<\/code><\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u0432 \u043d\u0430\u0448 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 <code>ArggregateRoot<\/code> \u0438 \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@ORM\\MappedSuperclass<\/code> \u0447\u0442\u043e\u0431\u044b Doctrine \u0441\u043c\u043e\u0433\u043b\u0430 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u043e\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435.<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateRoot {     \/**      * @ORM\\Version      * @ORM\\Column(type=\"integer\")      *\/     protected int $version;          \/\/.... }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0438\u0445. \u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0437\u0430\u043a\u0430\u0437, \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0437\u0430\u043a\u0430\u0437 \u0438 \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0437\u0430\u043a\u0430\u0437.<\/p>\n<pre><code class=\"php\">&lt;?php  final class OrderTestController extends AbstractController {     public function createAndClose(EntityManagerInterface $em): Response     {         \/\/ \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0437\u0430\u043a\u0430\u0437         $order = new Order('09597988-aa74-4bb3-9fb9-0e154dd7cdec');         $em->persist($order);         $em->flush();          \/\/ \u0417\u0430\u043a\u0437\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043a\u0430\u0437         $order = $em->getRepository(Order::class)->find('09597988-aa74-4bb3-9fb9-0e154dd7cdec');         $order->close();         $em->flush();                return $this->json([], 201);     } }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043c\u044b \u0432\u044b\u0437\u043e\u0432\u0435\u043c <code>$order->close()<\/code> \u043d\u0430\u0448 \u0437\u0430\u043a\u0430\u0437 \u0441\u043c\u0435\u043d\u0438\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \u043d\u0430 <em>closed<\/em>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0432\u0435\u0440\u0441\u0438\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 <em>version, <\/em>\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u0441\u044f \u043d\u0430 +1. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0443 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0437\u0430\u043a\u0430\u0437\u0430 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>$order->addLine($line)<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u0448 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043d\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u043b \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0435 \u043d\u0430 +1, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c-\u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0430\u0441\u044c. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0439 \u0441\u0430\u043c\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u2014 \u043e\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c-\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u2014 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 +1.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Doctrine \u0432 \u043d\u0430\u0434\u0435\u0436\u0434\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0430\u0441 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c.<\/p>\n<p>\u041f\u043e\u0447\u0438\u0442\u0430\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, Doctrine <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-orm\/en\/2.9\/cookbook\/aggregate-fields.html#using-an-aggregate-field\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442<\/a> \u043f\u043e\u0439\u0442\u0438 \u043f\u0443\u0442\u0451\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u0432 \u0437\u0430\u043a\u0430\u0437\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c: <\/p>\n<ol>\n<li>\n<p>\u0412\u0441\u0435\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u0442\u044c \u0440\u0438\u0441\u043a \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u043c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0435 \u043d\u0430\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f. \u041c\u044b \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u043c\u0438, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437.<\/p>\n<h2>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 Doctrine \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0442\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0451 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u043c\u0435\u043b\u043e \u0431\u044b \u0434\u0430\u043d\u043d\u043e\u0435 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0438 \u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0432\u0432\u0435\u0434\u0451\u043c \u043d\u043e\u0432\u044b\u0439 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 AggregateEntity, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0438\u043c\u0438 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0441\u0442\u044b\u043c, \u043d\u043e \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateEntity { }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043a \u043a\u0430\u043a\u043e\u043c\u0443 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0443 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0439\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438, \u043d\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0439\u0442\u0438 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0438\u043c &#8212; \u0447\u0435\u0440\u0435\u0437 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Domain;  \/**  * @Annotation  * @Target(\"CLASS\")  *\/ final class AggregateEntityAnnotation {     \/**      * Method for getting the Aggregated Root      *\/     public string $methodAggregateRoot; }<\/code><\/pre>\n<p>\u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0430\u043d\u043d\u0443\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u043a \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 <code>OrderLine<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u0435\u0451 \u043e\u0442 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>AggegateEntity<\/code> :<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);   namespace App\\Order;  use App\\Shared\\Domain\\AggregateEntity; use App\\Shared\\Domain\\AggregateEntityAnnotation; use Doctrine\\ORM\\Mapping as ORM; use Ramsey\\Uuid\\Uuid;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"order_lines\")  * @AggregateEntityAnnotation(methodAggregateRoot=\"getOrder\")  *\/ class OrderLine extends AggregateEntity {    ...            \/**      * @ORM\\ManyToOne(targetEntity=\"Order\", inversedBy=\"items\")      * @ORM\\JoinColumn(name=\"order_id\")      *\/     private Order $order;       ...      public function getOrder(): Order     {         return $this->order;     }      ... }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448\u0435 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>$aggregateVersion<\/code> \u0432 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 <code>AggregateRoot<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>updateAggregateVersion()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u043e\u043b\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441 \u043f\u043e\u043b\u0435\u043c <code>version<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0439 Doctrine. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u044e\u0449\u0435\u0435\u0441\u044f \u043d\u0430 +1:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateRoot extends AggregateEntity {     \/**      * @ORM\\Column(type=\"integer\", options={\"default\" : 1})      *\/     protected int $aggregateVersion = 1;        ...            public function updateAggregateVersion(): void     {         $this->aggregateVersion++;     } } <\/code><\/pre>\n<p>\u041d\u0430\u043c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430\u0448\u0443 \u0432\u0435\u0440\u0441\u0438\u044e. \u0417\u0430\u0439\u043c\u0451\u043c\u0441\u044f \u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Doctrine;  use App\\Shared\\Domain\\AggregateEntity; use App\\Shared\\Domain\\AggregateEntityAnnotation; use App\\Shared\\Domain\\AggregateRootEntity; use Doctrine\\Common\\Annotations\\Reader; use Doctrine\\ORM\\EntityManagerInterface; use LogicException; use ReflectionClass;  final class DoctrineAggregateVersioning {     private Reader $reader;      public function __construct(Reader $reader)     {         $this->reader = $reader;     }      public function update(EntityManagerInterface $em, AggregateEntity ...$entities): void     {         $aggregateRoot = $this->getAggregateRoot($entities);          if (!$em->contains($aggregateRoot)) {             $em->persist($aggregateRoot);         }        \/\/\u0418\u0437\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430         $aggregateRoot->updateAggregateVersion();          $uow = $em->getUnitOfWork();         $classMetadata = $em->getClassMetadata(get_class($aggregateRoot));       \/\/\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f         $uow->recomputeSingleEntityChangeSet($classMetadata, $aggregateRoot);     }      \/**      * @param AggregateEntity[] $entities      * @return AggregateRootEntity      *\/     private function getAggregateRoot(array $entities): AggregateRootEntity     {         $aggregateRoot = null;          \/\/\u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u0430\u0433\u0440\u0435\u0433\u0430\u0442         foreach ($entities as $entity) {             if ($entity instanceof AggregateRootEntity) {                 $aggregateRoot = $entity;             }         }        \/\/\u0415\u0441\u043b\u0438 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043d\u0435 \u043d\u0430\u0448\u0451\u043b\u0441\u044f, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0435\u0433\u043e \u0438\u0437 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438         if ($aggregateRoot === null) {             $aggregateEntity = end($entities);             $annotation = $this->getAggregateEntityAnnotation($aggregateEntity);              if (!method_exists($aggregateEntity, $annotation->methodAggregateRoot)) {                 throw new LogicException(sprintf('Method \"%s\" not exists in class \"%s\".',                     $annotation->methodAggregateRoot,                     $aggregateEntity::class                 ));             }              $aggregateRoot = $aggregateEntity->{$annotation->methodAggregateRoot}();         }          return $aggregateRoot;     }      private function getAggregateEntityAnnotation(AggregateEntity $entity): AggregateEntityAnnotation     {         $reflectionClass = new ReflectionClass($entity);          if (!$annotation = $this->reader->getClassAnnotation($reflectionClass, AggregateEntityAnnotation::class)) {             throw new LogicException(sprintf('Aggregate \"%s\" must have AggregateEntityAnnotation!', $entity::class));         }          return $annotation;     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043d\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b. \u0412\u043d\u0435\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f <code>onFlush<\/code>.<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Infrastructure\\Doctrine\\Listener;  use App\\Shared\\Doctrine\\DoctrineAggregateVersioning; use App\\Shared\\Domain\\AggregateEntity; use Doctrine\\Bundle\\DoctrineBundle\\EventSubscriber\\EventSubscriberInterface; use Doctrine\\ORM\\Event\\OnFlushEventArgs; use Doctrine\\ORM\\Events;  final class DoctrineAggregateVersioningSubscriber implements EventSubscriberInterface {     private DoctrineAggregateVersioning $aggregateVersioning;      public function __construct(DoctrineAggregateVersioning $aggregateVersioning)     {         $this->aggregateVersioning = $aggregateVersioning;     }      public function getSubscribedEvents(): array     {         return [             Events::onFlush,         ];     }      public function onFlush(OnFlushEventArgs $args): void     {         $em = $args->getEntityManager();         $uow = $em->getUnitOfWork();          \/\/\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438         $entities = array_merge(             $uow->getScheduledEntityInsertions(),             $uow->getScheduledEntityUpdates(),             $uow->getScheduledEntityDeletions()         );      \/\/\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438         $aggregateEntities = [];         foreach ($entities as $entity) {             if ($entity instanceof AggregateEntity) {                 $aggregateEntities[] = $entity;             }         }          if (empty($aggregateEntities)) {             return;         }        \/\/\u0418\u0437\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0435\u0440\u0441\u0438\u044e         $this->aggregateVersioning->update($em, ...$aggregateEntities);     } }<\/code><\/pre>\n<h2>\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>\u0414\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u044b \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u043e\u043a\u043e\u043b\u043e 2-\u0445 \u0434\u043d\u0435\u0439, \u043e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0438 \u043d\u0430\u0439\u0442\u0438 \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u043d\u0430\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0448\u043b\u0438 \u043a \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c\u0443. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u0438, \u0432 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u0442\u0435\u043f\u0435\u043d\u0438, \u00ab\u043a\u043e\u0441\u0442\u044b\u043b\u044c\u043d\u043e\u0435\u00bb. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0432 \u043d\u0430\u0434\u0435\u0436\u0434\u0435 \u043f\u0440\u0438\u0434\u0442\u0438 \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e\u043c\u0443 \u0440\u0435\u0448\u0435\u043d\u0438\u044e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430 \u0425\u0430\u0431\u0440. \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0445\u043e\u0440\u043e\u0448\u0438\u043c, \u0442\u043e \u043e\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u043c. \u0410 \u043c\u044b, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0433\u043e\u0442\u043e\u0432\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043a\u0430\u043a \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443.<\/p>\n<p>\u0410\u0432\u0442\u043e\u0440\u044b:<\/p>\n<div class=\"persona\" persona=\"true\"><img persona=\"true\" class=\"image persona__image\"\/><\/p>\n<h5 class=\"persona__heading\" persona=\"true\">\u0412\u043e\u0440\u043e\u0436\u0446\u043e\u0432 \u041c\u0430\u043a\u0441\u0438\u043c<\/h5>\n<p persona=\"true\" class=\"persona__text\">PHP Developer<\/p>\n<\/div>\n<div class=\"persona\" persona=\"true\"><img persona=\"true\" class=\"image persona__image\"\/><\/p>\n<h5 class=\"persona__heading\" persona=\"true\">\u0417\u0430\u0445\u0430\u0440\u043e\u0432 \u0418\u043b\u044c\u044f<\/h5>\n<p persona=\"true\" class=\"persona__text\">PHP Developer<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/590471\/\"> https:\/\/habr.com\/ru\/articles\/590471\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e DDD \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0441\u0451 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c. \u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044e \u0441 \u0435\u0451 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c\u0438, \u043f\u043b\u044e\u0441\u0430\u043c\u0438 \u0438 \u043c\u0438\u043d\u0443\u0441\u0430\u043c\u0438. \u042f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0430\u0441\u044c \u043d\u0430\u0448\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0438 \u043d\u0430 PHP, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0438 Data Mapper\u2019\u0430 <a href=\"https:\/\/www.doctrine-project.org\" rel=\"noopener noreferrer nofollow\">Doctrine ORM<\/a>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0434\u043e\u043d\u0435\u0441\u0442\u0438 \u043d\u0430\u0448\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0432\u0441\u0435\u043c  \u0410\u0433\u0440\u0435\u0433\u0430\u0442 \u0417\u0430\u043a\u0430\u0437\u0430 (Order) \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430 (OrderLine), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438 Dortrine ORM. \u0422\u0430\u043a \u0436\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442, \u0447\u0442\u043e\u0431\u044b \u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0430\u043c\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435. \u0418 \u0442\u0430\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c!<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0448 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u0437\u0430\u043a\u0430\u0437\u0430:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use App\\Shared\\Domain\\AggregateRoot; use Doctrine\\Common\\Collections\\Collection; use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"orders\")  *\/ class Order extends AggregateRoot {     private const STATUS_NEW = 'new';     private const STATUS_CLOSED = 'closed';      \/**      * @ORM\\Id      * @ORM\\Column(type=\"guid\")      *\/     private string $id;     \/**      * @ORM\\Column(type=\"string\")      *\/     private string $status;     \/**      * @var OrderLine[]|Collection      * @ORM\\OneToMany(targetEntity=\"OrderLine\", mappedBy=\"order\", orphanRemoval=true, cascade={\"persist\"})      *\/     private Collection $items;      public function __construct(string $id, Collection $lineItems)     {         if ($lineItems->isEmpty()) {             throw new \\DomainException('\u041f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442.');         }         $this->id = $id;         $this->items = $lineItems;         $this->status = self::STATUS_NEW;     }        public function close(): void     {         $this->status = self::STATUS_CLOSED;     }      public function addLine(Line $line): void     {         $this->items->add(new OrderLine($this, $line));     }      public function getId(): string     {         return $this->id;     }      public function getStatus(): string     {         return $this->status;     }      \/**      * @return OrderLine[]      *\/     public function getItems(): array     {         return $this->items->toArray();     } }<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u0430\u043a\u0430\u0437\u0430:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use Doctrine\\ORM\\Mapping as ORM; use Ramsey\\Uuid\\Uuid;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"order_lines\")  *\/ class OrderLine {     \/**      * @ORM\\Id      * @ORM\\Column(type=\"guid\")      *\/     private string $id;     \/**      * @ORM\\ManyToOne(targetEntity=\"Order\", inversedBy=\"orderLines\")      * @ORM\\JoinColumn(name=\"order_id\")      *\/     private Order $order;     \/**      * @ORM\\Embedded(class=\"Line\")      *\/     private Line $line;      public function __construct(Order $order, Line $line)     {         $this->id = Uuid::uuid4()->toString();         $this->order = $order;         $this->line = $line;     }      public function getId(): string     {         return $this->id;     }      public function getOrder(): Order     {         return $this->order;     }      public function getLine(): Line     {         return $this->line;     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0437\u0430\u043a\u0430\u0437\u0430 \u0432\u044b\u043d\u0435\u0441\u043b\u0438 \u0438\u0437 \u043d\u0435\u0433\u043e Line \u0432 Value Object:<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Order;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Embeddable  *\/ final class Line {     \/**      * @var string      *      * @ORM\\Column(type=\"string\")      *\/     private $name;     \/**      * @var int      *      * @ORM\\Column(type=\"integer\")      *\/     private $quantity;     \/**      * @ORM\\Column(type=\"float\")      *\/     private $price;      public function __construct(string $name, int $quantity, float $price)     {         $this->name = $name;         $this->quantity = $quantity;         $this->price = $price;     }      public function getQuantity(): int     {         return $this->quantity;     }      public function getName(): string     {         return $this->name;     }      public function getPrice(): float     {         return $this->price;     } }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e \u0432\u0441\u0435\u0445 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430\u0445 \u0432\u043e\u0437\u043d\u0438\u043a\u0448\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u2014 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 <code>AggregateRoot<\/code>:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace Atiline\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateRoot {     \/**      * @var DomainEvent[]      *\/     private array $recordedEvents = [];      abstract public function getId();      protected function recordEvent(DomainEvent $event): void     {         $this->recordedEvents[] = $event;     }      public function releaseEvents(): array     {         $events = $this->recordedEvents;         $this->recordedEvents = [];         return $events;     } }<\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 Data Mapper&#8217;\u0430 \u043c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 <a href=\"https:\/\/www.doctrine-project.org\" rel=\"noopener noreferrer nofollow\">Doctrine ORM<\/a>, \u0430 \u0434\u043b\u044f \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-annotations\/en\/1.13\/index.html\" rel=\"noopener noreferrer nofollow\">Doctrine Annotations<\/a>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 Entity \u0438 Value Object \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438.<\/p>\n<h2>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u0443\u0442\u0435\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0430 \u0438 \u043e\u0442\u043a\u0430\u0442\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. Doctrine <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-orm\/en\/2.9\/reference\/transactions-and-concurrency.html#optimistic-locking\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442<\/a> \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043f\u0443\u0442\u0451\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>$version<\/code> \u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@ORM\\Version<\/code><\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u0432 \u043d\u0430\u0448 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 <code>ArggregateRoot<\/code> \u0438 \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@ORM\\MappedSuperclass<\/code> \u0447\u0442\u043e\u0431\u044b Doctrine \u0441\u043c\u043e\u0433\u043b\u0430 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u043e\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435.<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateRoot {     \/**      * @ORM\\Version      * @ORM\\Column(type=\"integer\")      *\/     protected int $version;          \/\/.... }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0438\u0445. \u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0437\u0430\u043a\u0430\u0437, \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0437\u0430\u043a\u0430\u0437 \u0438 \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0437\u0430\u043a\u0430\u0437.<\/p>\n<pre><code class=\"php\">&lt;?php  final class OrderTestController extends AbstractController {     public function createAndClose(EntityManagerInterface $em): Response     {         \/\/ \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0437\u0430\u043a\u0430\u0437         $order = new Order('09597988-aa74-4bb3-9fb9-0e154dd7cdec');         $em->persist($order);         $em->flush();          \/\/ \u0417\u0430\u043a\u0437\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043a\u0430\u0437         $order = $em->getRepository(Order::class)->find('09597988-aa74-4bb3-9fb9-0e154dd7cdec');         $order->close();         $em->flush();                return $this->json([], 201);     } }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043c\u044b \u0432\u044b\u0437\u043e\u0432\u0435\u043c <code>$order->close()<\/code> \u043d\u0430\u0448 \u0437\u0430\u043a\u0430\u0437 \u0441\u043c\u0435\u043d\u0438\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \u043d\u0430 <em>closed<\/em>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0432\u0435\u0440\u0441\u0438\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 <em>version, <\/em>\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u0441\u044f \u043d\u0430 +1. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0443 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0437\u0430\u043a\u0430\u0437\u0430 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>$order->addLine($line)<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u0448 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043d\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u043b \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0435 \u043d\u0430 +1, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c-\u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0430\u0441\u044c. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0435\u0439 \u0441\u0430\u043c\u043e\u0433\u043e \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u2014 \u043e\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c-\u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u2014 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 +1.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Doctrine \u0432 \u043d\u0430\u0434\u0435\u0436\u0434\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0430\u0441 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c.<\/p>\n<p>\u041f\u043e\u0447\u0438\u0442\u0430\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, Doctrine <a href=\"https:\/\/www.doctrine-project.org\/projects\/doctrine-orm\/en\/2.9\/cookbook\/aggregate-fields.html#using-an-aggregate-field\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442<\/a> \u043f\u043e\u0439\u0442\u0438 \u043f\u0443\u0442\u0451\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u0430\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u0432 \u0437\u0430\u043a\u0430\u0437\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c: <\/p>\n<ol>\n<li>\n<p>\u0412\u0441\u0435\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u0442\u044c \u0440\u0438\u0441\u043a \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u043c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0435 \u043d\u0430\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f. \u041c\u044b \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u043c\u0438, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437.<\/p>\n<h2>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 Doctrine \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0442\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0451 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u043c\u0435\u043b\u043e \u0431\u044b \u0434\u0430\u043d\u043d\u043e\u0435 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0438 \u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0432\u0432\u0435\u0434\u0451\u043c \u043d\u043e\u0432\u044b\u0439 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 AggregateEntity, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0438\u043c\u0438 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0441\u0442\u044b\u043c, \u043d\u043e \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);  namespace App\\Shared\\Domain;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\MappedSuperclass  *\/ abstract class AggregateEntity { }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043a \u043a\u0430\u043a\u043e\u043c\u0443 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0443 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0439\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438, \u043d\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u0439\u0442\u0438 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0438\u043c &#8212; \u0447\u0435\u0440\u0435\u0437 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442:<\/p>\n<pre><code class=\"php\">&lt;?php  declare(strict_types=1);  namespace App\\Shared\\Domain;  \/**  * @Annotation  * @Target(\"CLASS\")  *\/ final class AggregateEntityAnnotation {     \/**      * Method for getting the Aggregated Root      *\/     public string $methodAggregateRoot; }<\/code><\/pre>\n<p>\u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0430\u043d\u043d\u0443\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u043a \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 <code>OrderLine<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u0435\u0451 \u043e\u0442 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>AggegateEntity<\/code> :<\/p>\n<pre><code class=\"php\">&lt;?php declare(strict_types=1);   namespace App\\Order;  use App\\Shared\\Domain\\AggregateEntity; use App\\Shared\\Domain\\AggregateEntityAnnotation; use Doctrine\\ORM\\Mapping as ORM; use Ramsey\\Uuid\\Uuid;  \/**  * @ORM\\Entity  * @ORM\\Table(name=\"order_lines\")  * @AggregateEntityAnnotation(methodAggregateRoot=\"getOrder\")  *\/ class OrderLine extends AggregateEntity {    ...            \/**      * @ORM\\ManyToOne(targetEntity=\"Order\", inversedBy=\"items\")      * @ORM\\JoinColumn(name=\"order_id\")      *\/     private Order $order;       ...      public function getOrder(): Order     {         return $this->order;     }      ... }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448\u0435 \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>$aggregateVersion<\/code> \u0432 \u0441\u0443\u043f\u0435\u0440 \u043a\u043b\u0430\u0441\u0441 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 <code>AggregateRoot<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>updateAggregateVersion()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u043e\u043b\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441 \u043f\u043e\u043b\u0435\u043c <code>version<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0439<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-411799","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/411799","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=411799"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/411799\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=411799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=411799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=411799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}