From eef32d4372ee3bb46a02c71d4c04a5e14f5fb191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20H=C3=B6rnicke?= Date: Tue, 24 Jun 2014 11:02:24 +0200 Subject: [PATCH 01/46] added method to be able to reuse the console application --- .../ORM/Tools/Console/ConsoleRunner.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php b/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php index 7e88615aa..c69e2342b 100644 --- a/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php +++ b/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php @@ -55,13 +55,29 @@ class ConsoleRunner * @return void */ static public function run(HelperSet $helperSet, $commands = array()) + { + $cli = self::createApplication($helperSet, $commands); + $cli->run(); + } + + /** + * Creates a console application with the given helperset and + * optional commands. + * + * @param \Symfony\Component\Console\Helper\HelperSet $helperSet + * @param array $commands + * + * @return \Symfony\Component\Console\Application + */ + static public function createApplication(HelperSet $helperSet, $commands = array()) { $cli = new Application('Doctrine Command Line Interface', Version::VERSION); $cli->setCatchExceptions(true); $cli->setHelperSet($helperSet); self::addCommands($cli); $cli->addCommands($commands); - $cli->run(); + + return $cli; } /** From 1d16e5322f62b20f8a8a80452be25fb483e59279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20H=C3=B6rnicke?= Date: Thu, 24 Jul 2014 09:23:36 +0200 Subject: [PATCH 02/46] added a simple test --- .../ORM/Tools/Console/ConsoleRunnerTest.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php new file mode 100644 index 000000000..9d1966534 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php @@ -0,0 +1,26 @@ +assertInstanceOf('Symfony\Component\Console\Application', $app); + $this->assertSame($helperSet, $app->getHelperSet()); + $this->assertEquals(Version::VERSION, $app->getVersion()); + } +} From a76506c3fd164d44774b56ac88d964361dad48f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20H=C3=B6rnicke?= Date: Thu, 24 Jul 2014 09:38:08 +0200 Subject: [PATCH 03/46] amended documentation --- docs/en/reference/tools.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/en/reference/tools.rst b/docs/en/reference/tools.rst index a5f99d141..eb93831b9 100644 --- a/docs/en/reference/tools.rst +++ b/docs/en/reference/tools.rst @@ -507,3 +507,22 @@ defined ones) is possible through the command: new \MyProject\Tools\Console\Commands\AnotherCommand(), new \MyProject\Tools\Console\Commands\OneMoreCommand(), )); + + +Re-use console application +-------------------------- + +You are also able to retrieve and re-use the default console application. +Just call ``ConsoleRunner::createApplication(...)`` with an appropriate +HelperSet, like it is described in the configuration section. + +.. code-block:: php + + run(); + From 1b9f42ae67d5f7a779524c08ccbead3033b1639a Mon Sep 17 00:00:00 2001 From: Jefersson Nathan Date: Wed, 30 Jul 2014 16:54:24 -0300 Subject: [PATCH 04/46] Use `null` comparation instead of `is_null()` --- tests/Doctrine/Tests/Mocks/EntityManagerMock.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Doctrine/Tests/Mocks/EntityManagerMock.php b/tests/Doctrine/Tests/Mocks/EntityManagerMock.php index b27e96c4b..74f4efcf0 100644 --- a/tests/Doctrine/Tests/Mocks/EntityManagerMock.php +++ b/tests/Doctrine/Tests/Mocks/EntityManagerMock.php @@ -86,13 +86,13 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager public static function create($conn, \Doctrine\ORM\Configuration $config = null, \Doctrine\Common\EventManager $eventManager = null) { - if (is_null($config)) { + if (null === $config) { $config = new \Doctrine\ORM\Configuration(); $config->setProxyDir(__DIR__ . '/../Proxies'); $config->setProxyNamespace('Doctrine\Tests\Proxies'); $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true)); } - if (is_null($eventManager)) { + if (null === $eventManager) { $eventManager = new \Doctrine\Common\EventManager(); } From 2d23c95c3fe3644fcee569724c65bb695adc31d1 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 30 Jul 2014 15:00:35 -0700 Subject: [PATCH 05/46] Fix bulk insert code example Previous code example did not flush all entities when entity count was not a multiple of batch count. --- docs/en/reference/batch-processing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/reference/batch-processing.rst b/docs/en/reference/batch-processing.rst index 77b4e1720..7a62aff00 100644 --- a/docs/en/reference/batch-processing.rst +++ b/docs/en/reference/batch-processing.rst @@ -42,6 +42,8 @@ internally but also mean more work during ``flush``. $em->clear(); // Detaches all objects from Doctrine! } } + $em->flush(); //Persist objects that did not make up an entire batch + $em->clear(); Bulk Updates ------------ From 7c2ab7fff87aaadcf6f267ae053f7daf9270ef5d Mon Sep 17 00:00:00 2001 From: Simon Harris Date: Thu, 31 Jul 2014 16:45:33 +0100 Subject: [PATCH 06/46] Changes for grammar and clarity --- docs/en/reference/caching.rst | 73 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/docs/en/reference/caching.rst b/docs/en/reference/caching.rst index ff5cadd7b..0f18e8a20 100644 --- a/docs/en/reference/caching.rst +++ b/docs/en/reference/caching.rst @@ -4,9 +4,9 @@ Caching Doctrine provides cache drivers in the ``Common`` package for some of the most popular caching implementations such as APC, Memcache and Xcache. We also provide an ``ArrayCache`` driver which stores -the data in a PHP array. Obviously, the cache does not live between -requests but this is useful for testing in a development -environment. +the data in a PHP array. Obviously, when using ``ArrayCache``, the +cache does not persist between requests, but this is useful for +testing in a development environment. Cache Drivers ------------- @@ -14,20 +14,19 @@ Cache Drivers The cache drivers follow a simple interface that is defined in ``Doctrine\Common\Cache\Cache``. All the cache drivers extend a base class ``Doctrine\Common\Cache\AbstractCache`` which implements -the before mentioned interface. +this interface. -The interface defines the following methods for you to publicly -use. +The interface defines the following public methods for you to implement: -- fetch($id) - Fetches an entry from the cache. -- contains($id) - Test if an entry exists in the cache. -- save($id, $data, $lifeTime = false) - Puts data into the cache. -- delete($id) - Deletes a cache entry. +- fetch($id) - Fetches an entry from the cache +- contains($id) - Test if an entry exists in the cache +- save($id, $data, $lifeTime = false) - Puts data into the cache +- delete($id) - Deletes a cache entry Each driver extends the ``AbstractCache`` class which defines a few abstract protected methods that each of the drivers must -implement. +implement: - \_doFetch($id) @@ -35,8 +34,8 @@ implement. - \_doSave($id, $data, $lifeTime = false) - \_doDelete($id) -The public methods ``fetch()``, ``contains()``, etc. utilize the -above protected methods that are implemented by the drivers. The +The public methods ``fetch()``, ``contains()`` etc. use the +above protected methods which are implemented by the drivers. The code is organized this way so that the protected methods in the drivers do the raw interaction with the cache implementation and the ``AbstractCache`` can build custom functionality on top of @@ -65,7 +64,7 @@ Memcache In order to use the Memcache cache driver you must have it compiled and enabled in your php.ini. You can read about Memcache -` on the PHP website `_. It will +`on the PHP website `_. It will give you a little background information about what it is and how you can use it as well as how to install it. @@ -90,7 +89,7 @@ Memcache. In order to use the Memcached cache driver you must have it compiled and enabled in your php.ini. You can read about Memcached -` on the PHP website `_. It will +`on the PHP website `_. It will give you a little background information about what it is and how you can use it as well as how to install it. @@ -129,10 +128,10 @@ Redis ~~~~~ In order to use the Redis cache driver you must have it compiled -and enabled in your php.ini. You can read about what is Redis +and enabled in your php.ini. You can read about what Redis is `from here `_. Also check `A PHP extension for Redis `_ for how you can use -and install Redis PHP extension. +and install the Redis PHP extension. Below is a simple example of how you could use the Redis cache driver by itself. @@ -151,8 +150,8 @@ Using Cache Drivers ------------------- In this section we'll describe how you can fully utilize the API of -the cache drivers to save cache, check if some cache exists, fetch -the cached data and delete the cached data. We'll use the +the cache drivers to save data to a cache, check if some cached data +exists, fetch the cached data and delete the cached data. We'll use the ``ArrayCache`` implementation as our example here. .. code-block:: php @@ -163,7 +162,7 @@ the cached data and delete the cached data. We'll use the Saving ~~~~~~ -To save some data to the cache driver it is as simple as using the +Saving some data to the cache driver is as simple as using the ``save()`` method. .. code-block:: php @@ -172,7 +171,7 @@ To save some data to the cache driver it is as simple as using the $cacheDriver->save('cache_id', 'my_data'); The ``save()`` method accepts three arguments which are described -below. +below: - ``$id`` - The cache id @@ -195,7 +194,7 @@ object, etc. Checking ~~~~~~~~ -Checking whether some cache exists is very simple, just use the +Checking whether cached data exists is very simple: just use the ``contains()`` method. It accepts a single argument which is the ID of the cache entry. @@ -213,7 +212,7 @@ Fetching Now if you want to retrieve some cache entry you can use the ``fetch()`` method. It also accepts a single argument just like -``contains()`` which is the ID of the cache entry. +``contains()`` which is again the ID of the cache entry. .. code-block:: php @@ -249,7 +248,7 @@ the ``deleteAll()`` method. Namespaces ~~~~~~~~~~ -If you heavily use caching in your application and utilize it in +If you heavily use caching in your application and use it in multiple parts of your application, or use it in different applications on the same server you may have issues with cache naming collisions. This can be worked around by using namespaces. @@ -265,8 +264,8 @@ Integrating with the ORM ------------------------ The Doctrine ORM package is tightly integrated with the cache -drivers to allow you to improve performance of various aspects of -Doctrine by just simply making some additional configurations and +drivers to allow you to improve the performance of various aspects of +Doctrine by simply making some additional configurations and method calls. Query Cache @@ -374,9 +373,9 @@ the cache driver. Clearing the Cache ------------------ -We've already shown you previously how you can use the API of the +We've already shown you how you can use the API of the cache drivers to manually delete cache entries. For your -convenience we offer a command line task for you to help you with +convenience we offer a command line task to help you with clearing the query, result and metadata cache. From the Doctrine command line you can run the following command. @@ -408,7 +407,7 @@ To clear the result cache use the ``--result`` option. $ ./doctrine clear-cache --result When you use the ``--result`` option you can use some other options -to be more specific about what queries result sets you want to +to be more specific about which queries' result sets you want to clear. Just like the API of the cache drivers you can clear based on an @@ -418,19 +417,19 @@ ID, regular expression, prefix or suffix. $ ./doctrine clear-cache --result --id=cache_id -Or if you want to clear based on a regular expressions. +Or if you want to clear based on a regular expressions: .. code-block:: php $ ./doctrine clear-cache --result --regex=users_.* -Or with a prefix. +Or with a prefix: .. code-block:: php $ ./doctrine clear-cache --result --prefix=users_ -And finally with a suffix. +And finally with a suffix: .. code-block:: php @@ -447,15 +446,15 @@ And finally with a suffix. Cache Slams ----------- -Something to be careful of when utilizing the cache drivers is -cache slams. If you have a heavily trafficked website with some +Something to be careful of when using the cache drivers is +"cache slams". Imagine you have a heavily trafficked website with some code that checks for the existence of a cache record and if it does not exist it generates the information and saves it to the cache. -Now if 100 requests were issued all at the same time and each one -sees the cache does not exist and they all try and insert the same +Now, if 100 requests were issued all at the same time and each one +sees the cache does not exist and they all try to insert the same cache entry it could lock up APC, Xcache, etc. and cause problems. Ways exist to work around this, like pre-populating your cache and -not letting your users requests populate the cache. +not letting your users' requests populate the cache. You can read more about cache slams `in this blog post `_. From e0ae7634d5e27b7f903e5b3b80bc56fec0dcc9e6 Mon Sep 17 00:00:00 2001 From: encoder64 Date: Sun, 3 Aug 2014 17:02:33 +0300 Subject: [PATCH 07/46] #DDC-1590: Fix Inheritance in Code-Generation --- lib/Doctrine/ORM/Tools/EntityGenerator.php | 10 +-- .../Tests/Models/DDC1590/DDC1590Entity.php | 85 +++++++++++++++++++ .../Tests/Models/DDC1590/DDC1590User.php | 41 +++++++++ .../Tests/ORM/Tools/EntityGeneratorTest.php | 79 +++++++++++++++++ 4 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php create mode 100644 tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index e6680e53b..c040dff57 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -714,9 +714,9 @@ public function __construct() */ protected function hasProperty($property, ClassMetadataInfo $metadata) { - if ($this->extendsClass()) { + if ($this->extendsClass() || class_exists($metadata->name)) { // don't generate property if its already on the base class. - $reflClass = new \ReflectionClass($this->getClassToExtend()); + $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); if ($reflClass->hasProperty($property)) { return true; } @@ -743,15 +743,15 @@ public function __construct() */ protected function hasMethod($method, ClassMetadataInfo $metadata) { - if ($this->extendsClass()) { + if ($this->extendsClass() || class_exists($metadata->name)) { // don't generate method if its already on the base class. - $reflClass = new \ReflectionClass($this->getClassToExtend()); + $reflClass = new \ReflectionClass($this->getClassToExtend() ?: $metadata->name); if ($reflClass->hasMethod($method)) { return true; } } - + // check traits for existing method foreach ($this->getTraits($metadata) as $trait) { if ($trait->hasMethod($method)) { diff --git a/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php b/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php new file mode 100644 index 000000000..7d6565a28 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php @@ -0,0 +1,85 @@ +id; + } + + /** + * Set createdAt + * + * @param \DateTime $createdAt + * + * @return DDC1590User + */ + public function setCreatedAt($createdAt) + { + $this->created_at = $createdAt; + + return $this; + } + + /** + * Get createdAt + * + * @return \DateTime + */ + public function getCreatedAt() + { + return $this->created_at; + } + + /** + * Set updatedAt + * + * @param \DateTime $updatedAt + * + * @return DDC1590User + */ + public function setUpdatedAt($updatedAt) + { + $this->updated_at = $updatedAt; + + return $this; + } + + /** + * Get updatedAt + * + * @return \DateTime + */ + public function getUpdatedAt() + { + return $this->updated_at; + } +} diff --git a/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php b/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php new file mode 100644 index 000000000..9e521df13 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php @@ -0,0 +1,41 @@ +name = $name; + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } +} diff --git a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php index 6394f6399..9e9687e91 100644 --- a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php @@ -547,6 +547,85 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->assertSame($reflClass->hasMethod('getAddress'), false); } + /** + * @group DDC-1590 + */ + public function testMethodsAndPropertiesAreNotDuplicatedInChildClasses() + { + $cmf = new ClassMetadataFactory(); + $em = $this->_getTestEntityManager(); + + $cmf->setEntityManager($em); + + $ns = $this->_namespace; + $nsdir = $this->_tmpDir . '/' . $ns; + + $content = str_replace( + 'namespace Doctrine\Tests\Models\DDC1590', + 'namespace '.$ns, + file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php') + ); + + $fname = $nsdir . "/DDC1590User.php"; + file_put_contents($fname, $content); + require $fname; + + + $metadata = $cmf->getMetadataFor($ns . '\DDC1590User'); + $this->_generator->writeEntityClass($metadata, $this->_tmpDir); + + // class DDC1590User extends DDC1590Entity { ... } + $source = file_get_contents($fname); + + // class _DDC1590User extends DDC1590Entity { ... } + $source2 = str_replace('class DDC1590User', 'class _DDC1590User', $source); + $fname2 = $fname = $nsdir . "/_DDC1590User.php"; + file_put_contents($fname2, $source2); + require $fname2; + + // class __DDC1590User { ... } + $source3 = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source); + $fname3 = $fname = $nsdir . "/__DDC1590User.php"; + file_put_contents($fname3, $source3); + require $fname3; + + + // class _DDC1590User extends DDC1590Entity { ... } + $rc2 = new \ReflectionClass($ns.'\_DDC1590User'); + + $this->assertSame($rc2->hasProperty('name'), true); + $this->assertSame($rc2->hasProperty('id'), true); + $this->assertSame($rc2->hasProperty('created_at'), true); + $this->assertSame($rc2->hasProperty('updated_at'), true); + + $this->assertSame($rc2->hasMethod('getName'), true); + $this->assertSame($rc2->hasMethod('setName'), true); + $this->assertSame($rc2->hasMethod('getId'), true); + $this->assertSame($rc2->hasMethod('setId'), false); + $this->assertSame($rc2->hasMethod('getCreatedAt'), true); + $this->assertSame($rc2->hasMethod('setCreatedAt'), true); + $this->assertSame($rc2->hasMethod('getUpdatedAt'), true); + $this->assertSame($rc2->hasMethod('setUpdatedAt'), true); + + + // class __DDC1590User { ... } + $rc3 = new \ReflectionClass($ns.'\__DDC1590User'); + + $this->assertSame($rc3->hasProperty('name'), true); + $this->assertSame($rc3->hasProperty('id'), false); + $this->assertSame($rc3->hasProperty('created_at'), false); + $this->assertSame($rc3->hasProperty('updated_at'), false); + + $this->assertSame($rc3->hasMethod('getName'), true); + $this->assertSame($rc3->hasMethod('setName'), true); + $this->assertSame($rc3->hasMethod('getId'), false); + $this->assertSame($rc3->hasMethod('setId'), false); + $this->assertSame($rc3->hasMethod('getCreatedAt'), false); + $this->assertSame($rc3->hasMethod('setCreatedAt'), false); + $this->assertSame($rc3->hasMethod('getUpdatedAt'), false); + $this->assertSame($rc3->hasMethod('setUpdatedAt'), false); + } + /** * @return array */ From 4e805bb59a766d4741d1197ddd5ca6f4dfff5a98 Mon Sep 17 00:00:00 2001 From: encoder64 Date: Sun, 3 Aug 2014 17:07:20 +0300 Subject: [PATCH 08/46] #DDC-1590: Fix Inheritance in Code-Generation: Code Style Fixes --- lib/Doctrine/ORM/Tools/EntityGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index c040dff57..918e4162b 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -751,7 +751,7 @@ public function __construct() return true; } } - + // check traits for existing method foreach ($this->getTraits($metadata) as $trait) { if ($trait->hasMethod($method)) { From 94ba6e2dfc455ccdb2505f6d566286cc5eff6b28 Mon Sep 17 00:00:00 2001 From: encoder64 Date: Mon, 4 Aug 2014 20:18:26 +0300 Subject: [PATCH 09/46] #DDC-1590: Simple Fixes --- .../Tests/Models/DDC1590/DDC1590Entity.php | 29 ------------------- .../Tests/Models/DDC1590/DDC1590User.php | 23 --------------- .../Tests/ORM/Tools/EntityGeneratorTest.php | 12 ++------ 3 files changed, 3 insertions(+), 61 deletions(-) diff --git a/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php b/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php index 7d6565a28..a4dff26fa 100644 --- a/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php +++ b/tests/Doctrine/Tests/Models/DDC1590/DDC1590Entity.php @@ -20,11 +20,6 @@ abstract class DDC1590Entity */ protected $created_at; - /** - * @Column(type="datetime") - */ - protected $updated_at; - /** * Get id * @@ -58,28 +53,4 @@ abstract class DDC1590Entity { return $this->created_at; } - - /** - * Set updatedAt - * - * @param \DateTime $updatedAt - * - * @return DDC1590User - */ - public function setUpdatedAt($updatedAt) - { - $this->updated_at = $updatedAt; - - return $this; - } - - /** - * Get updatedAt - * - * @return \DateTime - */ - public function getUpdatedAt() - { - return $this->updated_at; - } } diff --git a/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php b/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php index 9e521df13..436ab0d54 100644 --- a/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php +++ b/tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php @@ -15,27 +15,4 @@ class DDC1590User extends DDC1590Entity */ protected $name; - /** - * Set name - * - * @param string $name - * - * @return DDC1590User - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name - * - * @return string - */ - public function getName() - { - return $this->name; - } } diff --git a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php index 9e9687e91..2baecb88d 100644 --- a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php @@ -562,7 +562,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $content = str_replace( 'namespace Doctrine\Tests\Models\DDC1590', - 'namespace '.$ns, + 'namespace ' . $ns, file_get_contents(__DIR__ . '/../../Models/DDC1590/DDC1590User.php') ); @@ -579,13 +579,13 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase // class _DDC1590User extends DDC1590Entity { ... } $source2 = str_replace('class DDC1590User', 'class _DDC1590User', $source); - $fname2 = $fname = $nsdir . "/_DDC1590User.php"; + $fname2 = $nsdir . "/_DDC1590User.php"; file_put_contents($fname2, $source2); require $fname2; // class __DDC1590User { ... } $source3 = str_replace('class DDC1590User extends DDC1590Entity', 'class __DDC1590User', $source); - $fname3 = $fname = $nsdir . "/__DDC1590User.php"; + $fname3 = $nsdir . "/__DDC1590User.php"; file_put_contents($fname3, $source3); require $fname3; @@ -596,7 +596,6 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->assertSame($rc2->hasProperty('name'), true); $this->assertSame($rc2->hasProperty('id'), true); $this->assertSame($rc2->hasProperty('created_at'), true); - $this->assertSame($rc2->hasProperty('updated_at'), true); $this->assertSame($rc2->hasMethod('getName'), true); $this->assertSame($rc2->hasMethod('setName'), true); @@ -604,8 +603,6 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->assertSame($rc2->hasMethod('setId'), false); $this->assertSame($rc2->hasMethod('getCreatedAt'), true); $this->assertSame($rc2->hasMethod('setCreatedAt'), true); - $this->assertSame($rc2->hasMethod('getUpdatedAt'), true); - $this->assertSame($rc2->hasMethod('setUpdatedAt'), true); // class __DDC1590User { ... } @@ -614,7 +611,6 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->assertSame($rc3->hasProperty('name'), true); $this->assertSame($rc3->hasProperty('id'), false); $this->assertSame($rc3->hasProperty('created_at'), false); - $this->assertSame($rc3->hasProperty('updated_at'), false); $this->assertSame($rc3->hasMethod('getName'), true); $this->assertSame($rc3->hasMethod('setName'), true); @@ -622,8 +618,6 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase $this->assertSame($rc3->hasMethod('setId'), false); $this->assertSame($rc3->hasMethod('getCreatedAt'), false); $this->assertSame($rc3->hasMethod('setCreatedAt'), false); - $this->assertSame($rc3->hasMethod('getUpdatedAt'), false); - $this->assertSame($rc3->hasMethod('setUpdatedAt'), false); } /** From cd4bc93483b7cd4ebfb2964461acca66680fb43c Mon Sep 17 00:00:00 2001 From: encoder64 Date: Sat, 9 Aug 2014 13:27:38 +0300 Subject: [PATCH 10/46] Simple Fixes --- .../Tests/ORM/Tools/EntityGeneratorTest.php | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php index 2baecb88d..1a41dee83 100644 --- a/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php @@ -593,31 +593,31 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase // class _DDC1590User extends DDC1590Entity { ... } $rc2 = new \ReflectionClass($ns.'\_DDC1590User'); - $this->assertSame($rc2->hasProperty('name'), true); - $this->assertSame($rc2->hasProperty('id'), true); - $this->assertSame($rc2->hasProperty('created_at'), true); + $this->assertTrue($rc2->hasProperty('name')); + $this->assertTrue($rc2->hasProperty('id')); + $this->assertTrue($rc2->hasProperty('created_at')); - $this->assertSame($rc2->hasMethod('getName'), true); - $this->assertSame($rc2->hasMethod('setName'), true); - $this->assertSame($rc2->hasMethod('getId'), true); - $this->assertSame($rc2->hasMethod('setId'), false); - $this->assertSame($rc2->hasMethod('getCreatedAt'), true); - $this->assertSame($rc2->hasMethod('setCreatedAt'), true); + $this->assertTrue($rc2->hasMethod('getName')); + $this->assertTrue($rc2->hasMethod('setName')); + $this->assertTrue($rc2->hasMethod('getId')); + $this->assertFalse($rc2->hasMethod('setId')); + $this->assertTrue($rc2->hasMethod('getCreatedAt')); + $this->assertTrue($rc2->hasMethod('setCreatedAt')); // class __DDC1590User { ... } $rc3 = new \ReflectionClass($ns.'\__DDC1590User'); - $this->assertSame($rc3->hasProperty('name'), true); - $this->assertSame($rc3->hasProperty('id'), false); - $this->assertSame($rc3->hasProperty('created_at'), false); + $this->assertTrue($rc3->hasProperty('name')); + $this->assertFalse($rc3->hasProperty('id')); + $this->assertFalse($rc3->hasProperty('created_at')); - $this->assertSame($rc3->hasMethod('getName'), true); - $this->assertSame($rc3->hasMethod('setName'), true); - $this->assertSame($rc3->hasMethod('getId'), false); - $this->assertSame($rc3->hasMethod('setId'), false); - $this->assertSame($rc3->hasMethod('getCreatedAt'), false); - $this->assertSame($rc3->hasMethod('setCreatedAt'), false); + $this->assertTrue($rc3->hasMethod('getName')); + $this->assertTrue($rc3->hasMethod('setName')); + $this->assertFalse($rc3->hasMethod('getId')); + $this->assertFalse($rc3->hasMethod('setId')); + $this->assertFalse($rc3->hasMethod('getCreatedAt')); + $this->assertFalse($rc3->hasMethod('setCreatedAt')); } /** From bca9d315310dab49407607f401837e07e8a411e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steve=20M=C3=BCller?= Date: Mon, 11 Aug 2014 16:53:18 +0200 Subject: [PATCH 11/46] add support for nesting embeddables --- .../ORM/Mapping/ClassMetadataFactory.php | 38 +++- .../ORM/Mapping/ClassMetadataInfo.php | 45 +++-- lib/Doctrine/ORM/Mapping/MappingException.php | 20 ++- .../Tests/ORM/Functional/ValueObjectsTest.php | 162 ++++++++++++++---- .../ORM/Mapping/XmlMappingDriverTest.php | 4 +- 5 files changed, 212 insertions(+), 57 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index 62f81939e..cbb8c0cc9 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -142,14 +142,22 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } if (!$class->isMappedSuperclass) { - foreach ($class->embeddedClasses as $property => $embeddableClass) { if (isset($embeddableClass['inherited'])) { continue; } + if ($embeddableClass['class'] === $class->name) { + throw MappingException::infiniteEmbeddableNesting($class->name, $property); + } + $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); + + if ($embeddableMetadata->isEmbeddedClass) { + $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); + } + $class->inlineEmbeddable($property, $embeddableMetadata); } } @@ -370,6 +378,34 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } } + /** + * Adds nested embedded classes metadata to a parent class. + * + * @param ClassMetadata $subClass Sub embedded class metadata to add nested embedded classes metadata from. + * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to. + * @param string $prefix Embedded classes' prefix to use for nested embedded classes field names. + */ + private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix) + { + foreach ($subClass->embeddedClasses as $property => $embeddableClass) { + if (isset($embeddableClass['inherited'])) { + continue; + } + + $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); + + $parentClass->mapEmbedded(array( + 'fieldName' => $prefix . '.' . $property, + 'class' => $embeddableMetadata->name, + 'columnPrefix' => $embeddableClass['columnPrefix'], + 'declaredField' => $embeddableClass['declaredField'] + ? $prefix . '.' . $embeddableClass['declaredField'] + : $prefix, + 'originalField' => $embeddableClass['originalField'] ?: $property, + )); + } + } + /** * Adds inherited named queries to the subclass mapping. * diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 96a71de18..8f9f8cbd5 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -929,15 +929,31 @@ class ClassMetadataInfo implements ClassMetadata // Restore ReflectionClass and properties $this->reflClass = $reflService->getClass($this->name); + $parentReflFields = array(); + + foreach ($this->embeddedClasses as $property => $embeddedClass) { + if (isset($embeddedClass['declaredField'])) { + $parentReflFields[$property] = new ReflectionEmbeddedProperty( + $parentReflFields[$embeddedClass['declaredField']], + $reflService->getAccessibleProperty( + $this->embeddedClasses[$embeddedClass['declaredField']]['class'], + $embeddedClass['originalField'] + ), + $embeddedClass['class'] + ); + + continue; + } + + $parentReflFields[$property] = $reflService->getAccessibleProperty($this->name, $property); + } + foreach ($this->fieldMappings as $field => $mapping) { if (isset($mapping['declaredField'])) { - $declaringClass = isset($this->embeddedClasses[$mapping['declaredField']]['declared']) - ? $this->embeddedClasses[$mapping['declaredField']]['declared'] : $this->name; - $this->reflFields[$field] = new ReflectionEmbeddedProperty( - $reflService->getAccessibleProperty($declaringClass, $mapping['declaredField']), - $reflService->getAccessibleProperty($this->embeddedClasses[$mapping['declaredField']]['class'], $mapping['originalField']), - $this->embeddedClasses[$mapping['declaredField']]['class'] + $parentReflFields[$mapping['declaredField']], + $reflService->getAccessibleProperty($mapping['originalClass'], $mapping['originalField']), + $mapping['originalClass'] ); continue; } @@ -3171,15 +3187,13 @@ class ClassMetadataInfo implements ClassMetadata */ public function mapEmbedded(array $mapping) { - if ($this->isEmbeddedClass) { - throw MappingException::noEmbeddablesInEmbeddable($this->name); - } - $this->assertFieldNotMapped($mapping['fieldName']); $this->embeddedClasses[$mapping['fieldName']] = array( 'class' => $this->fullyQualifiedClassName($mapping['class']), 'columnPrefix' => $mapping['columnPrefix'], + 'declaredField' => isset($mapping['declaredField']) ? $mapping['declaredField'] : null, + 'originalField' => isset($mapping['originalField']) ? $mapping['originalField'] : null, ); } @@ -3192,8 +3206,15 @@ class ClassMetadataInfo implements ClassMetadata public function inlineEmbeddable($property, ClassMetadataInfo $embeddable) { foreach ($embeddable->fieldMappings as $fieldMapping) { - $fieldMapping['declaredField'] = $property; - $fieldMapping['originalField'] = $fieldMapping['fieldName']; + $fieldMapping['originalClass'] = isset($fieldMapping['originalClass']) + ? $fieldMapping['originalClass'] + : $embeddable->name; + $fieldMapping['declaredField'] = isset($fieldMapping['declaredField']) + ? $property . '.' . $fieldMapping['declaredField'] + : $property; + $fieldMapping['originalField'] = isset($fieldMapping['originalField']) + ? $fieldMapping['originalField'] + : $fieldMapping['fieldName']; $fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName']; if (! empty($this->embeddedClasses[$property]['columnPrefix'])) { diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index 82d5a4585..7a8eaada6 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -782,11 +782,21 @@ class MappingException extends \Doctrine\ORM\ORMException ); } - public static function noEmbeddablesInEmbeddable($className) + /** + * @param string $className + * @param string $propertyName + * + * @return MappingException + */ + public static function infiniteEmbeddableNesting($className, $propertyName) { - return new self(sprintf( - "You embedded one or more embeddables in embeddable '%s', but this behavior is currently unsupported.", - $className - )); + return new self( + sprintf( + 'Infinite nesting detected for embedded property %s::%s. ' . + 'You cannot embed an embeddable from the same type inside an embeddable.', + $className, + $propertyName + ) + ); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php index 4e34004b8..98aea6e47 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php @@ -32,6 +32,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $person->address->street = "United States of Tara Street"; $person->address->zip = "12345"; $person->address->city = "funkytown"; + $person->address->country = new DDC93Country('Germany'); // 1. check saving value objects works $this->_em->persist($person); @@ -46,11 +47,14 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('United States of Tara Street', $person->address->street); $this->assertEquals('12345', $person->address->zip); $this->assertEquals('funkytown', $person->address->city); + $this->assertInstanceOf(DDC93Country::CLASSNAME, $person->address->country); + $this->assertEquals('Germany', $person->address->country->name); // 3. check changing value objects works $person->address->street = "Street"; $person->address->zip = "54321"; $person->address->city = "another town"; + $person->address->country->name = "United States of America"; $this->_em->flush(); $this->_em->clear(); @@ -60,6 +64,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('Street', $person->address->street); $this->assertEquals('54321', $person->address->zip); $this->assertEquals('another town', $person->address->city); + $this->assertEquals('United States of America', $person->address->country->name); // 4. check deleting works $personId = $person->id;; @@ -78,6 +83,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $person->address->street = "Tree"; $person->address->zip = "12345"; $person->address->city = "funkytown"; + $person->address->country = new DDC93Country('United States of America'); $this->_em->persist($person); } @@ -94,6 +100,8 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('Tree', $person->address->street); $this->assertEquals('12345', $person->address->zip); $this->assertEquals('funkytown', $person->address->city); + $this->assertInstanceOf(DDC93Country::CLASSNAME, $person->address->country); + $this->assertEquals('United States of America', $person->address->country->name); } $dql = "SELECT p FROM " . __NAMESPACE__ . "\DDC93Person p"; @@ -103,6 +111,7 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('Tree', $person['address.street']); $this->assertEquals('12345', $person['address.zip']); $this->assertEquals('funkytown', $person['address.city']); + $this->assertEquals('United States of America', $person['address.country.name']); } } @@ -115,32 +124,41 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->markTestSkipped('SLC does not work with UPDATE/DELETE queries through EM.'); } - $person = new DDC93Person('Johannes', new DDC93Address('Moo', '12345', 'Karlsruhe')); + $person = new DDC93Person('Johannes', new DDC93Address('Moo', '12345', 'Karlsruhe', new DDC93Country('Germany'))); $this->_em->persist($person); $this->_em->flush($person); // SELECT - $selectDql = "SELECT p FROM " . __NAMESPACE__ ."\\DDC93Person p WHERE p.address.city = :city"; + $selectDql = "SELECT p FROM " . __NAMESPACE__ ."\\DDC93Person p WHERE p.address.city = :city AND p.address.country.name = :country"; $loadedPerson = $this->_em->createQuery($selectDql) ->setParameter('city', 'Karlsruhe') + ->setParameter('country', 'Germany') ->getSingleResult(); $this->assertEquals($person, $loadedPerson); - $this->assertNull($this->_em->createQuery($selectDql)->setParameter('city', 'asdf')->getOneOrNullResult()); + $this->assertNull( + $this->_em->createQuery($selectDql) + ->setParameter('city', 'asdf') + ->setParameter('country', 'Germany') + ->getOneOrNullResult() + ); // UPDATE - $updateDql = "UPDATE " . __NAMESPACE__ . "\\DDC93Person p SET p.address.street = :street WHERE p.address.city = :city"; + $updateDql = "UPDATE " . __NAMESPACE__ . "\\DDC93Person p SET p.address.street = :street, p.address.country.name = :country WHERE p.address.city = :city"; $this->_em->createQuery($updateDql) ->setParameter('street', 'Boo') + ->setParameter('country', 'DE') ->setParameter('city', 'Karlsruhe') ->execute(); $this->_em->refresh($person); $this->assertEquals('Boo', $person->address->street); + $this->assertEquals('DE', $person->address->country->name); // DELETE - $this->_em->createQuery("DELETE " . __NAMESPACE__ . "\\DDC93Person p WHERE p.address.city = :city") + $this->_em->createQuery("DELETE " . __NAMESPACE__ . "\\DDC93Person p WHERE p.address.city = :city AND p.address.country.name = :country") ->setParameter('city', 'Karlsruhe') + ->setParameter('country', 'DE') ->execute(); $this->_em->clear(); @@ -165,43 +183,24 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($car, $reloadedCar); } - public function testEmbeddableWithinEmbeddable() - { - $this->setExpectedException( - 'Doctrine\ORM\Mapping\MappingException', - sprintf( - "You embedded one or more embeddables in embeddable '%s', but this behavior is currently unsupported.", - __NAMESPACE__ . '\DDC93ContactInfo' - ) - ); - - $this->_schemaTool->createSchema(array( - $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93Customer'), - $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93ContactInfo'), - $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC93PhoneNumber') - )); - } - public function testInlineEmbeddableWithPrefix() { - $expectedColumnName = 'foobar_id'; + $metadata = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonWithPrefix'); - $actualColumnName = $this->_em - ->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonWithPrefix') - ->getColumnName('id.id'); - - $this->assertEquals($expectedColumnName, $actualColumnName); + $this->assertEquals('foobar_id', $metadata->getColumnName('id.id')); + $this->assertEquals('bloo_foo_id', $metadata->getColumnName('nested.nestedWithPrefix.id')); + $this->assertEquals('bloo_nestedWithEmptyPrefix_id', $metadata->getColumnName('nested.nestedWithEmptyPrefix.id')); + $this->assertEquals('bloo_id', $metadata->getColumnName('nested.nestedWithPrefixFalse.id')); } public function testInlineEmbeddableEmptyPrefix() { - $expectedColumnName = 'id_id'; + $metadata = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonEmptyPrefix'); - $actualColumnName = $this->_em - ->getClassMetadata(__NAMESPACE__ . '\DDC3028PersonEmptyPrefix') - ->getColumnName('id.id'); - - $this->assertEquals($expectedColumnName, $actualColumnName); + $this->assertEquals('id_id', $metadata->getColumnName('id.id')); + $this->assertEquals('nested_foo_id', $metadata->getColumnName('nested.nestedWithPrefix.id')); + $this->assertEquals('nested_nestedWithEmptyPrefix_id', $metadata->getColumnName('nested.nestedWithEmptyPrefix.id')); + $this->assertEquals('nested_id', $metadata->getColumnName('nested.nestedWithPrefixFalse.id')); } public function testInlineEmbeddablePrefixFalse() @@ -223,6 +222,22 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertTrue($isFieldMapped); } + + public function testThrowsExceptionOnInfiniteEmbeddableNesting() + { + $this->setExpectedException( + 'Doctrine\ORM\Mapping\MappingException', + sprintf( + 'Infinite nesting detected for embedded property %s::nested. ' . + 'You cannot embed an embeddable from the same type inside an embeddable.', + __NAMESPACE__ . '\DDCInfiniteNestingEmbeddable' + ) + ); + + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDCInfiniteNestingEmbeddable'), + )); + } } @@ -297,6 +312,24 @@ class DDC93Car extends DDC93Vehicle { } +/** + * @Embeddable + */ +class DDC93Country +{ + const CLASSNAME = __CLASS__; + + /** + * @Column(type="string", nullable=true) + */ + public $name; + + public function __construct($name = null) + { + $this->name = $name; + } +} + /** * @Embeddable */ @@ -316,12 +349,15 @@ class DDC93Address * @Column(type="string") */ public $city; + /** @Embedded(class = "DDC93Country") */ + public $country; - public function __construct($street = null, $zip = null, $city = null) + public function __construct($street = null, $zip = null, $city = null, DDC93Country $country = null) { $this->street = $street; $this->zip = $zip; $this->city = $city; + $this->country = $country; } } @@ -338,8 +374,14 @@ class DDC93Customer /** @Embeddable */ class DDC93ContactInfo { + const CLASSNAME = __CLASS__; + + /** + * @Column(type="string") + */ + public $email; /** @Embedded(class = "DDC93Address") */ - private $address; + public $address; } /** @@ -352,9 +394,13 @@ class DDC3028PersonWithPrefix /** @Embedded(class="DDC3028Id", columnPrefix = "foobar_") */ public $id; - public function __construct(DDC3028Id $id = null) + /** @Embedded(class="DDC3028NestedEmbeddable", columnPrefix = "bloo_") */ + public $nested; + + public function __construct(DDC3028Id $id = null, DDC3028NestedEmbeddable $nested = null) { $this->id = $id; + $this->nested = $nested; } } @@ -368,9 +414,13 @@ class DDC3028PersonEmptyPrefix /** @Embedded(class="DDC3028Id", columnPrefix = "") */ public $id; - public function __construct(DDC3028Id $id = null) + /** @Embedded(class="DDC3028NestedEmbeddable", columnPrefix = "") */ + public $nested; + + public function __construct(DDC3028Id $id = null, DDC3028NestedEmbeddable $nested = null) { $this->id = $id; + $this->nested = $nested; } } @@ -408,6 +458,33 @@ class DDC3028Id } } +/** + * @Embeddable + */ +class DDC3028NestedEmbeddable +{ + const CLASSNAME = __CLASS__; + + /** @Embedded(class="DDC3028Id", columnPrefix = "foo_") */ + public $nestedWithPrefix; + + /** @Embedded(class="DDC3028Id", columnPrefix = "") */ + public $nestedWithEmptyPrefix; + + /** @Embedded(class="DDC3028Id", columnPrefix = false) */ + public $nestedWithPrefixFalse; + + public function __construct( + DDC3028Id $nestedWithPrefix = null, + DDC3028Id $nestedWithEmptyPrefix = null, + DDC3028Id $nestedWithPrefixFalse = null + ) { + $this->nestedWithPrefix = $nestedWithPrefix; + $this->nestedWithEmptyPrefix = $nestedWithEmptyPrefix; + $this->nestedWithPrefixFalse = $nestedWithPrefixFalse; + } +} + /** * @MappedSuperclass */ @@ -426,3 +503,12 @@ abstract class DDC3027Animal class DDC3027Dog extends DDC3027Animal { } + +/** + * @Embeddable + */ +class DDCInfiniteNestingEmbeddable +{ + /** @Embedded(class="DDCInfiniteNestingEmbeddable") */ + public $nested; +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php index f810e367d..3827c4173 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php @@ -65,7 +65,9 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest array( 'name' => array( 'class' => 'Doctrine\Tests\Models\ValueObjects\Name', - 'columnPrefix' => 'nm_' + 'columnPrefix' => 'nm_', + 'declaredField' => null, + 'originalField' => null, ) ), $class->embeddedClasses From 0768916a0648fe548ab039d557abdc9da3f44bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steve=20M=C3=BCller?= Date: Tue, 12 Aug 2014 07:56:39 +0200 Subject: [PATCH 12/46] fix handling infinite nesting of embeddables --- .../ORM/Mapping/ClassMetadataFactory.php | 11 ++- .../Tests/ORM/Functional/ValueObjectsTest.php | 77 ++++++++++++++++++- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index cbb8c0cc9..876f1ce57 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -64,6 +64,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory */ private $evm; + /** + * @var array + */ + private $embeddablesActiveNesting = array(); + /** * @param EntityManager $em */ @@ -148,10 +153,12 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory continue; } - if ($embeddableClass['class'] === $class->name) { + if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { throw MappingException::infiniteEmbeddableNesting($class->name, $property); } + $this->embeddablesActiveNesting[$class->name] = true; + $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); if ($embeddableMetadata->isEmbeddedClass) { @@ -159,6 +166,8 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory } $class->inlineEmbeddable($property, $embeddableMetadata); + + unset($this->embeddablesActiveNesting[$class->name]); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php index 98aea6e47..28a7e2664 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php @@ -223,21 +223,32 @@ class ValueObjectsTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertTrue($isFieldMapped); } - public function testThrowsExceptionOnInfiniteEmbeddableNesting() + /** + * @dataProvider getInfiniteEmbeddableNestingData + */ + public function testThrowsExceptionOnInfiniteEmbeddableNesting($embeddableClassName, $declaredEmbeddableClassName) { $this->setExpectedException( 'Doctrine\ORM\Mapping\MappingException', sprintf( 'Infinite nesting detected for embedded property %s::nested. ' . 'You cannot embed an embeddable from the same type inside an embeddable.', - __NAMESPACE__ . '\DDCInfiniteNestingEmbeddable' + __NAMESPACE__ . '\\' . $declaredEmbeddableClassName ) ); $this->_schemaTool->createSchema(array( - $this->_em->getClassMetadata(__NAMESPACE__ . '\DDCInfiniteNestingEmbeddable'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\' . $embeddableClassName), )); } + + public function getInfiniteEmbeddableNestingData() + { + return array( + array('DDCInfiniteNestingEmbeddable', 'DDCInfiniteNestingEmbeddable'), + array('DDCNestingEmbeddable1', 'DDCNestingEmbeddable4'), + ); + } } @@ -512,3 +523,63 @@ class DDCInfiniteNestingEmbeddable /** @Embedded(class="DDCInfiniteNestingEmbeddable") */ public $nested; } + +/** + * @Embeddable + */ +class DDCNestingEmbeddable1 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable2") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable2 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable3") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable3 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable4") */ + public $nested; +} + +/** + * @Embeddable + */ +class DDCNestingEmbeddable4 +{ + /** @Embedded(class="DDC3028Id") */ + public $id1; + + /** @Embedded(class="DDC3028Id") */ + public $id2; + + /** @Embedded(class="DDCNestingEmbeddable1") */ + public $nested; +} From 133bd288bf0b6685437bd69c799138b92e3ebf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20Stamenkovi=C4=87?= Date: Tue, 12 Aug 2014 09:57:19 +0200 Subject: [PATCH 13/46] Minor CS fix --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 96a71de18..5d36f64ac 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -917,6 +917,7 @@ class ClassMetadataInfo implements ClassMetadata return clone $this->_prototype; } + /** * Restores some state that can not be serialized/unserialized. * From 2c3126353c85bd345757c223df2ccaaaaac10d7a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 15:33:09 +0200 Subject: [PATCH 14/46] DDC-3120 - adding instantiator dependency --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 8f00b5236..0321ff590 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "ext-pdo": "*", "doctrine/collections": "~1.2", "doctrine/dbal": ">=2.5-dev,<2.6-dev", + "doctrine/instantiator": "1.0.*", "symfony/console": "2.*" }, "require-dev": { From d52dd3959213a553b67bd7cdba259f3e38af88e1 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 15:38:55 +0200 Subject: [PATCH 15/46] DDC-3120 - add failing test for un-serialization of an internal PHP class --- .../Tests/ORM/Mapping/ClassMetadataTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 2c35dc192..456e9d2ac 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -1100,6 +1100,16 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->assertFalse($class->isIdentifier('foo')); } + + /** + * @group DDC-3120 + */ + public function testCanInstantiateInternalPhpClassSubclass() + { + $classMetadata = new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity'); + + $this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance()); + } } /** @@ -1136,3 +1146,7 @@ class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy return strtolower($this->classToTableName($className)) . '_' . $propertyName; } } + +class MyArrayObjectEntity extends \ArrayObject +{ +} From c2993bcdeb2873d876e2e70a88078d08babef7f4 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 15:39:58 +0200 Subject: [PATCH 16/46] DDC-3120 - add failing test for un-serialization of an internal PHP class from cached metadata instance --- .../Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 456e9d2ac..21ca6b835 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -1110,6 +1110,17 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance()); } + + /** + * @group DDC-3120 + */ + public function testCanInstantiateInternalPhpClassSubclassFromUnserializedMetadata() + { + /* @var $classMetadata ClassMetadata */ + $classMetadata = unserialize(serialize(new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity'))); + + $this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance()); + } } /** From f8a8437c9514467d1c6d90d7dd4e776756726e48 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 15:51:17 +0200 Subject: [PATCH 17/46] DDC-3120 - need to wakeup reflection BEFORE using any `ClassMetadata` API --- .../Tests/ORM/Mapping/ClassMetadataTest.php | 134 +++++++++--------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 21ca6b835..0ffb41c18 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -2,8 +2,10 @@ namespace Doctrine\Tests\ORM\Mapping; +use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Events; +use Doctrine\ORM\Mapping\DefaultNamingStrategy; require_once __DIR__ . '/../../Models/Global/GlobalNamespaceModel.php'; @@ -12,7 +14,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testClassMetadataInstanceSerialization() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); // Test initial state $this->assertTrue(count($cm->getReflectionProperties()) == 0); @@ -36,7 +38,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $serialized = serialize($cm); $cm = unserialize($serialized); - $cm->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->wakeupReflection(new RuntimeReflectionService()); // Check state $this->assertTrue(count($cm->getReflectionProperties()) > 0); @@ -61,7 +63,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testFieldIsNullable() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); // Explicit Nullable $cm->mapField(array('fieldName' => 'status', 'nullable' => true, 'type' => 'string', 'length' => 50)); @@ -84,7 +86,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; $cm = new ClassMetadata('DoctrineGlobal_Article'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany(array( 'fieldName' => 'author', 'targetEntity' => 'DoctrineGlobal_User', @@ -101,7 +103,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testMapManyToManyJoinTableDefaults() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany( array( 'fieldName' => 'groups', @@ -121,7 +123,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testSerializeManyToManyJoinTableCascade() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany( array( 'fieldName' => 'groups', @@ -143,7 +145,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; $cm = new ClassMetadata('DoctrineGlobal_User'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setDiscriminatorMap(array('descr' => 'DoctrineGlobal_Article', 'foo' => 'DoctrineGlobal_User')); $this->assertEquals("DoctrineGlobal_Article", $cm->discriminatorMap['descr']); @@ -158,7 +160,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; $cm = new ClassMetadata('DoctrineGlobal_User'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setSubclasses(array('DoctrineGlobal_Article')); $this->assertEquals("DoctrineGlobal_Article", $cm->subClasses[0]); @@ -174,7 +176,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $field['type'] = 'string'; $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); $cm->setVersionMapping($field); @@ -183,7 +185,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testGetSingleIdentifierFieldName_MultipleIdentifierEntity_ThrowsException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->isIdentifierComposite = true; $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); @@ -193,7 +195,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateAssociationMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $a1 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'); $a2 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'); @@ -206,7 +208,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateColumnName_ThrowsMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); @@ -217,7 +219,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateColumnName_DiscriminatorColumn_ThrowsMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); @@ -228,7 +230,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateColumnName_DiscriminatorColumn2_ThrowsMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setDiscriminatorColumn(array('name' => 'name')); @@ -239,7 +241,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateFieldAndAssociationMapping1_ThrowsException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); @@ -250,7 +252,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDuplicateFieldAndAssociationMapping2_ThrowsException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapOneToOne(array('fieldName' => 'name', 'targetEntity' => 'CmsUser')); @@ -264,7 +266,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testGetTemporaryTableNameSchema() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setTableName('foo.bar'); @@ -274,7 +276,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDefaultTableName() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); // When table's name is not given $primaryTable = array(); @@ -284,7 +286,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals('CmsUser', $cm->table['name']); $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); // When joinTable's name is not given $cm->mapManyToMany(array( 'fieldName' => 'user', @@ -298,7 +300,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testDefaultJoinColumnName() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); // this is really dirty, but it's the simplest way to test whether // joinColumn's name will be automatically set to user_id @@ -309,7 +311,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals('user_id', $cm->associationMappings['user']['joinColumns'][0]['name']); $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany(array( 'fieldName' => 'user', 'targetEntity' => 'CmsUser', @@ -372,7 +374,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testSetMultipleIdentifierSetsComposite() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name')); $cm->mapField(array('fieldName' => 'username')); @@ -387,7 +389,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testMappingNotFound() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "No mapping found for field 'foo' on class 'Doctrine\Tests\Models\CMS\CmsUser'."); $cm->getFieldMapping('foo'); @@ -399,7 +401,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testJoinTableMappingDefaults() { $cm = new ClassMetadata('DoctrineGlobal_Article'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser')); @@ -412,7 +414,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testMapIdentifierAssociation() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapOneToOne(array( 'fieldName' => 'article', @@ -431,7 +433,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testOrphanRemovalIdentifierAssociation() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'The orphan removal option is not allowed on an association that'); $cm->mapOneToOne(array( @@ -449,7 +451,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInverseIdentifierAssociation() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'An inverse association is not allowed to be identifier in'); @@ -468,7 +470,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testIdentifierAssociationManyToMany() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'Many-to-many or one-to-many associations are not allowed to be identifier in'); @@ -488,7 +490,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "The field or association mapping misses the 'fieldName' attribute in entity 'Doctrine\Tests\Models\CMS\CmsUser'."); $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => '')); } @@ -496,7 +498,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrievalOfNamedQueries() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->assertEquals(0, count($cm->getNamedQueries())); @@ -515,7 +517,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrievalOfResultSetMappings() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->assertEquals(0, count($cm->getSqlResultSetMappings())); @@ -535,7 +537,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testExistanceOfNamedQuery() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedQuery(array( @@ -553,7 +555,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrieveOfNamedNativeQuery() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedNativeQuery(array( 'name' => 'find-all', @@ -586,7 +588,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrieveOfSqlResultSetMapping() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addSqlResultSetMapping(array( 'name' => 'find-all', @@ -644,7 +646,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testExistanceOfSqlResultSetMapping() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addSqlResultSetMapping(array( 'name' => 'find-all', @@ -665,7 +667,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testExistanceOfNamedNativeQuery() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedNativeQuery(array( @@ -682,7 +684,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrieveOfNamedQuery() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedQuery(array( @@ -699,7 +701,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testRetrievalOfNamedNativeQueries() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->assertEquals(0, count($cm->getNamedNativeQueries())); @@ -720,7 +722,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase { $metadata = new ClassMetadata('Doctrine\Tests\Models\Company\CompanyContract'); - $metadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $metadata->initializeReflection(new RuntimeReflectionService()); $metadata->addEntityListener(\Doctrine\ORM\Events::prePersist, 'CompanyContractListener', 'prePersistHandler'); $metadata->addEntityListener(\Doctrine\ORM\Events::postPersist, 'CompanyContractListener', 'postPersistHandler'); @@ -737,7 +739,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNamingCollisionNamedQueryShouldThrowException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedQuery(array( 'name' => 'userById', @@ -759,7 +761,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNamingCollisionNamedNativeQueryShouldThrowException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedNativeQuery(array( 'name' => 'find-all', @@ -785,7 +787,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNamingCollisionSqlResultSetMappingShouldThrowException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addSqlResultSetMapping(array( 'name' => 'find-all', @@ -813,7 +815,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase { $user = new \Doctrine\Tests\Models\CMS\CmsUser(); $cm = new ClassMetadata('DOCTRINE\TESTS\MODELS\CMS\CMSUSER'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name); } @@ -824,11 +826,11 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testLifecycleCallbackNotFound() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addLifecycleCallback('notfound', 'postLoad'); $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "Entity 'Doctrine\Tests\Models\CMS\CmsUser' has no method 'notfound' to be registered as lifecycle callback."); - $cm->validateLifecycleCallbacks(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->validateLifecycleCallbacks(new RuntimeReflectionService()); } /** @@ -837,7 +839,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testTargetEntityNotFound() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'UnknownClass')); $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "The target-entity Doctrine\Tests\Models\CMS\UnknownClass cannot be found in 'Doctrine\Tests\Models\CMS\CmsUser#address'."); @@ -853,7 +855,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNameIsMandatoryForNamedQueryMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedQuery(array( 'query' => 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', )); @@ -868,7 +870,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNameIsMandatoryForNameNativeQueryMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addNamedQuery(array( 'query' => 'SELECT * FROM cms_users', 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', @@ -885,7 +887,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNameIsMandatoryForEntityNameSqlResultSetMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addSqlResultSetMapping(array( 'name' => 'find-all', 'entities' => array( @@ -903,7 +905,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testNameIsMandatoryForDiscriminatorColumnsMappingException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setDiscriminatorColumn(array()); } @@ -919,9 +921,9 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $articleMetadata = new ClassMetadata('DoctrineGlobal_Article', $namingStrategy); $routingMetadata = new ClassMetadata('Doctrine\Tests\Models\Routing\RoutingLeg',$namingStrategy); - $addressMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); - $articleMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); - $routingMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $addressMetadata->initializeReflection(new RuntimeReflectionService()); + $articleMetadata->initializeReflection(new RuntimeReflectionService()); + $routingMetadata->initializeReflection(new RuntimeReflectionService()); $addressMetadata->mapManyToMany(array( 'fieldName' => 'user', @@ -947,7 +949,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $namingStrategy = new MyPrefixNamingStrategy(); $metadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy); - $metadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $metadata->initializeReflection(new RuntimeReflectionService()); $metadata->mapField(array('fieldName'=>'country')); $metadata->mapField(array('fieldName'=>'city')); @@ -964,7 +966,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidCascade() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "You have specified invalid cascade options for Doctrine\Tests\Models\CMS\CmsUser::\$address: 'invalid'; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'"); @@ -980,7 +982,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidPropertyAssociationOverrideNameException() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Admin'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'DDC964Address')); $cm->setAssociationOverride('invalidPropertyName', array()); @@ -994,7 +996,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidPropertyAttributeOverrideNameException() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Guest'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name')); $cm->setAttributeOverride('invalidPropertyName', array()); @@ -1008,7 +1010,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidOverrideAttributeFieldTypeException() { $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Guest'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapField(array('fieldName' => 'name', 'type'=>'string')); $cm->setAttributeOverride('name', array('type'=>'date')); @@ -1023,7 +1025,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidEntityListenerClassException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addEntityListener(Events::postLoad, '\InvalidClassName', 'postLoadHandler'); } @@ -1037,7 +1039,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testInvalidEntityListenerMethodException() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->addEntityListener(Events::postLoad, '\Doctrine\Tests\Models\Company\CompanyContractListener', 'invalidMethod'); } @@ -1045,7 +1047,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testManyToManySelfReferencingNamingStrategyDefaults() { $cm = new ClassMetadata('Doctrine\Tests\Models\CustomType\CustomTypeParent'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->mapManyToMany( array( 'fieldName' => 'friendsWithMe', @@ -1072,7 +1074,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testSetSequenceGeneratorThrowsExceptionWhenSequenceNameIsMissing() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); $cm->setSequenceGeneratorDefinition(array()); @@ -1084,7 +1086,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase public function testQuotedSequenceName() { $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); - $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->initializeReflection(new RuntimeReflectionService()); $cm->setSequenceGeneratorDefinition(array('sequenceName' => '`foo`')); @@ -1119,6 +1121,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase /* @var $classMetadata ClassMetadata */ $classMetadata = unserialize(serialize(new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity'))); + $classMetadata->wakeupReflection(new RuntimeReflectionService()); + $this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance()); } } @@ -1132,7 +1136,7 @@ class DDC2700MappedSuperClass private $foo; } -class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy +class MyNamespacedNamingStrategy extends DefaultNamingStrategy { /** * {@inheritdoc} @@ -1147,7 +1151,7 @@ class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStra } } -class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy +class MyPrefixNamingStrategy extends DefaultNamingStrategy { /** * {@inheritdoc} From 361ec2a474d78168473fb82a041f32c4b7665643 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 15:51:48 +0200 Subject: [PATCH 18/46] DDC-3120 - using `Doctrine\Instantiator` when building new instances --- .../ORM/Mapping/ClassMetadataInfo.php | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 5d36f64ac..f8b4bb78a 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Mapping; use BadMethodCallException; +use Doctrine\Instantiator\Instantiator; use InvalidArgumentException; use RuntimeException; use Doctrine\DBAL\Types\Type; @@ -643,11 +644,9 @@ class ClassMetadataInfo implements ClassMetadata public $reflFields = array(); /** - * The prototype from which new instances of the mapped class are created. - * - * @var object + * @var \Doctrine\Instantiator\InstantiatorInterface|null */ - private $_prototype; + private $instantiator; /** * Initializes a new ClassMetadata instance that will hold the object-relational mapping @@ -661,6 +660,7 @@ class ClassMetadataInfo implements ClassMetadata $this->name = $entityName; $this->rootEntityName = $entityName; $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy(); + $this->instantiator = new Instantiator(); } /** @@ -907,15 +907,7 @@ class ClassMetadataInfo implements ClassMetadata */ public function newInstance() { - if ($this->_prototype === null) { - if (PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513) { - $this->_prototype = $this->reflClass->newInstanceWithoutConstructor(); - } else { - $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name)); - } - } - - return clone $this->_prototype; + return $this->instantiator->instantiate($this->name); } /** @@ -928,7 +920,8 @@ class ClassMetadataInfo implements ClassMetadata public function wakeupReflection($reflService) { // Restore ReflectionClass and properties - $this->reflClass = $reflService->getClass($this->name); + $this->reflClass = $reflService->getClass($this->name); + $this->instantiator = $this->instantiator ?: new Instantiator(); foreach ($this->fieldMappings as $field => $mapping) { if (isset($mapping['declaredField'])) { From 7b145f8269ba2e9a07dede69daaa44fee6d74ef0 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Aug 2014 16:55:32 +0200 Subject: [PATCH 19/46] DDC-3120 - requiring `doctrine\instantiator:~1.0.1` as of doctrine/instantiator#4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0321ff590..a216eb192 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "ext-pdo": "*", "doctrine/collections": "~1.2", "doctrine/dbal": ">=2.5-dev,<2.6-dev", - "doctrine/instantiator": "1.0.*", + "doctrine/instantiator": "~1.0.1", "symfony/console": "2.*" }, "require-dev": { From 9b7318ab4c1fe09b7b9e58a683daadb4fdd2e0d5 Mon Sep 17 00:00:00 2001 From: Logan Bailey Date: Thu, 14 Aug 2014 17:07:05 -0700 Subject: [PATCH 20/46] Changed table name to be more appropriate. This change assumes that the Article object references the articles tables, not the user table. --- docs/en/reference/working-with-objects.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index a402be88c..a7e03bcc9 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -114,7 +114,7 @@ from newly opened EntityManager. $article = $em->find('Article', 1); This code only retrieves the ``Article`` instance with id 1 executing -a single SELECT statement against the user table in the database. +a single SELECT statement against the articles table in the database. You can still access the associated properties author and comments and the associated objects they contain. From edc2ed951253cdc8b927ac67ab55f4e72be3f9c4 Mon Sep 17 00:00:00 2001 From: Vincent Composieux Date: Fri, 15 Aug 2014 15:39:56 +0200 Subject: [PATCH 21/46] Fix QueryException::instanceOfUnrelatedClass() message --- lib/Doctrine/ORM/Query/QueryException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Query/QueryException.php b/lib/Doctrine/ORM/Query/QueryException.php index f2fb61c71..16a10856a 100644 --- a/lib/Doctrine/ORM/Query/QueryException.php +++ b/lib/Doctrine/ORM/Query/QueryException.php @@ -248,7 +248,7 @@ class QueryException extends \Doctrine\ORM\ORMException public static function instanceOfUnrelatedClass($className, $rootClass) { return new self("Cannot check if a child of '" . $rootClass . "' is instanceof '" . $className . "', " . - "inheritance hierarchy exists between these two classes."); + "inheritance hierarchy does not exists between these two classes."); } /** From a665cb0229a9caf53b29b2f42b436caf24e169a1 Mon Sep 17 00:00:00 2001 From: Giorgio Premi Date: Mon, 18 Aug 2014 12:02:51 +0200 Subject: [PATCH 22/46] DefaultRepositoryFactory: single repository for aliased entities --- .../ORM/Repository/DefaultRepositoryFactory.php | 10 ++++++---- .../ORM/Functional/EntityRepositoryTest.php | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index 2774dea68..d756ed4f9 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -43,13 +43,15 @@ class DefaultRepositoryFactory implements RepositoryFactory { $entityName = ltrim($entityName, '\\'); - if (isset($this->repositoryList[$entityName])) { - return $this->repositoryList[$entityName]; + $class = $entityManager->getClassMetadata($entityName)->getName(); + + if (isset($this->repositoryList[$class])) { + return $this->repositoryList[$class]; } $repository = $this->createRepository($entityManager, $entityName); - $this->repositoryList[$entityName] = $repository; + $this->repositoryList[$class] = $repository; return $repository; } @@ -74,4 +76,4 @@ class DefaultRepositoryFactory implements RepositoryFactory return new $repositoryClassName($entityManager, $metadata); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 12b941efc..193497a1b 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -611,6 +611,23 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository"); } + public function testSingleRepositoryInstanceForAnEntity() + { + $config = $this->_em->getConfiguration(); + $config->addEntityNamespace('Aliased', 'Doctrine\Tests\Models\CMS'); + $config->addEntityNamespace('AliasedAgain', 'Doctrine\Tests\Models\CMS'); + + $this->assertSame( + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'), + $this->_em->getRepository('Aliased:CmsUser') + ); + + $this->assertSame( + $this->_em->getRepository('Aliased:CmsUser'), + $this->_em->getRepository('AliasedAgain:CmsUser') + ); + } + /** * @group DDC-1376 * From 7865de92abcbf714e2bd9360cd3940e8d86be175 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:01:52 +0200 Subject: [PATCH 23/46] #1112 - renamed $class to $className --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index d756ed4f9..a0564ba94 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -43,15 +43,15 @@ class DefaultRepositoryFactory implements RepositoryFactory { $entityName = ltrim($entityName, '\\'); - $class = $entityManager->getClassMetadata($entityName)->getName(); + $className = $entityManager->getClassMetadata($entityName)->getName(); - if (isset($this->repositoryList[$class])) { - return $this->repositoryList[$class]; + if (isset($this->repositoryList[$className])) { + return $this->repositoryList[$className]; } $repository = $this->createRepository($entityManager, $entityName); - $this->repositoryList[$class] = $repository; + $this->repositoryList[$className] = $repository; return $repository; } From 3fed769b4030a5b5f4342c9cbee9a287482f4d92 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:02:34 +0200 Subject: [PATCH 24/46] #1112 - avoiding useless assignments/splitted return statement --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index a0564ba94..e7f0aca13 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -49,11 +49,7 @@ class DefaultRepositoryFactory implements RepositoryFactory return $this->repositoryList[$className]; } - $repository = $this->createRepository($entityManager, $entityName); - - $this->repositoryList[$className] = $repository; - - return $repository; + return $this->repositoryList[$className] = $this->createRepository($entityManager, $entityName); } /** From 01f22988b17e5b2d93438a0cc502b830d5816899 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:06:37 +0200 Subject: [PATCH 25/46] #1112 - cleaning up repository test - makes assertions more clear/simpler to read --- .../Tests/ORM/Functional/EntityRepositoryTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 193497a1b..4f11adc84 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -611,21 +611,17 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository"); } - public function testSingleRepositoryInstanceForAnEntity() + public function testSingleRepositoryInstanceForDifferentEntityAliases() { $config = $this->_em->getConfiguration(); + $config->addEntityNamespace('Aliased', 'Doctrine\Tests\Models\CMS'); $config->addEntityNamespace('AliasedAgain', 'Doctrine\Tests\Models\CMS'); - $this->assertSame( - $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'), - $this->_em->getRepository('Aliased:CmsUser') - ); + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); - $this->assertSame( - $this->_em->getRepository('Aliased:CmsUser'), - $this->_em->getRepository('AliasedAgain:CmsUser') - ); + $this->assertSame($repository, $this->_em->getRepository('Aliased:CmsUser')); + $this->assertSame($repository, $this->_em->getRepository('AliasedAgain:CmsUser')); } /** From ae16afa42899ffa70f179010c3e9fb47c0e7e946 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:07:07 +0200 Subject: [PATCH 26/46] #1112 - adding DDC-3257 group to test method --- tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 4f11adc84..59778b42d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -611,6 +611,9 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository"); } + /** + * @group DDC-3257 + */ public function testSingleRepositoryInstanceForDifferentEntityAliases() { $config = $this->_em->getConfiguration(); From 36bbd28b75f6ee6bc4596e306fd20feaba7f8b31 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:11:39 +0200 Subject: [PATCH 27/46] #1112 - adding test to verify that leading backslash is not relevant when fetching repositories --- .../Tests/ORM/Functional/EntityRepositoryTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 59778b42d..705802306 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -627,6 +627,17 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertSame($repository, $this->_em->getRepository('AliasedAgain:CmsUser')); } + /** + * @group DDC-3257 + */ + public function testCanRetrieveRepositoryFromClassNameWithLeadingBackslash() + { + $this->assertSame( + $this->_em->getRepository('\\Doctrine\\Tests\\Models\\CMS\\CmsUser'), + $this->_em->getRepository('Doctrine\\Tests\\Models\\CMS\\CmsUser') + ); + } + /** * @group DDC-1376 * From 19d3552f2a36ab7f005f59615f5119961f2a71a7 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:14:53 +0200 Subject: [PATCH 28/46] #1112 - Removing useless trimming of the entity name being passed in --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index e7f0aca13..24f5f2f84 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -41,8 +41,6 @@ class DefaultRepositoryFactory implements RepositoryFactory */ public function getRepository(EntityManagerInterface $entityManager, $entityName) { - $entityName = ltrim($entityName, '\\'); - $className = $entityManager->getClassMetadata($entityName)->getName(); if (isset($this->repositoryList[$className])) { From bf03694e28b3c5e080114caf845ba3b5338eef61 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:16:45 +0200 Subject: [PATCH 29/46] #1112 - Yoday need you may, better IDE hinting as well needed is. --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index 24f5f2f84..ae46c2438 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -60,10 +60,11 @@ class DefaultRepositoryFactory implements RepositoryFactory */ protected function createRepository(EntityManagerInterface $entityManager, $entityName) { + /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */ $metadata = $entityManager->getClassMetadata($entityName); $repositoryClassName = $metadata->customRepositoryClassName; - if ($repositoryClassName === null) { + if (null === $repositoryClassName) { $configuration = $entityManager->getConfiguration(); $repositoryClassName = $configuration->getDefaultRepositoryClassName(); } From aab7fce2d403ddee4cff2a3c50e2aa6290e567fe Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:17:54 +0200 Subject: [PATCH 30/46] #1112 - Elvis operator reduces code duplication even more --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index ae46c2438..b09430816 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -62,12 +62,8 @@ class DefaultRepositoryFactory implements RepositoryFactory { /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */ $metadata = $entityManager->getClassMetadata($entityName); - $repositoryClassName = $metadata->customRepositoryClassName; - - if (null === $repositoryClassName) { - $configuration = $entityManager->getConfiguration(); - $repositoryClassName = $configuration->getDefaultRepositoryClassName(); - } + $repositoryClassName = $metadata->customRepositoryClassName + ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName(); return new $repositoryClassName($entityManager, $metadata); } From dfbaac0401dd146194708e52043800ed9b573ac0 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Mon, 18 Aug 2014 15:18:59 +0200 Subject: [PATCH 31/46] #1112 - Fixed type-hint that is incompatible with most IDEs --- lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php index b09430816..b9afbfabf 100644 --- a/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php +++ b/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php @@ -32,7 +32,7 @@ class DefaultRepositoryFactory implements RepositoryFactory /** * The list of EntityRepository instances. * - * @var array<\Doctrine\Common\Persistence\ObjectRepository> + * @var \Doctrine\Common\Persistence\ObjectRepository[] */ private $repositoryList = array(); From 613119599febb05399c8f8037b4168745e016c42 Mon Sep 17 00:00:00 2001 From: Thomas Tourlourat Date: Thu, 21 Aug 2014 10:42:22 +0200 Subject: [PATCH 32/46] Fix wrong variable name --- docs/en/reference/second-level-cache.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index 03d5b6de4..d88e83fc6 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -466,7 +466,7 @@ Basic entity cache $country1 = $em->find('Country', 1); // Retrieve item from cache $country->setName("New Name"); - $em->persist($state); + $em->persist($country); $em->flush(); // Hit database to update the row and update cache $em->clear(); // Clear entity manager From ad1f228ef68a1ac1ed80b83125ef3ea93d37ee0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steve=20M=C3=BCller?= Date: Fri, 22 Aug 2014 09:26:54 +0200 Subject: [PATCH 33/46] fix DocBlock --- lib/Doctrine/ORM/Cache/CacheConfiguration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Cache/CacheConfiguration.php b/lib/Doctrine/ORM/Cache/CacheConfiguration.php index 760352314..4891cac49 100644 --- a/lib/Doctrine/ORM/Cache/CacheConfiguration.php +++ b/lib/Doctrine/ORM/Cache/CacheConfiguration.php @@ -85,7 +85,7 @@ class CacheConfiguration } /** - * @return \Doctrine\ORM\Cache\QueryCacheValidator + * @return \Doctrine\ORM\Cache\RegionsConfiguration */ public function getRegionsConfiguration() { From e7739d9411f119c1d01a4d64e63a3ba95e4f71cd Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 22 Aug 2014 13:42:43 +0200 Subject: [PATCH 34/46] Enabled colors for the PHPUnit output on Travis --- tests/travis/mysql.travis.xml | 2 +- tests/travis/pgsql.travis.xml | 4 ++-- tests/travis/sqlite.travis.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/travis/mysql.travis.xml b/tests/travis/mysql.travis.xml index 8319d1466..84c8fa1b3 100644 --- a/tests/travis/mysql.travis.xml +++ b/tests/travis/mysql.travis.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/travis/pgsql.travis.xml b/tests/travis/pgsql.travis.xml index 75c831dd1..8b053576c 100644 --- a/tests/travis/pgsql.travis.xml +++ b/tests/travis/pgsql.travis.xml @@ -1,5 +1,5 @@ - + @@ -36,4 +36,4 @@ - \ No newline at end of file + diff --git a/tests/travis/sqlite.travis.xml b/tests/travis/sqlite.travis.xml index 5233adeb6..f9b3ef1f3 100644 --- a/tests/travis/sqlite.travis.xml +++ b/tests/travis/sqlite.travis.xml @@ -1,5 +1,5 @@ - + @@ -18,4 +18,4 @@ - \ No newline at end of file + From 8d3fba55408d078a180afb9928ade04063e64d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steve=20M=C3=BCller?= Date: Tue, 26 Aug 2014 19:46:17 +0200 Subject: [PATCH 35/46] improve schema validator error message for invalid bi-directional relations --- lib/Doctrine/ORM/Tools/SchemaValidator.php | 2 +- .../Tests/ORM/Tools/SchemaValidatorTest.php | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Tools/SchemaValidator.php b/lib/Doctrine/ORM/Tools/SchemaValidator.php index 0db5b7e0e..6652e4966 100644 --- a/lib/Doctrine/ORM/Tools/SchemaValidator.php +++ b/lib/Doctrine/ORM/Tools/SchemaValidator.php @@ -124,7 +124,7 @@ class SchemaValidator $ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ". "bi-directional relationship, but the specified mappedBy association on the target-entity ". $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ". - "'inversedBy=".$fieldName."' attribute."; + "'inversedBy=\"" . $fieldName . "\"' attribute."; } elseif ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) { $ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ". diff --git a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php index 7858253f1..f36ed162a 100644 --- a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php @@ -134,6 +134,24 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmTestCase "The referenced column name 'id' has to be a primary key column on the target entity class 'Doctrine\Tests\ORM\Tools\DDC1649Two'." ), $ce); } + + /** + * @group DDC-3274 + */ + public function testInvalidBiDirectionalRelationMappingMissingInversedByAttribute() + { + $class = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC3274One'); + $ce = $this->validator->validateClass($class); + + $this->assertEquals( + array( + "The field Doctrine\Tests\ORM\Tools\DDC3274One#two is on the inverse side of a bi-directional " . + "relationship, but the specified mappedBy association on the target-entity " . + "Doctrine\Tests\ORM\Tools\DDC3274Two#one does not contain the required 'inversedBy=\"two\"' attribute." + ), + $ce + ); + } } /** @@ -263,3 +281,30 @@ class DDC1649Three private $two; } +/** + * @Entity + */ +class DDC3274One +{ + /** + * @Id @Column @GeneratedValue + */ + private $id; + + /** + * @OneToMany(targetEntity="DDC3274Two", mappedBy="one") + */ + private $two; +} + +/** + * @Entity + */ +class DDC3274Two +{ + /** + * @Id + * @ManyToOne(targetEntity="DDC3274One") + */ + private $one; +} From 02ba144c8dfa320e58f20cc9c8ebc5247fce29ef Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 27 Aug 2014 01:55:28 +0200 Subject: [PATCH 36/46] Adding test to verify SQL generation with an expression in `COUNT()` --- .../Tests/ORM/Query/SelectSqlGenerationTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index e886307f6..0a35b3bdb 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -263,6 +263,21 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } + public function testSupportsAggregateCountFunctionWithSimpleArithmetic() + { + $connMock = $this->_em->getConnection(); + $orgPlatform = $connMock->getDatabasePlatform(); + + $connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform); + + $this->assertSqlGeneration( + 'SELECT COUNT(CONCAT(u.id, u.name)) FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id', + 'SELECT COUNT(CONCAT(c0_.id, c0_.name)) AS sclr_0 FROM cms_users c0_ GROUP BY c0_.id' + ); + + $connMock->setDatabasePlatform($orgPlatform); + } + public function testSupportsWhereClauseWithPositionalParameter() { $this->assertSqlGeneration( From 097840dc935e1cfbc93fc673be077a8fe67e8e52 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 27 Aug 2014 01:56:11 +0200 Subject: [PATCH 37/46] Allowing expression in `COUNT()` DQL aggregation functions --- lib/Doctrine/ORM/Query/Parser.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index c64e731c6..ab47121ee 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -2962,9 +2962,7 @@ class Parser $isDistinct = true; } - $pathExp = ($lookaheadType === Lexer::T_COUNT) - ? $this->SingleValuedPathExpression() - : $this->SimpleArithmeticExpression(); + $pathExp = $this->SimpleArithmeticExpression(); $this->match(Lexer::T_CLOSE_PARENTHESIS); From a2e0133a94bf235498ee2e805c8ca9a147b7fa24 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 27 Aug 2014 02:01:56 +0200 Subject: [PATCH 38/46] Adding DDC-3276 test group --- tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 0a35b3bdb..0b5a60c96 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -263,6 +263,9 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } + /** + * @group DDC-3276 + */ public function testSupportsAggregateCountFunctionWithSimpleArithmetic() { $connMock = $this->_em->getConnection(); From 45d74e72203dc47cfc889132491114351657830e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 27 Aug 2014 02:12:08 +0200 Subject: [PATCH 39/46] DDC-3276 - #1122 - updating EBNF in docblock to reflect new syntax support --- lib/Doctrine/ORM/Query/Parser.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index ab47121ee..fea4f9a12 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -2939,8 +2939,7 @@ class Parser /** * AggregateExpression ::= - * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | - * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")" + * ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")" * * @return \Doctrine\ORM\Query\AST\AggregateExpression */ From 48a86511cb8a225c060b337ffcb6c338f7e6ed4b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 27 Aug 2014 02:17:08 +0200 Subject: [PATCH 40/46] DDC-3276 - #1122 - updating EBNF in documentation to reflect new syntax support --- docs/en/reference/dql-doctrine-query-language.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/en/reference/dql-doctrine-query-language.rst b/docs/en/reference/dql-doctrine-query-language.rst index e8348350e..0161eecf9 100644 --- a/docs/en/reference/dql-doctrine-query-language.rst +++ b/docs/en/reference/dql-doctrine-query-language.rst @@ -1626,8 +1626,7 @@ Aggregate Expressions .. code-block:: php - AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | - "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")" + AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")" Case Expressions ~~~~~~~~~~~~~~~~ From 00eb0d3b67f19c98f5949bfceac713f0a454ff02 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 27 Aug 2014 13:56:02 +0200 Subject: [PATCH 41/46] Fixed the structure of the reverse-engineered mapping --- lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index ce35e7e9f..e51c15282 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -407,7 +407,7 @@ class DatabaseDriver implements MappingDriver case Type::STRING: case Type::TEXT: $fieldMapping['length'] = $column->getLength(); - $fieldMapping['fixed'] = $column->getFixed(); + $fieldMapping['options']['fixed'] = $column->getFixed(); break; case Type::DECIMAL: @@ -419,18 +419,18 @@ class DatabaseDriver implements MappingDriver case Type::INTEGER: case Type::BIGINT: case Type::SMALLINT: - $fieldMapping['unsigned'] = $column->getUnsigned(); + $fieldMapping['options']['unsigned'] = $column->getUnsigned(); break; } // Comment if (($comment = $column->getComment()) !== null) { - $fieldMapping['comment'] = $comment; + $fieldMapping['options']['comment'] = $comment; } // Default if (($default = $column->getDefault()) !== null) { - $fieldMapping['default'] = $default; + $fieldMapping['options']['default'] = $default; } return $fieldMapping; From f0c02bb6d96efdd40211c30d1fabbdf12d7c8ffc Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 27 Aug 2014 14:00:34 +0200 Subject: [PATCH 42/46] Fixed the test expectations for the DatabaseDriver --- tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php b/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php index 17285ac20..64295f3cf 100644 --- a/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php @@ -189,14 +189,14 @@ class DatabaseDriverTest extends DatabaseDriverTestCase if ( ! $this->_em->getConnection()->getDatabasePlatform() instanceof PostgreSqlPlatform AND ! $this->_em->getConnection()->getDatabasePlatform() instanceof SQLServerPlatform) { $this->assertArrayHasKey('columnUnsigned', $metadata->fieldMappings); - $this->assertTrue($metadata->fieldMappings['columnUnsigned']['unsigned']); + $this->assertTrue($metadata->fieldMappings['columnUnsigned']['options']['unsigned']); } $this->assertArrayHasKey('columnComment', $metadata->fieldMappings); - $this->assertEquals('test_comment', $metadata->fieldMappings['columnComment']['comment']); + $this->assertEquals('test_comment', $metadata->fieldMappings['columnComment']['options']['comment']); $this->assertArrayHasKey('columnDefault', $metadata->fieldMappings); - $this->assertEquals('test_default', $metadata->fieldMappings['columnDefault']['default']); + $this->assertEquals('test_default', $metadata->fieldMappings['columnDefault']['options']['default']); $this->assertArrayHasKey('columnDecimal', $metadata->fieldMappings); $this->assertEquals(4, $metadata->fieldMappings['columnDecimal']['precision']); From 398688ab3821a726e3a304822812e3a0a60340cb Mon Sep 17 00:00:00 2001 From: Ka Date: Fri, 29 Aug 2014 08:42:14 +0200 Subject: [PATCH 43/46] Update improving-performance.rst --- docs/en/reference/improving-performance.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/reference/improving-performance.rst b/docs/en/reference/improving-performance.rst index 9bc4c8632..affaf2606 100644 --- a/docs/en/reference/improving-performance.rst +++ b/docs/en/reference/improving-performance.rst @@ -62,3 +62,7 @@ A lot of the points mentioned in the Best Practices chapter will also positively affect the performance of Doctrine. +Change Tracking policies +------------------------ + +See Change tracking policies chapter From 2120d4102997af66c7971839764a81578e9dba60 Mon Sep 17 00:00:00 2001 From: Ka Date: Fri, 29 Aug 2014 08:47:28 +0200 Subject: [PATCH 44/46] add a link to said chapter --- docs/en/reference/improving-performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/improving-performance.rst b/docs/en/reference/improving-performance.rst index affaf2606..d9de6c808 100644 --- a/docs/en/reference/improving-performance.rst +++ b/docs/en/reference/improving-performance.rst @@ -65,4 +65,4 @@ also positively affect the performance of Doctrine. Change Tracking policies ------------------------ -See Change tracking policies chapter +See: :doc:`Change Tracking Policies ` From 1378626937a3d6d1331a136e9514e80d10d0aa3b Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti Date: Fri, 29 Aug 2014 22:49:23 -0300 Subject: [PATCH 45/46] Fixed new line in docblock (247803715bd7e5ded75e25dbbb4eb2c5b7fbd2f2). --- lib/Doctrine/ORM/Tools/EntityGenerator.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index e04b15801..72b254e58 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -219,6 +219,7 @@ class EntityGenerator '/** * * + * * @return */ public function () @@ -233,6 +234,7 @@ public function () '/** * * + * * @param $ * * @return @@ -251,6 +253,7 @@ public function ($) '/** * * + * * @param $ * * @return @@ -269,6 +272,7 @@ public function ($) '/** * * + * * @param $ */ public function ($) @@ -1173,7 +1177,7 @@ public function __construct() } $replacements = array( - '' => ucfirst($type) . ' ' . $variableName . ".\n", + '' => ucfirst($type) . ' ' . $variableName, '' => $methodTypeHint, '' => $variableType, '' => $variableName, From f731a66e1c8a422fcb76a42ed005feb57de54509 Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti Date: Fri, 29 Aug 2014 23:11:49 -0300 Subject: [PATCH 46/46] Removed extra line breaks for docblocks in set, get, add and remove method templates. --- lib/Doctrine/ORM/Tools/EntityGenerator.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index 72b254e58..918e4162b 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -219,7 +219,6 @@ class EntityGenerator '/** * * - * * @return */ public function () @@ -234,7 +233,6 @@ public function () '/** * * - * * @param $ * * @return @@ -253,7 +251,6 @@ public function ($) '/** * * - * * @param $ * * @return @@ -272,7 +269,6 @@ public function ($) '/** * * - * * @param $ */ public function ($)