From 79ba8c6be8280062361675fd4e9f3abfcf23f7f6 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 18 Jan 2015 15:18:18 +0100 Subject: [PATCH] Add Changelog/Migration to 2.5 documentation chapter. --- UPGRADE.md | 6 +- docs/en/changelog/migration_2_5.rst | 690 ++++++++++++++++++++++++++++ docs/en/index.rst | 5 + 3 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 docs/en/changelog/migration_2_5.rst diff --git a/UPGRADE.md b/UPGRADE.md index 5a8985b089d..7e8caa6ca59 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -26,11 +26,15 @@ As of 2.5, ``EntityManager`` will follow configured cascades, providing a better memory management since associations will be garbage collected, optimizing resources consumption on long running jobs. -## BC BREAK: NamingStrategy has a new method ``embeddedFieldToColumnName($propertyName, $embeddedColumnName)`` +## BC BREAK: NamingStrategy interface changes + +1. A new method ``embeddedFieldToColumnName($propertyName, $embeddedColumnName)`` This method generates the column name for fields of embedded objects. If you implement your custom NamingStrategy, you now also need to implement this new method. +2. A change to method ``joinColumnName()`` to include the $className + ## Updates on entities scheduled for deletion are no longer processed In Doctrine 2.4, if you modified properties of an entity scheduled for deletion, UnitOfWork would diff --git a/docs/en/changelog/migration_2_5.rst b/docs/en/changelog/migration_2_5.rst new file mode 100644 index 00000000000..e5d81ad1cb3 --- /dev/null +++ b/docs/en/changelog/migration_2_5.rst @@ -0,0 +1,690 @@ +What is new in Doctrine ORM 2.5? +================================ + +This document describes changes between Doctrine ORM 2.4 and 2.5 (currently in +Beta). It contains a description of all the new features and sections +about behavioral changes and potential backwards compatibility breaks. +Please review this document carefully when updating to Doctrine 2.5. + +First note, that with the ORM 2.5 release we are dropping support +for PHP 5.3. We are enforcing this with Composer, servers without +at least PHP 5.4 will not allow installing Doctrine 2.5. + +New Features and Improvements +----------------------------- + +Events: PostLoad now triggered after associations are loaded +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before Doctrine 2.5 if you had an entity with a ``@PostLoad`` event +defined then Doctrine would trigger listeners after the fields were +loaded, but before assocations are available. + +- `DDC-54 `_ +- `Commit `_ + +Events: Add API to programatically add event listeners to Entity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When developing third party libraries or decoupled applications +it can be interesting to develop an entity listener without knowing +the entities that require this listener. + +You can now attach entity listeners to entities using the +``AttachEntityListenersListener`` class, which is listening to the +``loadMetadata`` event that is fired once for every entity during +metadata generation: + +.. code-block:: php + + addEntityListener( + 'MyProject\Entity\User', 'MyProject\Listener\TimestampableListener', + Events::prePersist, 'onPrePersist' + ); + + $evm->addEventListener(Events::loadClassMetadata, $listener); + + class TimestampableListener + { + public function onPrePersist($event) + { + $entity = $event->getEntity(); + $entity->setCreated(new \DateTime('now')); + } + } + +Embeddedable Objects +~~~~~~~~~~~~~~~~~~~~ + +Doctrine now supports creating multiple PHP objects from one database table +implementing a feature called "Embeddedable Objects". Next to an ``@Entity`` +class you can now define a class that is embeddable into a database table of an +entity using the ``@Embeddable`` annotation. Embeddable objects can never be +saved, updated or deleted on their own, only as part of an entity (called +"root-entity" or "aggregate"). Consequently embeddables don't have a primary +key, they are identified only by their values. + +Example of defining and using embeddables classes: + +.. code-block:: php + + `_. + +This feature was developed by external contributor `Johannes Schmitt +`_ + +- `DDC-93 `_ +- `Pull Request `_ + +Second-Level-Cache +~~~~~~~~~~~~~~~~~~ + +Since version 2.0 of Doctrine, fetching the same object twice by primary key +would result in just one query. This was achieved by the identity map pattern +(first-level-cache) that kept entities in memory. + +The newly introduced second-level-cache works a bit differently. Instead +of saving objects in memory, it saves them in a fast in-memory cache such +as Memcache, Redis, Riak or MongoDB. Additionally it allows saving the result +of more complex queries than by primary key. Summarized this feature works +like the existing Query result cache, but it much more powerful. + +As an example lets cache an entity Country that is a relation to the User +entity. We always want to display the country, but avoid the additional +query to this table. + +.. code-block:: php + + setSecondLevelCacheEnabled(); + + $cacheConfig = $config->getSecondLevelCacheConfiguration(); + $regionConfig = $cacheConfig->getRegionsConfiguration(); + $regionConfig->setLifetime('country_region', 3600); + +Now Doctrine will first check for the data of any country in the cache +instead of the database. + +- `Documentation + `_ +- `Pull Request `_ + +Criteria API: Support for ManyToMany assocations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We introduced support for querying collections using the `Criteria API +`_ +in 2.4. This only worked efficently for One-To-Many assocations, not for +Many-To-Many. With the start of 2.5 also Many-To-Many associations get queried +instead of loading them into memory. + +Criteria API: Add new contains() expression +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is now possible to use the Criteria API to check for string contains needle +using ``contains()``. This translates to using a ``column LIKE '%needle%'`` SQL +condition. + +.. code-block:: php + + where(Criteria::expr()->contains('name', 'Benjamin')); + + $users = $repository->matching($criteria); + +Criteria API: Support for EXTRA_LAZY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A collection that is marked as ``fetch="EXTRA_LAZY"`` will now return another +lazy collection when using ``Collection::matching($criteria)``: + +.. code-block:: php + + where(Criteria->expr()->eq("published", 1)); + + $publishedComments = $post->getComments()->matching($criteria); + + echo count($publishedComments); + +The lazy criteria currently supports the ``count()`` and ``contains()`` +functionality lazily. All other operations of the ``Collection`` interface +trigger a full load of the collection. + +This feature was contributed by `Michaƫl Gallego `_. + +- `Pull Request #1 `_ +- `Pull Request #2 `_ + +Mapping: Allow configuring Index flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is now possible to control the index flags in the DBAL +schema abstraction from the ORM using metadata. This was possible +only with a schema event listener before. + +.. code-block:: php + + `_. + +- `Pull Request `_ + +SQLFilter API: Check if parameter isset +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can now check in your SQLFilter if a parameter was set. This allows +to more easily control which features of a filter to enable or disable. + +Extending on the locale example of the documentation: + +.. code-block:: php + + reflClass->implementsInterface('LocaleAware')) { + return ""; + } + + if (!$this->hasParameter('locale')) { + return ""; + } + + return $targetTableAlias.'.locale = ' . $this->getParameter('locale'); + } + } + +This feature was contributed by `Miroslav Demovic `_ + +- `Pull Request `_ + + +EXTRA_LAZY Improvements +~~~~~~~~~~~~~~~~~~~~~~~ + +1. Efficient query when using EXTRA_LAZY and containsKey + + When calling ``Collection::containsKey($key)`` on one-to-many and many-to-many + collections using ``indexBy`` and ``EXTRA_LAZY`` a query is now executed to check + for the existance for the item. Prevoiusly this operation was performed in memory + by loading all entities of the collection. + + .. code-block:: php + + getGroups()->containsKey($groupId)) { + echo "User is in group $groupId\n"; + } + + This feature was contributed by `Asmir Mustafic `_ + + - `Pull Request `_ + +2. Add EXTRA_LAZY Support for get() for owning and inverse many-to-many + + This was contributed by `Sander Marechal `_. + +Improve efficiency of One-To-Many EAGER +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When marking a one-to-many association with ``fetch="EAGER"`` it will now +execute one query less than before and work correctly in combination with +``indexBy``. + +Full support for EntityManagerInterface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Most of the locations where previously only the ``Doctrine\ORM\EntityManager`` +was allowed are now changed to accept the ``EntityManagerInterface`` that was +introduced in 2.4. This allows you to more easily use the decorator pattern +to extend the EntityManager if you need. + +DQL Improvements +~~~~~~~~~~~~~~~~ + +1. It is now possible to add functions to the ORDER BY clause in DQL statements: + +.. code-block:: php + + createQuery($dql); + $query->setParameter('groups', array(1, 2, 3)); + + $users = $query->getResult(); + +6. Expressions inside COUNT() now allowed + +.. code-block:: php + + `_ to pass a callback instead that resolves +the function: + +.. code-block:: php + + addCustomNumericFunction( + 'IS_PUBLISHED', function($funcName) use ($currentSiteId) { + return new IsPublishedFunction($currentSiteId); + } + ); + +Query API: WHERE IN Query using a Collection as parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When performing a WHERE IN query for a collection of entities you can +now pass the array collection of entities as a parameter value to the query +object: + +.. code-block:: php + + getChildren(); + + $queryBuilder + ->select('p') + ->from('Product', 'p') + ->where('p.category IN (:categories)') + ->setParameter('categories', $categories) + ; + +This feature was contributed by `Michael Perrin +`_. + +- `Pull Request `_ +- `DDC-2319 `_ + +Query API: Add suport for default Query Hints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To configure multiple different features such as custom AST Walker, fetch modes, +locking and other features affecting DQL generation we have had a feature +called "query hints" since version 2.0. + +It is now possible to add query hints that are always enabled for every Query: + +.. code-block:: php + + setDefaultQueryHints( + 'doctrine.customOutputWalker' => 'MyProject\CustomOutputWalker' + ); + +This feature was contributed by `Artur Eshenbrener +`_. + +- `Pull Request `_ + +ResultSetMappingBuilder: Add support for Single-Table Inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before 2.5 the ResultSetMappingBuilder did not work with entities +that are using Single-Table-Inheritance. This restriction was lifted +by adding the missing support. + +YAML Mapping: Many-To-Many doesnt require join column definition +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Annotations and XML it was not necessary using conventions for naming +the many-to-many join column names, in YAML it was not possible however. + +A many-to-many definition in YAML is now possible using this minimal +definition: + +.. code-block:: yaml + + manyToMany: + groups: + targetEntity: Group + joinTable: + name: users_groups + +Schema Validator Command: Allow to skip sub-checks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Schema Validator command executes two independent checks +for validity of the mappings and if the schema is synchronized +correctly. It is now possible to skip any of the two steps +when executing the command: + +:: + + $ php vendor/bin/doctrine orm:validate-schema --skip-mapping + $ php vendor/bin/doctrine orm:validate-schema --skip-sync + +This allows you to write more specialized continuous integration and automation +checks. When no changes are found the command returns the exit code 0 +and 1, 2 or 3 when failing because of mapping, sync or both. + +EntityGenerator Command: Avoid backups +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When calling the EntityGenerator for an existing entity, Doctrine would +create a backup file every time to avoid loosing changes to the code. +You can now skip generating the backup file by passing the ``--no-backup`` +flag: + +:: + + $ php vendor/bin/doctrine orm:generate-entities src/ --no-backup + +Support for Objects as Identifiers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is now possible to use Objects as identifiers for Entities +as long as they implement the magic method ``__toString()``. + +.. code-block:: php + + value = $value; + } + + public function __toString() + { + return (string)$this->value; + } + } + + class User + { + /** @Id @Column(type="userid") */ + private $id; + + public function __construct(UserId $id) + { + $this->id = $id; + } + } + + class UserIdType extends \Doctrine\DBAL\Types\Type + { + // ... + } + + Doctrine\DBAL\Types\Type::addType('userid', 'MyProject\UserIdType'); + +Behavioral Changes (BC Breaks) +------------------------------ + +NamingStrategy interface changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Doctrine\ORM\Mapping\NamingStrategyInterface`` changed slightly +to pass the Class Name of the entity into the join column name generation: + +:: + + - function joinColumnName($propertyName); + + function joinColumnName($propertyName, $className = null); + +It also received a new method for supporting embeddables: + +:: + + public function embeddedFieldToColumnName($propertyName, $embeddedColumnName); + +Minor BC BREAK: EntityManagerInterface instead of EntityManager in type-hints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require +an ``EntityManagerInterface`` instead. +If you are extending any of the following classes, then you need to check following +signatures: + +- ``Doctrine\ORM\Tools\DebugUnitOfWorkListener#dumpIdentityMap(EntityManagerInterface $em)`` +- ``Doctrine\ORM\Mapping\ClassMetadataFactory#setEntityManager(EntityManagerInterface $em)`` + +Minor BC BREAK: Custom Hydrators API change +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As of 2.5, `AbstractHydrator` does not enforce the usage of cache as part of +API, and now provides you a clean API for column information through the method +`hydrateColumnInfo($column)`. +Cache variable being passed around by reference is no longer needed since +Hydrators are per query instantiated since Doctrine 2.4. + +- `DDC-3060 `_ + +Minor BC BREAK: Entity based EntityManager#clear() calls follow cascade detach +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Whenever ``EntityManager#clear()`` method gets called with a given entity class +name, until 2.4, it was only detaching the specific requested entity. +As of 2.5, ``EntityManager`` will follow configured cascades, providing a better +memory management since associations will be garbage collected, optimizing +resources consumption on long running jobs. + +Updates on entities scheduled for deletion are no longer processed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Doctrine 2.4, if you modified properties of an entity scheduled for deletion, UnitOfWork would +produce an UPDATE statement to be executed right before the DELETE statement. The entity in question +was therefore present in ``UnitOfWork#entityUpdates``, which means that ``preUpdate`` and ``postUpdate`` +listeners were (quite pointlessly) called. In ``preFlush`` listeners, it used to be possible to undo +the scheduled deletion for updated entities (by calling ``persist()`` if the entity was found in both +``entityUpdates`` and ``entityDeletions``). This does not work any longer, because the entire changeset +calculation logic is optimized away. + +Minor BC BREAK: Default lock mode changed from LockMode::NONE to null in method signatures +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A misconception concerning default lock mode values in method signatures lead to unexpected behaviour +in SQL statements on SQL Server. With a default lock mode of ``LockMode::NONE`` throughout the +method signatures in ORM, the table lock hint ``WITH (NOLOCK)`` was appended to all locking related +queries by default. This could result in unpredictable results because an explicit ``WITH (NOLOCK)`` +table hint tells SQL Server to run a specific query in transaction isolation level READ UNCOMMITTED +instead of the default READ COMMITTED transaction isolation level. +Therefore there now is a distinction between ``LockMode::NONE`` and ``null`` to be able to tell +Doctrine whether to add table lock hints to queries by intention or not. To achieve this, the following +method signatures have been changed to declare ``$lockMode = null`` instead of ``$lockMode = LockMode::NONE``: + +- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#getSelectSQL()`` +- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#load()`` +- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#refresh()`` +- ``Doctrine\ORM\Decorator\EntityManagerDecorator#find()`` +- ``Doctrine\ORM\EntityManager#find()`` +- ``Doctrine\ORM\EntityRepository#find()`` +- ``Doctrine\ORM\Persisters\BasicEntityPersister#getSelectSQL()`` +- ``Doctrine\ORM\Persisters\BasicEntityPersister#load()`` +- ``Doctrine\ORM\Persisters\BasicEntityPersister#refresh()`` +- ``Doctrine\ORM\Persisters\EntityPersister#getSelectSQL()`` +- ``Doctrine\ORM\Persisters\EntityPersister#load()`` +- ``Doctrine\ORM\Persisters\EntityPersister#refresh()`` +- ``Doctrine\ORM\Persisters\JoinedSubclassPersister#getSelectSQL()`` + +You should update signatures for these methods if you have subclassed one of the above classes. +Please also check the calling code of these methods in your application and update if necessary. + +.. note:: + + This in fact is really a minor BC BREAK and should not have any affect on database vendors + other than SQL Server because it is the only one that supports and therefore cares about + ``LockMode::NONE``. It's really just a FIX for SQL Server environments using ORM. + +Minor BC BREAK: __clone method not called anymore when entities are instantiated via metadata API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As of PHP 5.6, instantiation of new entities is deferred to the +`doctrine/instantiator `_ library, which will avoid calling ``__clone`` +or any public API on instantiated objects. + +BC BREAK: DefaultRepositoryFactory is now final +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Please implement the ``Doctrine\ORM\Repository\RepositoryFactory`` interface instead of extending +the ``Doctrine\ORM\Repository\DefaultRepositoryFactory``. + +BC BREAK: New object expression DQL queries now respects user provided aliasing and not return consumed fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When executing DQL queries with new object expressions, instead of returning +DTOs numerically indexes, it will now respect user provided aliases. Consider +the following query: + +:: + + SELECT new UserDTO(u.id,u.name) as user,new AddressDTO(a.street,a.postalCode) as address, a.id as addressId + FROM User u INNER JOIN u.addresses a WITH a.isPrimary = true + +Previously, your result would be similar to this: + +:: + + array( + 0=>array( + 0=>{UserDTO object}, + 1=>{AddressDTO object}, + 2=>{u.id scalar}, + 3=>{u.name scalar}, + 4=>{a.street scalar}, + 5=>{a.postalCode scalar}, + 'addressId'=>{a.id scalar}, + ), + ... + ) + +From now on, the resultset will look like this: + +:: + + array( + 0=>array( + 'user'=>{UserDTO object}, + 'address'=>{AddressDTO object}, + 'addressId'=>{a.id scalar} + ), + ... + ) diff --git a/docs/en/index.rst b/docs/en/index.rst index 4cb5225b12f..8e6afc82592 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -92,6 +92,11 @@ Tutorials * :doc:`Override Field/Association Mappings In Subclasses ` * :doc:`Embeddables ` +Changelogs +---------- + +* :doc:`Migration to 2.5 ` + Cookbook --------