What to expect when Doctrine 3 comes out

6a1345d8e6dd15b2c78eff0c331963b1?s=47 Denis Brumann
September 13, 2019

What to expect when Doctrine 3 comes out

Doctrine ORM is probably the most used database abstraction in PHP. With Doctrine 3 on the horizon it's a perfect time to look at how Doctrine has changed and will change and what this means for you as users. This talk looks at some of the already merged features for Doctrine 3 that could have an impact on your code and why the might prevent you from upgrading. I will show approaches for tackling these changes and how your projects might benefit from introducing them already.

6a1345d8e6dd15b2c78eff0c331963b1?s=128

Denis Brumann

September 13, 2019
Tweet

Transcript

  1. 5.

    WHAT I WILL COVER… WHAT HAS CHANGED? HOW HAS IT

    CHANGED? HOW TO ADAPT FOR THE CHANGE? @dbrumann / denis.brumann@sensiolabs.de 5
  2. 9.

    ROADMAP MAPPING UUID GENERATOR NAMED QUERIES NAMESPACE ALIASES PROXY OBJECTS

    CLASS METADATA ENTITY MANAGER SECOND LEVEL CACHE @dbrumann / denis.brumann@sensiolabs.de 10
  3. 14.

    YAML-MAPPING IS DEPRECATED IN 2.6 WILL BE REMOVED IN DOCTRINE

    3 SYMFONY BEST PRACTICES: ANNOTATIONS @dbrumann / denis.brumann@sensiolabs.de 15
  4. 18.

    /** @ORM\Entity */ class Customer { /** * @ORM\Id *

    @ORM\Column(type="guid") * @ORM\GeneratedValue(strategy="UUID") */ private $id; … @dbrumann / denis.brumann@sensiolabs.de 19
  5. 20.

    /** @ORM\Entity */ class Customer { /** * @ORM\Id *

    @ORM\Column(type="uuid") * @ORM\GeneratedValue(strategy="NONE") */ private $id; public function __construct() { $this->id = Uuid::uuid4(); } public function getId(): string { return (string) $this->id; } @dbrumann / denis.brumann@sensiolabs.de 21
  6. 21.

    WILL BE REMOVED IN DOCTRINE 3 USE UUID-LIB (E.G. RAMSEY/UUID)

    + NONE-GENERATOR UUID GENERATOR @dbrumann / denis.brumann@sensiolabs.de 22
  7. 23.

    24

  8. 24.

    25

  9. 25.

    class AddressController extends AbstractController { public function index(EntityManagerInterface $entityManager): Response

    { $repository = $entityManager->getRepository(Address::class); $addresses = $repository->createNativeNamedQuery('findAll') ->getResult(); return $this->render('addresses/index.html.twig', [ 'addresses' => $addresses, ]); } } @dbrumann / denis.brumann@sensiolabs.de 26
  10. 26.

    LIST OF REMOVED CLASSES Doctrine\ORM\Mapping\ NamedQueries NamedQuery NamedNativeQuery ColumnResult FieldResult

    EntityResult SqlResultSetMappings SqlResultSetMapping @dbrumann / denis.brumann@sensiolabs.de 27
  11. 28.

    WORKS FOR NOW WILL BE REMOVED IN DOCTRINE 3 MOVE

    LOGIC (E.G. TO REPOSITORY) NAMED QUERIES @dbrumann / denis.brumann@sensiolabs.de 29
  12. 33.

    POPULAR IN SYMFONY APPS < 3.x WILL BE REMOVED IN

    DOCTRINE 3! USE FULLY QUALIFIED CLASS NAME ::CLASS NAMESPACE ALIASES @dbrumann / denis.brumann@sensiolabs.de 34
  13. 35.

    /** @ORM\Entity(…) */ class Customer { … /** * @ORM\OneToMany(targetEntity="App\Entity\Address",

    mappedBy="customer") */ private $addresses; … public function getAddresses() { return this->addresses; } } @dbrumann / denis.brumann@sensiolabs.de 36
  14. 40.

    A proxy object is an object that is put in

    place or used instead of the "real" object. A proxy object can add behavior to the object being proxied without that object being aware of it. In Doctrine 2, proxy objects are used to realize several features but mainly for transparent lazy-loading. https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/advanced-configuration.html#proxy-objects PROXY OBJECTS @dbrumann / denis.brumann@sensiolabs.de 41
  15. 42.

    <?php namespace Proxies\__CG__\App\Entity; /** * DO NOT EDIT THIS FILE

    - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR */ class Order extends \App\Entity\Order implements \Doctrine\ORM\Proxy\Proxy { /** * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with * three parameters, being respectively the proxy object to be initialized, the method that triggered the * initialization process and an array of ordered parameters that were passed to that method. * * @see \Doctrine\Common\Persistence\Proxy::__setInitializer */ public $__initializer__; /** * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object * * @see \Doctrine\Common\Persistence\Proxy::__setCloner */ public $__cloner__; /** * @var boolean flag indicating if this object was already initialized * * @see \Doctrine\Common\Persistence\Proxy::__isInitialized */ public $__isInitialized__ = false; /** * @var array properties to be lazy loaded, with keys being the property * names and values being their default values * * @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties */ 43
  16. 43.

    /** * * @return array */ public function __sleep() {

    if ($this->__isInitialized__) { return ['__isInitialized__', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'id', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'items', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'createdOn']; } return ['__isInitialized__', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'id', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'items', '' . "\0" . 'App\\Entity\\Order' . "\0" . 'createdOn']; } /** * */ public function __wakeup() { if ( ! $this->__isInitialized__) { $this->__initializer__ = function (Order $proxy) { $proxy->__setInitializer(null); $proxy->__setCloner(null); $existingProperties = get_object_vars($proxy); foreach ($proxy->__getLazyProperties() as $property => $defaultValue) { if ( ! array_key_exists($property, $existingProperties)) { $proxy->$property = $defaultValue; } } }; } } /** * */ 44
  17. 44.

    WILL BE REPLACED WITH PROXYMANAGER-LIB (HOPEFULLY) NO CODE CHANGES ON

    YOUR PART PROXY OBJECTS @dbrumann / denis.brumann@sensiolabs.de 45
  18. 45.

    NO MORE FATAL ERRORS DUE TO MISSING PROXY CLASSES PROXY

    OBJECTS @dbrumann / denis.brumann@sensiolabs.de 46
  19. 46.

    final METHODS ARE NOW ALLOWED __clone NO LONGER CALLED BY

    ORM __wakeup NO LONGER CALLED BY ORM serialize() ⚠ RECURSIVE INITIALIZATION ACCESSING PRIVATE STATE WITH REFLECTION TRIGGERS LAZY-LOADING LAZY LOADING @dbrumann / denis.brumann@sensiolabs.de 47
  20. 49.

    Quoting is now always called. Implement your own Doctrine\ORM\Mapping\NamingStrategy to

    manipulate your schema, tables and column names to your custom desired naming convention. @dbrumann / denis.brumann@sensiolabs.de 50
  21. 50.

    LOTS MORE CHANGES AROUND CLASSMETADATA MOSTLY REORGANIZATION AND RENAMING CLASS

    METADATA @dbrumann / denis.brumann@sensiolabs.de 52
  22. 55.

    FLUSH() CAN BE COSTLY DATA INTEGRITY BUGS FLUSHING A SINGLE

    ENTITY @dbrumann / denis.brumann@sensiolabs.de 57
  23. 56.

    USE ENTITYMANAGER::CLEAR() MORE OFTEN USE EXPLICIT CHANGE TRACKING POLICIES @dbrumann

    / denis.brumann@sensiolabs.de 58 FLUSHING A SINGLE ENTITY
  24. 59.

    NO ALTERNATIVE PROVIDED SHOULD BE PART OF YOUR BUSINESS DOMAIN

    MERGE @dbrumann / denis.brumann@sensiolabs.de 61
  25. 61.

    The Second Level Cache is designed to reduce the amount

    of necessary database access. It sits between your application and the database to avoid the number of database hits as much as possible. SECOND LEVEL CACHE @dbrumann / denis.brumann@sensiolabs.de 63
  26. 62.

    The second level cache functionality is marked as experimental for

    now. It is a very complex feature and we cannot guarantee yet that it works stable in all cases. SECOND LEVEL CACHE @dbrumann / denis.brumann@sensiolabs.de 64
  27. 64.

    COMPONENTS QUERY CACHE CACHED ENTITY PERSISTER CACHED COLLECTION PERSISTER ENTITY

    HYDRATOR COLLECTION HYDRATOR CACHE FACTORY @dbrumann / denis.brumann@sensiolabs.de 66
  28. 65.

    DATA IS STORED IN DIFFERENT CACHE REGIONS EACH REGION HAS

    SPECIFIC NAMESPACE AND LIFETIME CACHE FOR QUERIES/COLLECTIONS ONLY CONTAINS IDENTIFIERS CACHE REGIONS @dbrumann / denis.brumann@sensiolabs.de 67
  29. 66.

    CACHES ARE NOT AWARE OF CHANGES TO PERSISTENT STORE BY

    OTHER APPLICATIONS PAGINATION COUNT QUERIES ARE NOT CACHED NOT ALL CACHES WORK IN DISTRIBUTED ENVS LIMITATIONS @dbrumann / denis.brumann@sensiolabs.de 69
  30. 70.

    RECAP MAPPING UUID GENERATOR NAMED QUERIES NAMESPACE ALIASES PROXY OBJECTS

    CLASS METADATA ENTITY MANAGER SECOND LEVEL CACHE @dbrumann / denis.brumann@sensiolabs.de 73
  31. 72.

    ENTITY MANAGER BEHAVIOR CHANGES FOR FLUSH NO MORE DETACH, MERGE

    & COPY @dbrumann / denis.brumann@sensiolabs.de 75
  32. 73.
  33. 74.