Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Patterns Behind Doctrine (Prototype Slides)

Patterns Behind Doctrine (Prototype Slides)

This is the earliest version of my talk about the internal workings of Doctrine ORM and how they relate to your code when using it. I mostly explain things inside the Unit Of Work, e.g. Object Hashes, Change Sets and Commit Order. The live demo showcasing fetch modes and query optimization is not included and the gifs are missing as well (sorry).

Please keep in mind that this is kind of a sneak preview based on the ground work for the "actual" talk and the final slides will look nothing like this. I figured it might be interesting for people to see how the slides will evolve over time.

Denis Brumann

November 28, 2018
Tweet

More Decks by Denis Brumann

Other Decks in Programming

Transcript

  1. /** @ORM\Entity() */ class Order { /** * @ORM\Id() *

    @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\OneToMany(targetEntity="App\Entity\OrderItem", mappedBy="order") */ private $items; /** * @ORM\Column(type="datetime_immutable") */ private $createdOn; }
  2. /** @ORM\Entity() */ class OrderItem { /** * @ORM\Id() *

    @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\ManyToOne(targetEntity="App\Entity\Order", inversedBy="items") * @ORM\JoinColumn(nullable=false) */ private $order; /** @ORM\Column() */ private $name; /** @ORM\Column(length=16) */ private $price; }
  3. /** @ORM\Entity() */ class OrderItem { /** * @ORM\Id() *

    @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\ManyToOne(targetEntity="App\Entity\Order", inversedBy="items") * @ORM\JoinColumn(nullable=false) */ private $order; /** @ORM\Column() */ private $name; /** @ORM\Column(length=16) */ private $price; }
  4. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  5. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  6. Unit Of Work A Unit of Work keeps track of

    everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.
  7. You usually do not directly interact with a UnitOfWork but

    with the EntityManager instead. Unit Of Work
  8. Unit Of Work What changes to write in what order.

    Identity Map Change Sets Cascading Operations (Persist, Delete, ...) Associations Commit Order
  9. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  10. $oid = spl_object_hash($entity) This function returns a unique identifier for

    the object. This id can be used as a hash key for storing objects, or for identifying an object, as long as the object is not destroyed. Once the object is destroyed, its hash may be reused for other objects.
  11. $item1 = new OrderItem(); $item1->setName('Socks'); $item1->setPrice('999'); $item2 = new OrderItem();

    $item2->setName('Socks'); $item2->setPrice('999'); $manager->persist($item1); $manager->persist($item2);
  12. Change Sets Computes all the changes that have been done

    to entities and collections since the last commit and stores these changes in the $entityChangeSet map temporarily for access by the persisters, until the UoW commit is finished.
  13. Entities will be persisted, when they are part of the

    Change Set, i.e. we explicitly persisted them, or when they are part of a cascaded association.
  14. /** @ORM\Entity() */ class Order { /** * @ORM\Id() *

    @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\OneToMany(..., cascade={"persist"}) */ private $items; /** * @ORM\Column(type="datetime_immutable") */ private $createdOn; }
  15. { "00000000085bc321000000004502eb13": { "createdOn": [
 null,
 {
 "date": "2018-12-20 20:49:32.824391",


    "timezone_type": 3,
 "timezone": "Europe\/Berlin"
 }
 ] }, "00000000085bc37e000000004502eb13": { "status": [null, 0], "name": [null, "Chewing gums"], "price": [null, "249"], "order": [null, {App\Entity\Order}] } }
  16. { "00000000085bc321000000004502eb13": { "createdOn": [
 null,
 {
 "date": "2018-12-20 20:49:32.824391",


    "timezone_type": 3,
 "timezone": "Europe\/Berlin"
 }
 ] }, "00000000085bc37e000000004502eb13": { "status": [null, 0], "name": [null, "Chewing gums"], "price": [null, "249"], "order": [null, {App\Entity\Order}] } } Order OrderItem
  17. Entity States A NEW entity instance has no persistent identity,

    and is not yet associated with an EntityManager and a UnitOfWork (i.e. those just created with the "new" operator).
  18. Entity States /** * An entity is new if it

    has just been instantiated (i.e. using the "new" operator) * and is not (yet) managed by an EntityManager. */ const STATE_NEW = 2;
  19. Entity States A MANAGED entity instance is an instance with

    a persistent identity that is associated with an EntityManager and whose persistence is thus managed.
  20. Entity States /** * An entity is in MANAGED state

    when its persistence is managed by an EntityManager. */ const STATE_MANAGED = 1;
  21. Entity States A DETACHED entity instance is an instance with

    a persistent identity that is not (or no longer) associated with an EntityManager and a UnitOfWork.
  22. Entity States /** * A detached entity is an instance

    with persistent state and identity that is not * (or no longer) associated with an EntityManager (and a UnitOfWork). */ const STATE_DETACHED = 3;
  23. Entity States A REMOVED entity instance is an instance with

    a persistent identity, associated with an EntityManager, that will be removed from the database upon transaction commit.
  24. Entity States /** * A removed entity instance is an

    instance with a persistent identity, * associated with an EntityManager, whose persistent state will be deleted * on commit. */ const STATE_REMOVED = 4;
  25. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  26. Only entities managed by the Unit Of Work will be

    inserted/updated/ deleted during flush
  27. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  28. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  29. $item = new OrderItem(); $item->setName('Socks'); $item->setPrice('999'); $manager->persist($item); $order = new

    Order(); $order->addItem($item); $manager->persist($order); $manager->flush();
  30. Doctrine will take care of correctly ordering each commit. You

    can persist your entities in any order you like.
  31. New entities either have to be persisted manually or through

    cascaded associations. An ID does not mean the entity is managed by Doctrine. Operations can be ordered by domain logic, rather than persistence logic. Doctrine will figure out the correct order for insert (update or delete).