Compare commits

...

162 Commits

Author SHA1 Message Date
Marco Pivetta
bebacf79d8 Release 2.4.6 2014-10-06 15:22:50 +02:00
Steve Müller
d46fa4adeb Merge pull request #1154 from Ocramius/hotfix/PHP-5.6-serialization-fix
DDC-3120 - PHP 5.6 internal classes/Serializable serialization fix
2014-10-06 15:08:37 +02:00
Marco Pivetta
64061bafaf DDC-3120 - Adding PHP 5.6 to build matrix 2014-10-06 14:28:05 +02:00
Marco Pivetta
a69584a841 DDC-3120 - Using ReflectionClass#newInstanceWithoutConstructor() also with PHP 5.6+ 2014-10-06 14:26:00 +02:00
Marco Pivetta
8fc1c34b29 DDC-3120 - metadata should be waked up before attempting new instance creation 2014-10-06 14:25:16 +02:00
Marco Pivetta
0d683c1897 DDC-3120 - metadata should be initialized before attempting new instance creation 2014-10-06 14:22:06 +02:00
Marco Pivetta
60b75fefed DDC-3120 - add failing test for un-serialization of an internal PHP class from cached metadata instance 2014-10-06 14:13:40 +02:00
Marco Pivetta
0a7e0617cc DDC-3120 - add failing test for un-serialization of an internal PHP class 2014-10-06 14:13:32 +02:00
Marco Pivetta
072e1eee7b Bump version to 2.4.6 2014-09-23 00:04:35 +02:00
Marco Pivetta
c0d3cdbdfb Release 2.4.5 2014-09-22 23:58:51 +02:00
Marco Pivetta
a50ae2c898 Merge pull request #1142 from TwoWholeWorms/2.4
func_get_args() call order fix for HHVM bug
2014-09-22 23:43:46 +02:00
Benjamin Nolan
dbbe7a4be5 Fix for HHVM 2014-09-22 20:00:15 +01:00
Marco Pivetta
406e177062 Bump version to 2.4.5 2014-07-11 05:13:19 +02:00
Marco Pivetta
fc19c3b53d Release 2.4.4 2014-07-11 05:05:53 +02:00
Marco Pivetta
5c5abb6771 Merge branch 'hotfix/DDC-3208-backport-DDC-3160' into 2.4 2014-07-11 04:49:42 +02:00
Marco Pivetta
42226dadd1 DDC-3208 - hotfix for DDC-3160 backported to 2.4.x 2014-07-11 04:49:30 +02:00
Benjamin Eberlei
84f8ef5ca4 Bump version to 2.4.4 2014-06-10 13:49:09 +02:00
Benjamin Eberlei
8a13376d42 Release 2.4.3 2014-06-10 13:49:08 +02:00
Marco Pivetta
8b5632cb65 The proxy factory always expects non-null identifier values 2014-06-10 13:48:35 +02:00
Benjamin Eberlei
859465b691 Fix wrong version 2014-06-03 21:43:21 +02:00
Benjamin Eberlei
530c01b5e3 [DDC-3120] Fix bug with unserialize bc break in PHP 5.4.29 and PHP 5.5.13 2014-06-03 17:36:31 +02:00
Marco Pivetta
63c5758070 Merge pull request #784 from eventhorizonpl/fix_docs
fix documentation warnings p1
Conflicts:
	docs/en/reference/advanced-configuration.rst
2014-04-21 05:07:57 +00:00
Benjamin Eberlei
2a9a53ae9d Merge branch 'DDC-3076' into 2.4 2014-04-17 00:03:39 +02:00
Frank Liepert
0081319712 [DDC-3076] Add/Improve tests 2014-04-17 00:03:11 +02:00
Frank Liepert
78ceda7ecf [DDC-3076] Fix ObjectHydrator 2014-04-17 00:03:11 +02:00
Frank Liepert
1f4810e370 [DDC-3076] Add test 2014-04-17 00:03:11 +02:00
Frank
376a3ac3b6 Fix: handle invalid discriminator value 2014-04-17 00:03:11 +02:00
Frank
ab87dd6325 Add: invalidDiscriminatorValue method 2014-04-17 00:03:11 +02:00
Guilherme Blanco
2ae245db30 Fixes DDC-2984. Made DDC-742 more resilient to recurring failures. 2014-04-16 23:41:53 +02:00
Benjamin Eberlei
9d36e855c0 Disable SQLServer platform related test, because of a wrong merge into 2.4 2014-03-23 16:38:05 +01:00
Benjamin Eberlei
f7c87cddd8 Merge branch 'DDC-2997' into 2.4 2014-03-23 15:38:07 +01:00
Alexandru Patranescu
1566b8a057 allow passing EntityManagerInterface when creating a HelperSet 2014-03-23 15:37:07 +01:00
Benjamin Eberlei
333fa1090a Merge branch 'DDC-3018' into 2.4 2014-03-23 15:17:56 +01:00
Benjamin Eberlei
0262b083bb [DDC-3018] Fix string literals in new operator. 2014-03-23 15:17:47 +01:00
Benjamin Eberlei
60c9c27c08 Merge branch 'DDC-2996' into 2.4 2014-03-23 13:19:43 +01:00
Benjamin Eberlei
8b75e3563a [DDC-2996] Fix bug in UnitOfWork#recomputeSingleEntityChangeSet
When calling UnitOfWork#recomputeSingleEntityChangeSet on an entity
that didn't have a changeset before, the computation was ignored.
This method however is suggested to be used in "onFlush" and "preFlush"
events in the documentation.

Also fix a bug where recomputeSingleEntityChangeSet was used
before calculating a real changeset for an object.
2014-03-23 13:19:22 +01:00
Benjamin Eberlei
cbf16f1cf8 Merge branch 'DDC-3033' into 2.4 2014-03-23 12:41:23 +01:00
Benjamin Eberlei
b84c828ea1 [DDC-3033] Clarify restrictions in events. 2014-03-23 12:40:56 +01:00
Benjamin Eberlei
55b7e4cff2 [DDC-3033] Fix bug in UnitOfWork#recomputeSingleEntityChangeSet.
The fix for DDC-2624 had a side effect on recomputation of
changesets in preUpdate events. The method wasn't adjusted
to the changes in its sister method computeChangeSet() and
had wrong assumptions about the computation.

Especially:
1. Collections have to be skipped
2. Comparison was changed to strict equality only.
2014-03-23 12:38:51 +01:00
Thomas Lallement
e38af55100 Update DDC3033Test.php 2014-03-23 12:38:51 +01:00
Thomas Lallement
7338c2d1f8 Update DDC3033Test.php 2014-03-23 12:38:51 +01:00
Thomas Lallement
0ff3cdf150 Failing Test (since commit 53a5a48aed)
Hi,

It seems to be a regression since the commit 53a5a48aed

Doctrine\ORM\PersistentCollection can be populated in $changeSet if you set a PreUpdate and PostUpdate event.

Original issue: http://www.doctrine-project.org/jira/browse/DDC-3033
2014-03-23 12:38:51 +01:00
Benjamin Eberlei
24c5c54c1e Merge branch 'DDC-3041' into 2.4 2014-03-23 10:18:36 +01:00
Menno Holtkamp
6bb367f488 Added test to ensure boolean metadata is properly exported/serialized to XML 2014-03-23 10:16:43 +01:00
Menno Holtkamp
213cc5c695 Use boolean values for 'unique' attribute
As defined in: https://github.com/doctrine/doctrine2/blob/master/doctrine-mapping.xsd#L294

Same as 'nullable' attribute. 

It was being exported as a "1" for TRUE and "0" for false
2014-03-23 10:16:43 +01:00
Benjamin Eberlei
a949e87ca8 Merge branch 'DDC-1985' into 2.4 2014-02-09 15:45:36 +01:00
Benjamin Eberlei
f18d0e093b [DDC-1985] Fix ordering preservation in SQL limit subquery output walker. 2014-02-09 15:45:28 +01:00
Benjamin Eberlei
0e139055f9 Merge branch 'DDC-2624' into 2.4 2014-02-09 14:31:15 +01:00
Benjamin Eberlei
b9c6659b70 Fix tests in 2.4 branch 2014-02-09 14:29:45 +01:00
Benjamin Eberlei
5c06121d94 [DDC-2624] Fix bug when persistent collection is cloned and used in a new entity. 2014-02-09 14:27:54 +01:00
Benjamin Eberlei
5bfa56aee0 Bump version to 2.4.3 2014-02-08 17:35:11 +01:00
Benjamin Eberlei
0363a5548d Release 2.4.2 2014-02-08 17:35:09 +01:00
Benjamin Eberlei
3764e49e6c Merge branch 'DDC-2895' into 2.4 2014-02-08 16:01:57 +01:00
Geoffrey Wagner
6ee20204a5 Fix some code standard things 2014-02-08 16:01:41 +01:00
Geoffrey Wagner
d9b0c87ded Fix some code standard things 2014-02-08 16:01:41 +01:00
Geoffrey Wagner
8594e5c4da Add a test
addLifecycleCallback now only allows a callback once so we do not hook them twice
2014-02-08 16:01:41 +01:00
Geoffrey Wagner
5f821f3b98 Fix Lifecycle Callbacks
Remove a bit of code that breaks lifecycle callbacks of parent MappedSuperclasses
2014-02-08 16:01:41 +01:00
Benjamin Eberlei
b566525099 Merge branch 'DDC-2931' into 2.4 2014-02-08 15:53:12 +01:00
Marco Pivetta
215c4a03e1 DDC-2931 - Removing previous broken fix for DDC-2931 - hardened 2014-02-08 15:52:46 +01:00
Marco Pivetta
b3ccd6466b DDC-2931 - Safe comparison between proxies and entities when refreshing objects 2014-02-08 15:52:46 +01:00
Marco Pivetta
b596bbb29f DDC-2931 - adding test that verifies that fetch-joined entities get refreshed with hints 2014-02-08 15:52:46 +01:00
Marco Pivetta
c204e6c6a1 DDC-2931 - removing old comments 2014-02-08 15:52:46 +01:00
Marco Pivetta
0bc94589e1 DDC-2931 - Removing refresh hints when fetching association data in hydrators 2014-02-08 15:52:45 +01:00
Marco Pivetta
f37856829f DDC-2931 - Detailed explanation 2014-02-08 15:52:45 +01:00
Marco Pivetta
157c793810 DDC-2931 - cleaning up code formatting/simplifying test case 2014-02-08 15:52:45 +01:00
root
72d838a804 [DDC-2931] testcase to reproduce Jira 2931 2014-02-08 15:52:45 +01:00
Benjamin Eberlei
58f8dc5d4c Update UPGRADE.md notes with BC mention. 2014-02-08 15:42:09 +01:00
Benjamin Eberlei
7d3ecd9481 Merge branch 'DDC-2947' into 2.4 2014-02-08 15:31:56 +01:00
Tim Lieberman
1bb55703a7 Make SchemaTool and SchemaValidator use EntityManagerInterface instead of EntityManager 2014-02-08 15:31:08 +01:00
Tim Lieberman
56cbcec13d Substitute EntityManagerInterface for EntityManager in Console EntityManagerHelper 2014-02-08 15:31:07 +01:00
Tim Lieberman
837c19bfc0 Console EntityManagerHelper now accepts EntityManagerInterface as constructor argument, instead of insisting on an EntityManager 2014-02-08 15:31:07 +01:00
Benjamin Eberlei
7b8f09ee4a Merge branch 'DDC-2700' into 2.4 2014-01-02 23:51:07 +01:00
Benjamin Eberlei
488a4dc78a [DDC-2700] Add test and fix CS. 2014-01-02 23:50:37 +01:00
Alex Pogodin
1364b6acc6 Identifier can be empty for MappedSuperclasses
When MappedSuperclass is inspected without identifier column been assigned, always return false. Solves "Undefined offset" notice.
2014-01-02 23:50:37 +01:00
Benjamin Eberlei
3dbe181762 Merge branch 'DDC-2732' into 2.4 2014-01-02 23:34:44 +01:00
Benjamin Eberlei
a3acaab65c [DDC-2732] Add tests for XML id options fix. 2014-01-02 23:34:17 +01:00
Eduardo
f183d25a33 Options not respected for ID Fields in XML Mapping Driver (XSD update)
XSD update.

The same bug of the yaml driver: see http://www.doctrine-project.org/jira/browse/DDC-2661
2014-01-02 23:34:17 +01:00
Eduardo
7c8350094e Options not respected for ID Fields in XML Mapping Driver
Same bug of the YAML driver, see: http://www.doctrine-project.org/jira/browse/DDC-2661
2014-01-02 23:34:17 +01:00
Benjamin Eberlei
c613410ba6 Merge branch 'DDC-2764' into 2.4 2014-01-02 23:16:56 +01:00
Sander Marechal
6bb7581dd7 Add rootAlias to Criteria where clauses 2014-01-02 23:16:35 +01:00
Sander Marechal
ab71dab7d1 Set rootAlias outside loop 2014-01-02 23:15:31 +01:00
Sander Marechal
2c114756bd [DDC-2764] Prefix criteria orderBy with rootAlias 2014-01-02 23:15:31 +01:00
Benjamin Eberlei
45496f040d Merge branch 'DDC-2775' into 2.4 2014-01-02 23:11:16 +01:00
Benjamin Eberlei
b40866c624 [DDC-2775] cleanup test. 2014-01-02 23:11:07 +01:00
Matthieu Napoli
a89cc7abea Inlined the model for the DCC2775 test case inside the test class 2014-01-02 23:07:53 +01:00
Matthieu Napoli
5ac111e5f8 Cleaned up tests for DDC-2775 2014-01-02 23:07:53 +01:00
Matthieu Napoli
c5f66e6e7f Fixed tests failing in pgsql because of used of a reserved keyword 2014-01-02 23:07:53 +01:00
Matthieu Napoli
b59f495875 Fixed tests for pgsql: was using reserved keyword as table name 2014-01-02 23:07:53 +01:00
Matthieu Napoli
3829b9c28b [DDC-2775] Bugfix 2014-01-02 23:07:53 +01:00
Matthieu Napoli
65bcdbf4c7 [DDC-2775] Tests reproducing DDC-2775 2014-01-02 23:07:53 +01:00
Benjamin Eberlei
95d000e51b Merge branch 'DDC-2692' into 2.4 2014-01-02 22:17:20 +01:00
Stefan Kleff
3657df3b01 Listener class prefix 2014-01-02 22:16:59 +01:00
Stefan Kleff
1661ffae9a removed unused use statements, fixed typo and group tag 2014-01-02 22:16:59 +01:00
Stefan Kleff
b424a5cf14 Added unit test 2014-01-02 22:16:59 +01:00
Stefan Kleff
2767a4eec4 Multiple invokation of listeners on PreFlush event
Only lifecycle callbacks and entity listeners should be triggered here. The preFlush listener event is already triggered at the beginning of commit()
2014-01-02 22:16:59 +01:00
Benjamin Eberlei
9486867279 Merge branch 'DDC-2645' into 2.4 2013-12-15 23:34:57 +01:00
Pouyan Savoli
6f2bb08972 [DDC-2645] Apply patch to fix issue 2013-12-15 23:34:34 +01:00
Aaron Muylaert
da2d3b406e Create failing test for DDC-2645.
Merge not dealing correctly with composite primary keys.
2013-12-15 23:34:34 +01:00
Benjamin Eberlei
c4b7d3fbea Bump version to 2.4.2 2013-11-12 13:40:15 +01:00
Benjamin Eberlei
84373d05a4 Release 2.4.1 2013-11-12 13:40:13 +01:00
Benjamin Eberlei
e82e7147fa Merge branch 'DDC-2715' into 2.4 2013-10-29 09:25:13 +01:00
jan brunnert
e23ed2250d Removed unnecessary is_object() check 2013-10-29 09:24:52 +01:00
jan brunnert
192bb6fd21 When the OptimisticLockingException is generated with the static function lockFailedVersionMismatch and the passed parameters are DateTime instances, the exception could not be thrown because the DateTime object is not implicitly converted to a string. 2013-10-29 09:24:52 +01:00
Benjamin Eberlei
0f3679f034 Merge branch 'DDC-2759' into 2.4 2013-10-26 11:17:34 +02:00
Benjamin Eberlei
1d2cd82706 [DDC-2759] Fix regression in ArrayHydrator introduced in DDC-1884 at SHA c7b4c9bf0f 2013-10-26 11:16:53 +02:00
Chris Collins
b983d86612 Added a failing test case for DDC-2759. 2013-10-26 11:16:53 +02:00
Benjamin Eberlei
b11f01643c Merge branch 'DDC-2668' into 2.4 2013-09-26 23:24:14 +02:00
Fabio B. Silva
b58fb8f5d4 [DDC-2668] Fix trim leading zero string 2013-09-26 23:23:49 +02:00
Benjamin Eberlei
925a22b71d Merge branch 'DDC-2608' into 2.4 2013-09-08 16:01:38 +02:00
Benjamin Eberlei
0f0d8abd67 [DDC-2608][DDC-2662] Fix SequenceGenerator requiring "sequenceName" and now throw exception. Fix a bug in quoting the sequenceName. 2013-09-08 16:00:14 +02:00
Benjamin Eberlei
470c15ce05 Merge branch 'DDC-2660' into 2.4 2013-09-08 14:39:54 +02:00
Benjamin Eberlei
3cc5fc0252 [DDC-2660] Fix error with NativeSQL, ResultSetMappingBuilder and Associations as Primary Key. 2013-09-08 14:39:25 +02:00
Benjamin Eberlei
fd0657089a Merge branch 'DDC-2661' into 2.4 2013-09-08 10:38:03 +02:00
Benjamin Eberlei
de3b237292 [DDC-2661] Fix bug in YamlDriver not passing options from id to mapField() 2013-09-08 10:37:42 +02:00
Benjamin Eberlei
1221cc3a2a More excludes 2013-09-07 18:27:20 +02:00
Benjamin Eberlei
9efbc1fa71 Bump version to 2.4.1 2013-09-07 18:19:57 +02:00
Benjamin Eberlei
57705e0d78 Release 2.4.0 2013-09-07 18:19:56 +02:00
Benjamin Eberlei
82bb6b78cd Travis should prefer dist. 2013-09-07 13:20:35 +02:00
Benjamin Eberlei
64c56b21aa Remove minimum stability from 2.4 composer.json 2013-09-07 13:08:14 +02:00
Benjamin Eberlei
b04e2e6364 Adjust composer.json to pending 2.4 stable release 2013-09-07 12:59:17 +02:00
Benjamin Eberlei
a70f9b7f49 Fix branch alias 2013-09-07 12:57:56 +02:00
Benjamin Eberlei
c88a7c1ffe New Build process
- Switch from Phing to Ant
- Remove PEAR packaging
- Add Composer archiving
2013-09-07 12:57:38 +02:00
Benjamin Eberlei
c206728c96 Merge branch 'DDC-2638' into 2.4 2013-09-07 09:04:34 +02:00
Attila Fulop
e8d420c641 Fix for entity generator discriminator column 2013-09-07 09:04:26 +02:00
Benjamin Eberlei
fdcab7eae8 Merge branch 'DDC-2640' into 2.4 2013-09-07 09:01:01 +02:00
Maks Feltrin
45d7d5234f DO NOT OVERRIDE CUSTOM TREE WALKERS IN getIterator() 2013-09-07 09:00:06 +02:00
Benjamin Eberlei
159ca79b81 Merge origin/2.4 into local branch 2013-09-07 08:55:15 +02:00
Benjamin Eberlei
2b148a27e0 Merge Oracle test fixes to 2.4 branch 2013-09-07 08:54:23 +02:00
Guilherme Blanco
0aef57f60c Fixing missing table aliases when using Many2Many persister. 2013-08-26 10:29:45 -04:00
Benjamin Eberlei
fef1e0286c Merge branch 'DDC-2235' into 2.4 2013-08-20 10:08:21 +02:00
Guilherme Blanco
4a38534150 Fixed DDC-2235. 2013-08-20 10:08:07 +02:00
Benjamin Eberlei
1de22adb16 Merge branch 'DDC-2506' into 2.4 2013-08-20 09:56:54 +02:00
Guilherme Blanco
62b4160887 Fixed DDC-2506 by manually updating code. Closes PR #708. 2013-08-20 09:56:39 +02:00
Benjamin Eberlei
dbb7c4d2bf Merge branch 'DDC-2607' into 2.4 2013-08-20 09:51:19 +02:00
Dustin Thomson
e8978ee365 Modified executeInserts method in JoinedSubclassPersister to only check for the presence of columns in a composite primary key 2013-08-20 09:51:01 +02:00
Benjamin Eberlei
c095b88804 Merge branch 'DDC-2578' into 2.4 2013-08-10 18:14:24 +02:00
Guilherme Blanco
efe4208ba6 Kept BC. 2013-08-10 18:14:07 +02:00
Guilherme Blanco
453a56670d Modified Hydrators to be per-query instances instead of a singleton-like approach. 2013-08-10 18:14:07 +02:00
Benjamin Eberlei
ec36e2c866 Merge branch 'DDC-2579' into 2.4 2013-08-10 17:54:37 +02:00
Fabio B. Silva
e250572cb4 fix DDC-2579 2013-08-10 17:53:50 +02:00
Benjamin Eberlei
758955e183 Merge branch 'DDC-2582' into 2.4 2013-08-10 17:48:20 +02:00
Guilherme Blanco
5b8d6a1486 CS fixes. 2013-08-10 17:48:03 +02:00
Guilherme Blanco
3f1003fee9 Fixed DDC-1884. 2013-08-10 17:48:03 +02:00
Benjamin Eberlei
7e241e89b8 Merge branch 'DDC-2548' into 2.4 2013-08-10 17:43:40 +02:00
Michaël Gallego
67c1e1d2b1 Allow to have non-distinct queries 2013-08-10 17:43:26 +02:00
Benjamin Eberlei
261eacdbfc Merge branch 'DDC-2565' into 2.4 2013-08-10 17:27:47 +02:00
Austin Morris
43df821691 convert PersistentCollection functional tests to unit tests 2013-08-10 17:27:30 +02:00
Austin Morris
11d09702da remove redundant require_once for TestInit.php 2013-08-10 17:27:30 +02:00
Austin Morris
f9f14139cf do not initialize coll on add() 2013-08-10 17:27:30 +02:00
Austin Morris
39f4d46d36 Initialize coll when using Collection methods inside PersistentCollection 2013-08-10 17:27:30 +02:00
Austin Morris
1dae8d318f PersistentCollection - initialize coll - create failing tests 2013-08-10 17:27:30 +02:00
Benjamin Eberlei
a361a7c1cb Merge branch 'DDC-2542' into 2.4 2013-08-10 17:02:34 +02:00
Roger Llopart Pla
6a73608baf Fixed name colision. 2013-08-10 17:02:10 +02:00
Roger Llopart Pla
f9955152b2 Added a test which verifies that the tree walkers are kept. 2013-08-10 17:02:10 +02:00
Roger Llopart Pla
5aad1df149 Added docblock. 2013-08-10 17:02:10 +02:00
Roger Llopart Pla
243832555b Appending the Paginator tree walker hint, instead of removing all the other hints. 2013-08-10 17:02:10 +02:00
Benjamin Eberlei
ae12fa6b5b Merge branch 'DDC-2577' into 2.4 2013-08-10 16:28:35 +02:00
Konstantin.Myakshin
edaf9b6813 Skip not mapped public properties in SchemaValidator 2013-08-10 16:28:27 +02:00
Benjamin Eberlei
b324a21abf Merge branch 'DDC-2587' into 2.4 2013-08-10 16:25:04 +02:00
J. Bruni
ff34aaaa2c Updated EntityGeneratorTest::testEntityTypeAlias 2013-08-10 16:24:43 +02:00
J. Bruni
9767a814a6 Updated EntityGeneratorTest::testEntityTypeAlias 2013-08-10 16:24:43 +02:00
J Bruni
e6007575e1 Corrected PHP type for "decimal" mapping type
"Basic Mapping" documentation says:
"decimal: Type that maps a SQL DECIMAL to a PHP string."
2013-08-10 16:24:43 +02:00
88 changed files with 2857 additions and 394 deletions

View File

@@ -4,6 +4,7 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
env:
- DB=mysql
@@ -16,7 +17,7 @@ before_script:
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi"
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi"
- composer install --prefer-source --dev
- composer install --prefer-dist --dev
script: phpunit --configuration tests/travis/$DB.travis.xml

View File

@@ -44,6 +44,12 @@ Now parenthesis are considered, the previous DQL will generate:
# Upgrade to 2.3
## Auto Discriminator Map breaks userland implementations with Listener
The new feature to detect discriminator maps automatically when none
are provided breaks userland implementations doing this with a
listener in ``loadClassMetadata`` event.
## EntityManager#find() not calls EntityRepository#find() anymore
Previous to 2.3, calling ``EntityManager#find()`` would be delegated to

View File

@@ -1,11 +1,3 @@
# Project Name
project.name=DoctrineORM
# Dependency minimum versions
dependencies.common=2.2.0beta1
dependencies.dbal=2.2.0beta1
dependencies.sfconsole=2.0.0
# Version class and file
project.version_class = Doctrine\ORM\Version
project.version_class = Doctrine\\ORM\\Version
project.version_file = lib/Doctrine/ORM/Version.php

199
build.xml
View File

@@ -1,114 +1,101 @@
<?xml version="1.0"?>
<project name="DoctrineORM" default="build" basedir=".">
<taskdef classname="phing.tasks.ext.d51PearPkg2Task" name="d51pearpkg2" />
<import file="${project.basedir}/lib/vendor/doctrine-build-common/packaging.xml" />
<property file="build.properties" />
<!--
Fileset for artifacts shared across all distributed packages.
-->
<fileset id="shared-artifacts" dir=".">
<include name="LICENSE"/>
<include name="UPGRADE*" />
<include name="doctrine-mapping.xsd" />
</fileset>
<!--
Fileset for command line scripts
-->
<fileset id="bin-scripts" dir="./bin">
<include name="doctrine"/>
<include name="doctrine-pear.php"/>
<include name="doctrine.bat"/>
</fileset>
<!--
Fileset for the sources of the Doctrine Common dependency.
-->
<fileset id="common-sources" dir="./lib/vendor/doctrine-common/lib">
<include name="Doctrine/Common/**"/>
</fileset>
<!--
Fileset for the sources of the Doctrine DBAL dependency.
-->
<fileset id="dbal-sources" dir="./lib/vendor/doctrine-dbal/lib">
<include name="Doctrine/DBAL/**"/>
</fileset>
<!--
Fileset for the sources of the Doctrine ORM.
-->
<fileset id="orm-sources" dir="./lib">
<include name="Doctrine/ORM/**"/>
</fileset>
<!--
Fileset for source of the Symfony YAML and Console components.
-->
<fileset id="symfony-sources" dir="./lib/vendor">
<include name="Symfony/Component/**"/>
<exclude name="**/.git/**" />
</fileset>
<!--
Builds ORM package, preparing it for distribution.
-->
<target name="copy-files" depends="prepare">
<copy todir="${build.dir}/${project.name}-${version}">
<fileset refid="shared-artifacts"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}">
<fileset refid="common-sources"/>
<fileset refid="dbal-sources"/>
<fileset refid="orm-sources"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}/Doctrine">
<fileset refid="symfony-sources"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}/bin">
<fileset refid="bin-scripts"/>
</copy>
<target name="php">
<exec executable="which" outputproperty="php_executable">
<arg value="php" />
</exec>
</target>
<!--
Builds distributable PEAR packages.
-->
<target name="define-pear-package" depends="copy-files">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/${project.name}-${version}">
<name>DoctrineORM</name>
<summary>Doctrine Object Relational Mapper</summary>
<channel>pear.doctrine-project.org</channel>
<description>The Doctrine ORM package is the primary package containing the object relational mapper.</description>
<lead user="jwage" name="Jonathan H. Wage" email="jonwage@gmail.com" />
<lead user="guilhermeblanco" name="Guilherme Blanco" email="guilhermeblanco@gmail.com" />
<lead user="romanb" name="Roman Borschel" email="roman@code-factory.org" />
<lead user="beberlei" name="Benjamin Eberlei" email="kontakt@beberlei.de" />
<license>LGPL</license>
<version release="${pear.version}" api="${pear.version}" />
<stability release="${pear.stability}" api="${pear.stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" />
<package name="Console" channel="pear.symfony.com" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.com" minimum_version="2.0.0" />
</dependencies>
<dirroles key="bin">script</dirroles>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Symfony/Component/Yaml/</ignore>
<ignore>Symfony/Component/Console/</ignore>
<release>
<install as="doctrine" name="bin/doctrine" />
<install as="doctrine.php" name="bin/doctrine-pear.php" />
<install as="doctrine.bat" name="bin/doctrine.bat" />
</release>
<replacement path="bin/doctrine" type="pear-config" from="@php_bin@" to="php_bin" />
<replacement path="bin/doctrine.bat" type="pear-config" from="@bin_dir@" to="bin_dir" />
</d51pearpkg2>
<target name="prepare">
<mkdir dir="build" />
</target>
<target name="build" depends="check-git-checkout-clean,prepare,php,composer">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="archive" />
<arg value="--dir=build" />
</exec>
</target>
<target name="composer" depends="php,composer-check,composer-download">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="install" />
</exec>
</target>
<target name="composer-check" depends="prepare">
<available file="build/composer.phar" property="composer.present"/>
</target>
<target name="composer-download" unless="composer.present">
<exec executable="wget">
<arg value="-Obuild/composer.phar" />
<arg value="http://getcomposer.org/composer.phar" />
</exec>
</target>
<target name="make-release" depends="check-git-checkout-clean,prepare,php">
<replace file="${project.version_file}" token="-DEV" value="" failOnNoReplacements="true" />
<exec executable="${php_executable}" outputproperty="doctrine.current_version" failonerror="true">
<arg value="-r" />
<arg value="require_once '${project.version_file}';echo ${project.version_class}::VERSION;" />
</exec>
<exec executable="${php_executable}" outputproperty="doctrine.next_version" failonerror="true">
<arg value="-r" />
<arg value="$parts = explode('.', str_ireplace(array('-DEV', '-ALPHA', '-BETA'), '', '${doctrine.current_version}'));
if (count($parts) != 3) {
throw new \InvalidArgumentException('Version is assumed in format x.y.z, ${doctrine.current_version} given');
}
$parts[2]++;
echo implode('.', $parts);
" />
</exec>
<git-commit file="${project.version_file}" message="Release ${doctrine.current_version}" />
<git-tag version="${doctrine.current_version}" />
<replace file="${project.version_file}" token="${doctrine.current_version}" value="${doctrine.next_version}-DEV" />
<git-commit file="${project.version_file}" message="Bump version to ${doctrine.next_version}" />
</target>
<target name="check-git-checkout-clean">
<exec executable="git" failonerror="true">
<arg value="diff-index" />
<arg value="--quiet" />
<arg value="HEAD" />
</exec>
</target>
<macrodef name="git-commit">
<attribute name="file" default="NOT SET"/>
<attribute name="message" default="NOT SET"/>
<sequential>
<exec executable="git">
<arg value="add" />
<arg value="@{file}" />
</exec>
<exec executable="git">
<arg value="commit" />
<arg value="-m" />
<arg value="@{message}" />
</exec>
</sequential>
</macrodef>
<macrodef name="git-tag">
<attribute name="version" default="NOT SET" />
<sequential>
<exec executable="git">
<arg value="tag" />
<arg value="-m" />
<arg value="v@{version}" />
<arg value="v@{version}" />
</exec>
</sequential>
</macrodef>
</project>

View File

@@ -11,16 +11,15 @@
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"}
],
"minimum-stability": "dev",
"require": {
"php": ">=5.3.2",
"ext-pdo": "*",
"doctrine/collections": "~1.1",
"doctrine/dbal": ">=2.4-beta,<2.5-dev",
"symfony/console": "2.*"
"doctrine/dbal": "~2.4",
"symfony/console": "~2.0"
},
"require-dev": {
"symfony/yaml": "2.1",
"symfony/yaml": "~2.1",
"satooshi/php-coveralls": "dev-master"
},
"suggest": {
@@ -34,5 +33,8 @@
"branch-alias": {
"dev-master": "2.4.x-dev"
}
},
"archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp", "*coveralls.yml"]
}
}

View File

@@ -14,7 +14,7 @@ Doctrine ORM don't panic. You can get help from different sources:
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
- The `Doctrine Mailing List <http://groups.google.com/group/doctrine-user>`_
- Internet Relay Chat (IRC) in `#doctrine on Freenode <irc://irc.freenode.net/doctrine>`_
- Internet Relay Chat (IRC) in #doctrine on Freenode
- Report a bug on `JIRA <http://www.doctrine-project.org/jira>`_.
- On `Twitter <https://twitter.com/search/%23doctrine2>`_ with ``#doctrine2``
- On `StackOverflow <http://stackoverflow.com/questions/tagged/doctrine2>`_
@@ -120,3 +120,4 @@ Cookbook
:doc:`MySQL Enums <cookbook/mysql-enums>`
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
.. include:: toc.rst

View File

@@ -106,7 +106,7 @@ 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
`from here <http://redis.io/>`_. Also check
`here <https://github.com/nicolasff/phpredis/>`_ for how you can use
`A PHP extension for Redis <https://github.com/nicolasff/phpredis/>`_ for how you can use
and install Redis PHP extension.
Below is a simple example of how you could use the Redis cache

View File

@@ -100,7 +100,7 @@ Doctrine ships with a number of command line tools that are very helpful
during development. You can call this command from the Composer binary
directory:
.. code-block::
.. code-block:: sh
$ php vendor/bin/doctrine

View File

@@ -207,10 +207,13 @@ listeners:
- Lifecycle Callbacks are methods on the entity classes that are
called when the event is triggered. They receives some kind of ``EventArgs``.
called when the event is triggered. As of v2.4 they receive some kind
of ``EventArgs`` instance.
- Lifecycle Event Listeners and Subscribers are classes with specific callback
methods that receives some kind of ``EventArgs`` instance which
give access to the entity, EntityManager or other relevant data.
methods that receives some kind of ``EventArgs`` instance.
The EventArgs instance received by the listener gives access to the entity,
EntityManager and other relevant data.
.. note::
@@ -224,10 +227,11 @@ listeners:
Lifecycle Callbacks
-------------------
A lifecycle event is a regular event with the additional feature of
providing a mechanism to register direct callbacks inside the
corresponding entity classes that are executed when the lifecycle
event occurs.
Lifecycle Callbacks are defined on an entity class. They allow you to
trigger callbacks whenever an instance of that entity class experiences
a relevant lifecycle event. More than one callback can be defined for each
lifecycle event. Lifecycle Callbacks are best used for simple operations
specific to a particular entity class's lifecycle.
.. code-block:: php
@@ -277,8 +281,9 @@ event occurs.
}
}
Note that when using annotations you have to apply the
@HasLifecycleCallbacks marker annotation on the entity class.
Note that the methods set as lifecycle callbacks need to be public and,
when using these annotations, you have to apply the
``@HasLifecycleCallbacks`` marker annotation on the entity class.
If you want to register lifecycle callbacks from YAML or XML you
can do it with the following.
@@ -295,6 +300,10 @@ can do it with the following.
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
postPersist: [ doStuffOnPostPersist ]
In YAML the ``key`` of the lifecycleCallbacks entry is the event that you
are triggering on and the value is the method (or methods) to call. The allowed
event types are the ones listed in the previous Lifecycle Events section.
XML would look something like this:
.. code-block:: xml
@@ -317,9 +326,14 @@ XML would look something like this:
</doctrine-mapping>
You just need to make sure a public ``doStuffOnPrePersist()`` and
``doStuffOnPostPersist()`` method is defined on your ``User``
model.
In XML the ``type`` of the lifecycle-callback entry is the event that you
are triggering on and the ``method`` is the method to call. The allowed event
types are the ones listed in the previous Lifecycle Events section.
When using YAML or XML you need to remember to create public methods to match the
callback names you defined. E.g. in these examples ``doStuffOnPrePersist()``,
``doOtherStuffOnPrePersist()`` and ``doStuffOnPostPersist()`` methods need to be
defined on your ``User`` model.
.. code-block:: php
@@ -375,8 +389,10 @@ Listening and subscribing to Lifecycle Events
Lifecycle event listeners are much more powerful than the simple
lifecycle callbacks that are defined on the entity classes. They
allow to implement re-usable behaviors between different entity
classes, yet require much more detailed knowledge about the inner
sit at a level above the entities and allow you to implement re-usable
behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner
workings of the EntityManager and UnitOfWork. Please read the
*Implementing Event Listeners* section carefully if you are trying
to write your own listener.
@@ -476,8 +492,8 @@ data and lost updates/persists/removes.
For the described events that are also lifecycle callback events
the restrictions apply as well, with the additional restriction
that you do not have access to the EntityManager or UnitOfWork APIs
inside these events.
that (prior to version 2.4) you do not have access to the
EntityManager or UnitOfWork APIs inside these events.
prePersist
~~~~~~~~~~
@@ -501,11 +517,9 @@ The following restrictions apply to ``prePersist``:
- If you are using a PrePersist Identity Generator such as
sequences the ID value will *NOT* be available within any
PrePersist events.
- Doctrine will not recognize changes made to relations in a pre
persist event called by "reachability" through a cascade persist
unless you use the internal ``UnitOfWork`` API. We do not recommend
such operations in the persistence by reachability context, so do
this at your own risk and possibly supported by unit-tests.
- Doctrine will not recognize changes made to relations in a prePersist
event. This includes modifications to
collections such as additions, removals or replacement.
preRemove
~~~~~~~~~
@@ -699,7 +713,8 @@ Restrictions for this event:
recognized by the flush operation anymore.
- Changes to fields of the passed entities are not recognized by
the flush operation anymore, use the computed change-set passed to
the event to modify primitive field values.
the event to modify primitive field values, e.g. use
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
- Any calls to ``EntityManager#persist()`` or
``EntityManager#remove()``, even in combination with the UnitOfWork
API are strongly discouraged and don't work as expected outside the
@@ -769,9 +784,10 @@ An ``Entity Listener`` could be any class, by default it should be a class with
- Different from :ref:`reference-events-implementing-listeners` an ``Entity Listener`` is invoked just to the specified entity
- An entity listener method receives two arguments, the entity instance and the lifecycle event.
- A callback method could be defined by naming convention or specifying a method mapping.
- When the listener mapping is not given the parser will lookup for methods that match with the naming convention.
- When the listener mapping is given the parser won't lookup for any naming convention.
- The callback method can be defined by naming convention or specifying a method mapping.
- When a listener mapping is not given the parser will use the naming convention to look for a matching method,
e.g. it will look for a public ``preUpdate()`` method if you are listening to the ``preUpdate`` event.
- When a listener mapping is given the parser will not look for any methods using the naming convention.
.. code-block:: php

View File

@@ -143,7 +143,7 @@ See the documentation chapter on :doc:`inheritance mapping <inheritance-mapping>
the details.
Why does Doctrine not create proxy objects for my inheritance hierarchy?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you set a many-to-one or one-to-one association target-entity to any parent class of
an inheritance hierarchy Doctrine does not know what PHP class the foreign is actually of.

View File

@@ -8,12 +8,14 @@ Tutorials
:maxdepth: 1
tutorials/getting-started
tutorials/getting-started-database
tutorials/getting-started-models
tutorials/working-with-indexed-associations
tutorials/extra-lazy-associations
tutorials/composite-primary-keys
tutorials/ordered-associations
tutorials/in-ten-quick-steps
tutorials/override-field-association-mappings-in-subclasses
tutorials/pagination.rst
Reference Guide
---------------
@@ -22,9 +24,9 @@ Reference Guide
:maxdepth: 1
:numbered:
reference/introduction
reference/architecture
reference/configuration
reference/installation
reference/configuration.rst
reference/faq
reference/basic-mapping
reference/association-mapping
@@ -51,9 +53,9 @@ Reference Guide
reference/metadata-drivers
reference/best-practices
reference/limitations-and-known-issues
tutorials/pagination.rst
reference/filters.rst
reference/namingstrategy.rst
reference/advanced-configuration.rst
Cookbook
@@ -63,6 +65,7 @@ Cookbook
:maxdepth: 1
cookbook/aggregate-fields
cookbook/custom-mapping-types
cookbook/decorator-pattern
cookbook/dql-custom-walkers
cookbook/dql-user-defined-functions
@@ -70,6 +73,7 @@ Cookbook
cookbook/implementing-the-notify-changetracking-policy
cookbook/implementing-wakeup-or-clone
cookbook/integrating-with-codeigniter
cookbook/resolve-target-entity-listener
cookbook/sql-table-prefixes
cookbook/strategy-cookbook-introduction
cookbook/validation-of-entities

View File

@@ -350,6 +350,7 @@
<xs:element name="generator" type="orm:generator" minOccurs="0" />
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="custom-id-generator" type="orm:custom-id-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />

View File

@@ -701,6 +701,18 @@ abstract class AbstractQuery
return isset($this->_hints[$name]) ? $this->_hints[$name] : false;
}
/**
* Check if the query has a hint
*
* @param string $name The name of the hint
*
* @return bool False if the query does not have any hint
*/
public function hasHint($name)
{
return isset($this->_hints[$name]);
}
/**
* Return the key value map of query hints that are currently set.
*
@@ -787,7 +799,7 @@ abstract class AbstractQuery
return $stmt;
}
$data = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);

View File

@@ -99,13 +99,6 @@ use Doctrine\Common\Util\ClassUtils;
*/
private $eventManager;
/**
* The maintained (cached) hydrators. One instance per type.
*
* @var array
*/
private $hydrators = array();
/**
* The proxy factory used to create dynamic proxies.
*
@@ -840,17 +833,15 @@ use Doctrine\Common\Util\ClassUtils;
* This method caches the hydrator instances which is used for all queries that don't
* selectively iterate over the result.
*
* @deprecated
*
* @param int $hydrationMode
*
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
public function getHydrator($hydrationMode)
{
if ( ! isset($this->hydrators[$hydrationMode])) {
$this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode);
}
return $this->hydrators[$hydrationMode];
return $this->newHydrator($hydrationMode);
}
/**

View File

@@ -146,6 +146,7 @@ class ArrayHydrator extends AbstractHydrator
$baseElement =& $this->_resultPointers[$parent];
} else {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
continue;
}
@@ -167,6 +168,7 @@ class ArrayHydrator extends AbstractHydrator
if ( ! $indexExists || ! $indexIsValid) {
$element = $data;
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $element;
} else {
@@ -183,7 +185,10 @@ class ArrayHydrator extends AbstractHydrator
} else {
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
if (
( ! isset($nonemptyComponents[$dqlAlias])) &&
( ! isset($baseElement[$relationAlias]))
) {
$baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = $data;
@@ -192,10 +197,9 @@ class ArrayHydrator extends AbstractHydrator
$coll =& $baseElement[$relationAlias];
if ($coll !== null) {
if (is_array($coll)) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
}
} else {
// It's a root result element
@@ -204,22 +208,21 @@ class ArrayHydrator extends AbstractHydrator
// if this row has a NULL value for the root result id then make it a null result.
if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
if ($this->_rsm->isMixed) {
$result[] = array($entityKey => null);
} else {
$result[] = null;
}
$result[] = $this->_rsm->isMixed
? array($entityKey => null)
: null;
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
continue;
}
// Check for an existing element
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $rowData[$dqlAlias];
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
$element = $this->_rsm->isMixed
? array($entityKey => $rowData[$dqlAlias])
: $rowData[$dqlAlias];
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
@@ -227,6 +230,7 @@ class ArrayHydrator extends AbstractHydrator
} else {
$resultKey = $this->_resultCounter;
$result[] = $element;
++$this->_resultCounter;
}
@@ -234,11 +238,13 @@ class ArrayHydrator extends AbstractHydrator
} else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] =& $result[$index];
++$this->_resultCounter;
}*/
}
$this->updateResultPointer($result, $index, $dqlAlias, false);
}
}
@@ -247,11 +253,9 @@ class ArrayHydrator extends AbstractHydrator
if (isset($scalars)) {
if ( ! isset($resultKey) ) {
// this only ever happens when no object is fetched (scalar result only)
if (isset($this->_rsm->indexByMap['scalars'])) {
$resultKey = $row[$this->_rsm->indexByMap['scalars']];
} else {
$resultKey = $this->_resultCounter - 1;
}
$resultKey = isset($this->_rsm->indexByMap['scalars'])
? $row[$this->_rsm->indexByMap['scalars']]
: $this->_resultCounter - 1;
}
foreach ($scalars as $name => $value) {
@@ -279,6 +283,12 @@ class ArrayHydrator extends AbstractHydrator
return;
}
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
return;
}
if ($index !== false) {
$this->_resultPointers[$dqlAlias] =& $coll[$index];
@@ -289,12 +299,6 @@ class ArrayHydrator extends AbstractHydrator
return;
}
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
return;
}
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];

View File

@@ -88,4 +88,18 @@ class HydrationException extends \Doctrine\ORM\ORMException
$discrColumnName, $entityName, $dqlAlias
));
}
/**
* @param string $discrValue
* @param array $discrMap
*
* @return HydrationException
*/
public static function invalidDiscriminatorValue($discrValue, $discrMap)
{
return new self(sprintf(
'The discriminator value "%s" is invalid. It must be one of "%s".',
$discrValue, implode('", "', $discrMap)
));
}
}

View File

@@ -266,7 +266,13 @@ class ObjectHydrator extends AbstractHydrator
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
}
$className = $this->ce[$className]->discriminatorMap[$data[$discrColumn]];
$discrMap = $this->ce[$className]->discriminatorMap;
if ( ! isset($discrMap[$data[$discrColumn]])) {
throw HydrationException::invalidDiscriminatorValue($data[$discrColumn], array_keys($discrMap));
}
$className = $discrMap[$data[$discrColumn]];
unset($data[$discrColumn]);
}

View File

@@ -98,7 +98,13 @@ class SimpleObjectHydrator extends AbstractHydrator
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
$discrMap = $this->class->discriminatorMap;
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
}
$entityName = $discrMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
}

View File

@@ -866,7 +866,11 @@ class ClassMetadataInfo implements ClassMetadata
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
if (PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513 || PHP_VERSION_ID >= 50600) {
$this->_prototype = $this->reflClass->newInstanceWithoutConstructor();
} else {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
}
return clone $this->_prototype;
@@ -1031,9 +1035,14 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function isIdentifier($fieldName)
{
if ( ! $this->identifier) {
return false;
}
if ( ! $this->isIdentifierComposite) {
return $fieldName === $this->identifier[0];
}
return in_array($fieldName, $this->identifier);
}
@@ -2483,6 +2492,10 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function addLifecycleCallback($callback, $event)
{
if(isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
return;
}
$this->lifecycleCallbacks[$event][] = $callback;
}
@@ -2790,8 +2803,12 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function setSequenceGeneratorDefinition(array $definition)
{
if (isset($definition['name']) && $definition['name'] == '`') {
$definition['name'] = trim($definition['name'], '`');
if ( ! isset($definition['sequenceName'])) {
throw MappingException::missingSequenceName($this->name);
}
if ($definition['sequenceName'][0] == '`') {
$definition['sequenceName'] = trim($definition['sequenceName'], '`');
$definition['quoted'] = true;
}

View File

@@ -450,12 +450,9 @@ class AnnotationDriver extends AbstractAnnotationDriver
if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// filter for the declaring class only, callbacks from parents will already be registered.
if ($method->getDeclaringClass()->name !== $class->name) {
continue;
}
foreach ($this->getMethodCallbacks($method) as $value) {
$metadata->addLifecycleCallback($value[0], $value[1]);
}
}

View File

@@ -278,6 +278,10 @@ class XmlDriver extends FileDriver
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
}
if (isset($idElement->options)) {
$mapping['options'] = $this->_parseOptions($idElement->options->children());
}
$metadata->mapField($mapping);
if (isset($idElement->generator)) {

View File

@@ -264,6 +264,10 @@ class YamlDriver extends FileDriver
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
if (isset($idElement['options'])) {
$mapping['options'] = $idElement['options'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {

View File

@@ -757,4 +757,16 @@ class MappingException extends \Doctrine\ORM\ORMException
$cascades
));
}
/**
* @param string $className
*
* @return MappingException
*/
public static function missingSequenceName($className)
{
return new self(
sprintf('Missing "sequenceName" attribute for sequence id generator definition on class "%s".', $className)
);
}
}

View File

@@ -73,6 +73,8 @@ class OptimisticLockException extends ORMException
*/
public static function lockFailedVersionMismatch($entity, $expectedLockVersion, $actualLockVersion)
{
$expectedLockVersion = ($expectedLockVersion instanceof \DateTime) ? $expectedLockVersion->getTimestamp() : $expectedLockVersion;
$actualLockVersion = ($actualLockVersion instanceof \DateTime) ? $actualLockVersion->getTimestamp() : $actualLockVersion;
return new self("The optimistic lock failed, version " . $expectedLockVersion . " was expected, but is actually ".$actualLockVersion, $entity);
}

View File

@@ -757,6 +757,8 @@ final class PersistentCollection implements Collection, Selectable
*/
public function key()
{
$this->initialize();
return $this->coll->key();
}
@@ -765,6 +767,8 @@ final class PersistentCollection implements Collection, Selectable
*/
public function current()
{
$this->initialize();
return $this->coll->current();
}
@@ -773,6 +777,8 @@ final class PersistentCollection implements Collection, Selectable
*/
public function next()
{
$this->initialize();
return $this->coll->next();
}

View File

@@ -567,8 +567,8 @@ class BasicEntityPersister
$tableName = $this->quoteStrategy->getTableName($class, $this->platform);
$idColumns = $this->quoteStrategy->getIdentifierColumnNames($class, $this->platform);
$id = array_combine($idColumns, $identifier);
$types = array_map(function ($identifier) use ($class, $em) {
$types = array_map(function ($identifier) use ($class, $em) {
if (isset($class->fieldMappings[$identifier])) {
return $class->fieldMappings[$identifier]['type'];
}
@@ -580,7 +580,7 @@ class BasicEntityPersister
}
if (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])) {
$types[] = $targetMapping->associationMappings[$targetMapping->identifier[0]]['type'];
return $targetMapping->associationMappings[$targetMapping->identifier[0]]['type'];
}
throw ORMException::unrecognizedField($targetMapping->identifier[0]);

View File

@@ -197,7 +197,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
}
foreach ($data as $columnName => $value) {
if (!isset($id[$columnName])) {
if (!is_array($id) || !isset($id[$columnName])) {
$stmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
}
}

View File

@@ -235,7 +235,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
foreach ($joinColumns as $joinColumn) {
$columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
$referencedName = $joinColumn['referencedColumnName'];
$conditions[] = $columnName . ' = ?';
$conditions[] = 't.' . $columnName . ' = ?';
$params[] = ($class->containsForeignIdentifier)
? $id[$class->getFieldForColumn($referencedName)]
: $id[$class->fieldNames[$referencedName]];
@@ -361,12 +361,13 @@ class ManyToManyPersister extends AbstractCollectionPersister
$params = array();
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
$whereClauses[] = $joinTableColumn . ' = ?';
$whereClauses[] = ($addFilters ? 't.' : '') . $joinTableColumn . ' = ?';
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
$params[] = ($targetClass->containsForeignIdentifier)
? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
: $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
continue;
}
@@ -377,9 +378,12 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
if ($addFilters) {
$quotedJoinTable .= ' t';
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' t ' . $joinTargetEntitySQL;
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
$whereClauses[] = $filterSql;
}
}

View File

@@ -20,6 +20,8 @@
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
@@ -36,71 +38,60 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
class TrimFunction extends FunctionNode
{
/**
* @var bool
* @var boolean
*/
public $leading;
/**
* @var bool
* @var boolean
*/
public $trailing;
/**
* @var bool
* @var boolean
*/
public $both;
/**
* @var bool
* @var boolean
*/
public $trimChar = false;
/**
* @var \Doctrine\ORM\Query\AST\Node
*/
public $stringPrimary;
/**
* @override
* {@inheritdoc}
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
public function getSql(SqlWalker $sqlWalker)
{
$pos = AbstractPlatform::TRIM_UNSPECIFIED;
if ($this->leading) {
$pos = AbstractPlatform::TRIM_LEADING;
} else if ($this->trailing) {
$pos = AbstractPlatform::TRIM_TRAILING;
} else if ($this->both) {
$pos = AbstractPlatform::TRIM_BOTH;
}
$stringPrimary = $sqlWalker->walkStringPrimary($this->stringPrimary);
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
$trimMode = $this->getTrimMode();
$trimChar = ($this->trimChar !== false)
? $sqlWalker->getConnection()->quote($this->trimChar)
: false;
return $sqlWalker->getConnection()->getDatabasePlatform()->getTrimExpression(
$sqlWalker->walkStringPrimary($this->stringPrimary),
$pos,
($this->trimChar != false) ? $sqlWalker->getConnection()->quote($this->trimChar) : false
);
return $platform->getTrimExpression($stringPrimary, $trimMode, $trimChar);
}
/**
* @override
* {@inheritdoc}
*/
public function parse(\Doctrine\ORM\Query\Parser $parser)
public function parse(Parser $parser)
{
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
if (strcasecmp('leading', $lexer->lookahead['value']) === 0) {
$parser->match(Lexer::T_LEADING);
$this->leading = true;
} else if (strcasecmp('trailing', $lexer->lookahead['value']) === 0) {
$parser->match(Lexer::T_TRAILING);
$this->trailing = true;
} else if (strcasecmp('both', $lexer->lookahead['value']) === 0) {
$parser->match(Lexer::T_BOTH);
$this->both = true;
}
$this->parseTrimMode($parser);
if ($lexer->isNextToken(Lexer::T_STRING)) {
$parser->match(Lexer::T_STRING);
$this->trimChar = $lexer->token['value'];
}
@@ -112,4 +103,61 @@ class TrimFunction extends FunctionNode
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* @param \Doctrine\ORM\Query\Parser $parser
*
* @return integer
*/
private function getTrimMode()
{
if ($this->leading) {
return AbstractPlatform::TRIM_LEADING;
}
if ($this->trailing) {
return AbstractPlatform::TRIM_TRAILING;
}
if ($this->both) {
return AbstractPlatform::TRIM_BOTH;
}
return AbstractPlatform::TRIM_UNSPECIFIED;
}
/**
* @param \Doctrine\ORM\Query\Parser $parser
*
* @return void
*/
private function parseTrimMode(Parser $parser)
{
$lexer = $parser->getLexer();
$value = $lexer->lookahead['value'];
if (strcasecmp('leading', $value) === 0) {
$parser->match(Lexer::T_LEADING);
$this->leading = true;
return;
}
if (strcasecmp('trailing', $value) === 0) {
$parser->match(Lexer::T_TRAILING);
$this->trailing = true;
return;
}
if (strcasecmp('both', $value) === 0) {
$parser->match(Lexer::T_BOTH);
$this->both = true;
return;
}
}
}

View File

@@ -41,13 +41,20 @@ class RangeVariableDeclaration extends Node
public $aliasIdentificationVariable;
/**
* @param string $abstractSchemaName
* @param string $aliasIdentificationVar
* @var boolean
*/
public function __construct($abstractSchemaName, $aliasIdentificationVar)
public $isRoot;
/**
* @param string $abstractSchemaName
* @param string $aliasIdentificationVar
* @param boolean $isRoot
*/
public function __construct($abstractSchemaName, $aliasIdentificationVar, $isRoot = true)
{
$this->abstractSchemaName = $abstractSchemaName;
$this->abstractSchemaName = $abstractSchemaName;
$this->aliasIdentificationVariable = $aliasIdentificationVar;
$this->isRoot = $isRoot;
}
/**

View File

@@ -1544,6 +1544,9 @@ class Parser
public function IdentificationVariableDeclaration()
{
$rangeVariableDeclaration = $this->RangeVariableDeclaration();
$rangeVariableDeclaration->isRoot = true;
$indexBy = $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
$joins = array();
@@ -1622,15 +1625,19 @@ class Parser
$this->match(Lexer::T_JOIN);
$next = $this->lexer->glimpse();
$joinDeclaration = ($next['type'] === Lexer::T_DOT)
? $this->JoinAssociationDeclaration()
: $this->RangeVariableDeclaration();
$joinDeclaration = ($next['type'] === Lexer::T_DOT) ? $this->JoinAssociationDeclaration() : $this->RangeVariableDeclaration();
$adhocConditions = $this->lexer->isNextToken(Lexer::T_WITH);
$join = new AST\Join($joinType, $joinDeclaration);
// Create AST node
$join = new AST\Join($joinType, $joinDeclaration);
// Describe non-root join declaration
if ($joinDeclaration instanceof AST\RangeVariableDeclaration) {
$joinDeclaration->isRoot = false;
$adhocConditions = true;
}
// Check for ad-hoc Join conditions
if ($this->lexer->isNextToken(Lexer::T_WITH) || $joinDeclaration instanceof AST\RangeVariableDeclaration) {
if ($adhocConditions) {
$this->match(Lexer::T_WITH);
$join->conditionalExpression = $this->ConditionalExpression();

View File

@@ -47,6 +47,11 @@ class QueryExpressionVisitor extends ExpressionVisitor
Comparison::LTE => Expr\Comparison::LTE
);
/**
* @var string
*/
private $rootAlias;
/**
* @var Expr
*/
@@ -58,10 +63,13 @@ class QueryExpressionVisitor extends ExpressionVisitor
private $parameters = array();
/**
* Constructor with internal initialization.
* Constructor
*
* @param string $rootAlias
*/
public function __construct()
public function __construct($rootAlias)
{
$this->rootAlias = $rootAlias;
$this->expr = new Expr();
}
@@ -133,33 +141,33 @@ class QueryExpressionVisitor extends ExpressionVisitor
switch ($comparison->getOperator()) {
case Comparison::IN:
$this->parameters[] = $parameter;
return $this->expr->in($comparison->getField(), $placeholder);
return $this->expr->in($this->rootAlias . '.' . $comparison->getField(), $placeholder);
case Comparison::NIN:
$this->parameters[] = $parameter;
return $this->expr->notIn($comparison->getField(), $placeholder);
return $this->expr->notIn($this->rootAlias . '.' . $comparison->getField(), $placeholder);
case Comparison::EQ:
case Comparison::IS:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr->isNull($comparison->getField());
return $this->expr->isNull($this->rootAlias . '.' . $comparison->getField());
}
$this->parameters[] = $parameter;
return $this->expr->eq($comparison->getField(), $placeholder);
return $this->expr->eq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
case Comparison::NEQ:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr->isNotNull($comparison->getField());
return $this->expr->isNotNull($this->rootAlias . '.' . $comparison->getField());
}
$this->parameters[] = $parameter;
return $this->expr->neq($comparison->getField(), $placeholder);
return $this->expr->neq($this->rootAlias . '.' . $comparison->getField(), $placeholder);
default:
$operator = self::convertComparisonOperator($comparison->getOperator());
if ($operator) {
$this->parameters[] = $parameter;
return new Expr\Comparison(
$comparison->getField(),
$this->rootAlias . '.' . $comparison->getField(),
$operator,
$placeholder
);

View File

@@ -168,7 +168,12 @@ class ResultSetMappingBuilder extends ResultSetMapping
throw new \InvalidArgumentException("The column '$columnAlias' conflicts with another column in the mapper.");
}
$this->addMetaResult($alias, $columnAlias, $columnName);
$this->addMetaResult(
$alias,
$columnAlias,
$columnName,
(isset($associationMapping['id']) && $associationMapping['id'] === true)
);
}
}
}

View File

@@ -842,7 +842,9 @@ class SqlWalker implements TreeWalker
$class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
$this->rootAliases[] = $dqlAlias;
if ($rangeVariableDeclaration->isRoot) {
$this->rootAliases[] = $dqlAlias;
}
$sql = $this->quoteStrategy->getTableName($class,$this->platform) . ' '
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
@@ -858,13 +860,14 @@ class SqlWalker implements TreeWalker
* Walks down a JoinAssociationDeclaration AST node, thereby generating the appropriate SQL.
*
* @param AST\JoinAssociationDeclaration $joinAssociationDeclaration
* @param int $joinType
* @param int $joinType
* @param AST\ConditionalExpression $condExpr
*
* @return string
*
* @throws QueryException
*/
public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joinType = AST\Join::JOIN_TYPE_INNER)
public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joinType = AST\Join::JOIN_TYPE_INNER, $condExpr = null)
{
$sql = '';
@@ -979,6 +982,13 @@ class SqlWalker implements TreeWalker
break;
}
// Handle WITH clause
if ($condExpr !== null) {
// Phase 2 AST optimization: Skip processing of ConditionalExpression
// if only one ConditionalTerm is defined
$sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')';
}
// FIXME: these should either be nested or all forced to be left joins (DDC-XXX)
if ($targetClass->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
@@ -1058,24 +1068,37 @@ class SqlWalker implements TreeWalker
switch (true) {
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\RangeVariableDeclaration):
$class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName);
$condExprConjunction = $class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER
$class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName);
$dqlAlias = $joinDeclaration->aliasIdentificationVariable;
$tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
$condition = '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
$condExprConjunction = ($class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER)
? ' AND '
: ' ON ';
$sql .= $this->walkRangeVariableDeclaration($joinDeclaration)
. $condExprConjunction . '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
$sql .= $this->walkRangeVariableDeclaration($joinDeclaration);
$conditions = array($condition);
// Apply remaining inheritance restrictions
$discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($dqlAlias));
if ($discrSql) {
$conditions[] = $discrSql;
}
// Apply the filters
$filterExpr = $this->generateFilterConditionSQL($class, $tableAlias);
if ($filterExpr) {
$conditions[] = $filterExpr;
}
$sql .= $condExprConjunction . implode(' AND ', $conditions);
break;
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\JoinAssociationDeclaration):
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType);
// Handle WITH clause
if (($condExpr = $join->conditionalExpression) !== null) {
// Phase 2 AST optimization: Skip processing of ConditionalExpression
// if only one ConditionalTerm is defined
$sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')';
}
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType, $join->conditionalExpression);
break;
}
@@ -1474,6 +1497,7 @@ class SqlWalker implements TreeWalker
break;
}
$fieldType = 'string';
switch (true) {
case ($e instanceof AST\PathExpression):
$fieldName = $e->field;
@@ -1494,10 +1518,6 @@ class SqlWalker implements TreeWalker
break;
}
break;
default:
$fieldType = 'string';
break;
}
$this->scalarResultAliasMap[$resultAlias] = $columnAlias;

View File

@@ -894,8 +894,8 @@ class QueryBuilder
*/
public function andWhere($where)
{
$where = $this->getDQLPart('where');
$args = func_get_args();
$where = $this->getDQLPart('where');
if ($where instanceof Expr\Andx) {
$where->addMultiple($args);
@@ -927,8 +927,8 @@ class QueryBuilder
*/
public function orWhere($where)
{
$where = $this->getDqlPart('where');
$args = func_get_args();
$where = $this->getDqlPart('where');
if ($where instanceof Expr\Orx) {
$where->addMultiple($args);
@@ -1007,8 +1007,8 @@ class QueryBuilder
*/
public function andHaving($having)
{
$having = $this->getDqlPart('having');
$args = func_get_args();
$having = $this->getDqlPart('having');
if ($having instanceof Expr\Andx) {
$having->addMultiple($args);
@@ -1030,8 +1030,8 @@ class QueryBuilder
*/
public function orHaving($having)
{
$having = $this->getDqlPart('having');
$args = func_get_args();
$having = $this->getDqlPart('having');
if ($having instanceof Expr\Orx) {
$having->addMultiple($args);
@@ -1087,7 +1087,8 @@ class QueryBuilder
*/
public function addCriteria(Criteria $criteria)
{
$visitor = new QueryExpressionVisitor();
$rootAlias = $this->getRootAlias();
$visitor = new QueryExpressionVisitor($rootAlias);
if ($whereExpression = $criteria->getWhereExpression()) {
$this->andWhere($visitor->dispatch($whereExpression));
@@ -1098,7 +1099,7 @@ class QueryBuilder
if ($criteria->getOrderings()) {
foreach ($criteria->getOrderings() as $sort => $order) {
$this->addOrderBy($sort, $order);
$this->addOrderBy($rootAlias . '.' . $sort, $order);
}
}

View File

@@ -22,7 +22,7 @@ namespace Doctrine\ORM\Tools\Console;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\ORM\Version;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
@@ -35,10 +35,10 @@ class ConsoleRunner
/**
* Create a Symfony Console HelperSet
*
* @param EntityManager $entityManager
* @param EntityManagerInterface $entityManager
* @return HelperSet
*/
public static function createHelperSet(EntityManager $entityManager)
public static function createHelperSet(EntityManagerInterface $entityManager)
{
return new HelperSet(array(
'db' => new ConnectionHelper($entityManager->getConnection()),

View File

@@ -19,8 +19,9 @@
namespace Doctrine\ORM\Tools\Console\Helper;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Helper\Helper;
use Doctrine\ORM\EntityManager;
/**
* Doctrine CLI Connection Helper.
@@ -35,18 +36,18 @@ use Doctrine\ORM\EntityManager;
class EntityManagerHelper extends Helper
{
/**
* Doctrine ORM EntityManager.
* Doctrine ORM EntityManagerInterface.
*
* @var EntityManager
* @var EntityManagerInterface
*/
protected $_em;
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
* @param EntityManagerInterface $em
*/
public function __construct(EntityManager $em)
public function __construct(EntityManagerInterface $em)
{
$this->_em = $em;
}
@@ -54,7 +55,7 @@ class EntityManagerHelper extends Helper
/**
* Retrieves Doctrine ORM EntityManager.
*
* @return EntityManager
* @return EntityManagerInterface
*/
public function getEntityManager()
{

View File

@@ -152,7 +152,7 @@ class EntityGenerator
Type::SMALLINT => 'integer',
Type::TEXT => 'string',
Type::BLOB => 'string',
Type::DECIMAL => 'float',
Type::DECIMAL => 'string',
Type::JSON_ARRAY => 'array',
Type::SIMPLE_ARRAY => 'array',
);
@@ -911,7 +911,7 @@ public function __construct()
protected function generateDiscriminatorColumnAnnotation($metadata)
{
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
$discrColumn = $metadata->discriminatorValue;
$discrColumn = $metadata->discriminatorColumn;
$columnDefinition = 'name="' . $discrColumn['name']
. '", type="' . $discrColumn['type']
. '", length=' . $discrColumn['length'];

View File

@@ -193,7 +193,7 @@ class XmlExporter extends AbstractExporter
}
if (isset($field['unique']) && $field['unique']) {
$fieldXml->addAttribute('unique', $field['unique']);
$fieldXml->addAttribute('unique', $field['unique'] ? 'true' : 'false');
}
if (isset($field['options'])) {

View File

@@ -100,9 +100,9 @@ class LimitSubqueryOutputWalker extends SqlWalker
$hiddens[$idx] = $expr->hiddenAliasResultVariable;
$expr->hiddenAliasResultVariable = false;
}
$innerSql = parent::walkSelectStatement($AST);
// Restore hiddens
foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
$expr->hiddenAliasResultVariable = $hiddens[$idx];
@@ -160,11 +160,8 @@ class LimitSubqueryOutputWalker extends SqlWalker
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
implode(', ', $sqlIdentifier), $innerSql);
if ($this->platform instanceof PostgreSqlPlatform ||
$this->platform instanceof OraclePlatform) {
//http://www.doctrine-project.org/jira/browse/DDC-1958
$this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql);
}
// http://www.doctrine-project.org/jira/browse/DDC-1958
$sql = $this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql);
// Apply the limit and offset.
$sql = $this->platform->modifyLimitQuery(
@@ -181,7 +178,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
return $sql;
}
/**
* Generates new SQL for Postgresql or Oracle if necessary.
*
@@ -192,7 +189,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
*
* @return void
*/
public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, &$sql)
public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, $sql)
{
// For every order by, find out the SQL alias by inspecting the ResultSetMapping.
$sqlOrderColumns = array();
@@ -215,11 +212,6 @@ class LimitSubqueryOutputWalker extends SqlWalker
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
}
// We don't need orderBy in inner query.
// However at least on 5.4.6 I'm getting a segmentation fault and thus we don't clear it for now.
/*$AST->orderByClause = null;
$innerSql = parent::walkSelectStatement($AST);*/
if (count($orderBy)) {
$sql = sprintf(
'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
@@ -228,5 +220,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
implode(', ', $orderBy)
);
}
return $sql;
}
}

26
lib/Doctrine/ORM/Tools/Pagination/Paginator.php Normal file → Executable file
View File

@@ -121,7 +121,7 @@ class Paginator implements \Countable, \IteratorAggregate
/* @var $countQuery Query */
$countQuery = $this->cloneQuery($this->query);
if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) {
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
}
@@ -134,7 +134,7 @@ class Paginator implements \Countable, \IteratorAggregate
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
$countQuery->setResultSetMapping($rsm);
} else {
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
$this->appendTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker');
}
$countQuery->setFirstResult(null)->setMaxResults(null);
@@ -165,7 +165,7 @@ class Paginator implements \Countable, \IteratorAggregate
if ($this->useOutputWalker($subQuery)) {
$subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
} else {
$subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
$this->appendTreeWalker($subQuery, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker');
}
$subQuery->setFirstResult($offset)->setMaxResults($length);
@@ -178,7 +178,7 @@ class Paginator implements \Countable, \IteratorAggregate
return new \ArrayIterator(array());
}
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
$this->appendTreeWalker($whereInQuery, 'Doctrine\ORM\Tools\Pagination\WhereInWalker');
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, count($ids));
$whereInQuery->setFirstResult(null)->setMaxResults(null);
$whereInQuery->setParameter(WhereInWalker::PAGINATOR_ID_ALIAS, $ids);
@@ -231,4 +231,22 @@ class Paginator implements \Countable, \IteratorAggregate
return $this->useOutputWalkers;
}
/**
* Appends a custom tree walker to the tree walkers hint.
*
* @param Query $query
* @param string $walkerClass
*/
private function appendTreeWalker(Query $query, $walkerClass)
{
$hints = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS);
if ($hints === false) {
$hints = array();
}
$hints[] = $walkerClass;
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints);
}
}

View File

@@ -26,7 +26,7 @@ use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Internal\CommitOrderCalculator;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
@@ -47,7 +47,7 @@ use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
class SchemaTool
{
/**
* @var \Doctrine\ORM\EntityManager
* @var \Doctrine\ORM\EntityManagerInterface
*/
private $em;
@@ -67,9 +67,9 @@ class SchemaTool
* Initializes a new SchemaTool instance that uses the connection of the
* provided EntityManager.
*
* @param \Doctrine\ORM\EntityManager $em
* @param \Doctrine\ORM\EntityManagerInterface $em
*/
public function __construct(EntityManager $em)
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
$this->platform = $em->getConnection()->getDatabasePlatform();

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Tools;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\DBAL\Types\Type;
@@ -37,14 +37,14 @@ use Doctrine\DBAL\Types\Type;
class SchemaValidator
{
/**
* @var EntityManager
* @var EntityManagerInterface
*/
private $em;
/**
* @param EntityManager $em
* @param EntityManagerInterface $em
*/
public function __construct(EntityManager $em)
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
@@ -241,6 +241,11 @@ class SchemaValidator
continue;
}
if ( ! isset($class->fieldMappings[$publicAttr->getName()]) &&
! isset($class->associationMappings[$publicAttr->getName()])) {
continue;
}
$ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ".
"or protected. Public fields may break lazy-loading.";
}

View File

@@ -530,7 +530,7 @@ class UnitOfWork implements PropertyChangedListener
$class = $this->em->getClassMetadata(get_class($entity));
}
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush);
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush) & ~ListenersInvoker::INVOKE_MANAGER;
if ($invoke !== ListenersInvoker::INVOKE_NONE) {
$this->listenersInvoker->invoke($class, Events::preFlush, $entity, new PreFlushEventArgs($this->em), $invoke);
@@ -541,7 +541,15 @@ class UnitOfWork implements PropertyChangedListener
foreach ($class->reflFields as $name => $refProp) {
$value = $refProp->getValue($entity);
if ($class->isCollectionValuedAssociation($name) && $value !== null && ! ($value instanceof PersistentCollection)) {
if ($class->isCollectionValuedAssociation($name) && $value !== null) {
if ($value instanceof PersistentCollection) {
if ($value->getOwner() === $entity) {
continue;
}
$value = new ArrayCollection($value->getValues());
}
// If $value is not a Collection then use an ArrayCollection.
if ( ! $value instanceof Collection) {
$value = new ArrayCollection($value);
@@ -894,20 +902,24 @@ class UnitOfWork implements PropertyChangedListener
$actualData = array();
foreach ($class->reflFields as $name => $refProp) {
if ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) {
if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
&& ($name !== $class->versionField)
&& ! $class->isCollectionValuedAssociation($name)) {
$actualData[$name] = $refProp->getValue($entity);
}
}
if ( ! isset($this->originalEntityData[$oid])) {
throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
}
$originalData = $this->originalEntityData[$oid];
$changeSet = array();
foreach ($actualData as $propName => $actualValue) {
$orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
if (is_object($orgValue) && $orgValue !== $actualValue) {
$changeSet[$propName] = array($orgValue, $actualValue);
} else if ($orgValue != $actualValue || ($orgValue === null ^ $actualValue === null)) {
if ($orgValue !== $actualValue) {
$changeSet[$propName] = array($orgValue, $actualValue);
}
}
@@ -915,8 +927,10 @@ class UnitOfWork implements PropertyChangedListener
if ($changeSet) {
if (isset($this->entityChangeSets[$oid])) {
$this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
} else if ( ! isset($this->entityInsertions[$oid])) {
$this->entityChangeSets[$oid] = $changeSet;
$this->entityUpdates[$oid] = $entity;
}
$this->originalEntityData[$oid] = $actualData;
}
}
@@ -1736,6 +1750,8 @@ class UnitOfWork implements PropertyChangedListener
$associatedId = $this->getEntityIdentifier($idValue);
$flatId[$idField] = $associatedId[$targetClassMetadata->identifier[0]];
} else {
$flatId[$idField] = $idValue;
}
}
@@ -2231,6 +2247,8 @@ class UnitOfWork implements PropertyChangedListener
function ($assoc) { return $assoc['isCascadeRemove']; }
);
$entitiesToCascade = array();
foreach ($associationMappings as $assoc) {
if ($entity instanceof Proxy && !$entity->__isInitialized__) {
$entity->__load();
@@ -2243,18 +2261,22 @@ class UnitOfWork implements PropertyChangedListener
case (is_array($relatedEntities)):
// If its a PersistentCollection initialization is intended! No unwrap!
foreach ($relatedEntities as $relatedEntity) {
$this->doRemove($relatedEntity, $visited);
$entitiesToCascade[] = $relatedEntity;
}
break;
case ($relatedEntities !== null):
$this->doRemove($relatedEntities, $visited);
$entitiesToCascade[] = $relatedEntities;
break;
default:
// Do nothing
}
}
foreach ($entitiesToCascade as $relatedEntity) {
$this->doRemove($relatedEntity, $visited);
}
}
/**
@@ -2471,16 +2493,16 @@ class UnitOfWork implements PropertyChangedListener
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
: $data[$fieldName];
}
$idHash = implode(' ', $id);
} else {
$idHash = isset($class->associationMappings[$class->identifier[0]])
$id = isset($class->associationMappings[$class->identifier[0]])
? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]
: $data[$class->identifier[0]];
$id = array($class->identifier[0] => $idHash);
$id = array($class->identifier[0] => $id);
}
$idHash = implode(' ', $id);
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
$entity = $this->identityMap[$class->rootEntityName][$idHash];
$oid = spl_object_hash($entity);
@@ -2490,14 +2512,14 @@ class UnitOfWork implements PropertyChangedListener
&& isset($hints[Query::HINT_REFRESH_ENTITY])
&& ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
&& $unmanagedProxy instanceof Proxy
&& (($unmanagedProxyClass = $this->em->getClassMetadata(get_class($unmanagedProxy))) === $class)
&& $this->isIdentifierEquals($unmanagedProxy, $entity)
) {
// DDC-1238 - we have a managed instance, but it isn't the provided one.
// Therefore we clear its identifier. Also, we must re-fetch metadata since the
// refreshed object may be anything
foreach ($unmanagedProxyClass->identifier as $fieldName) {
$unmanagedProxyClass->reflFields[$fieldName]->setValue($unmanagedProxy, null);
foreach ($class->identifier as $fieldName) {
$class->reflFields[$fieldName]->setValue($unmanagedProxy, null);
}
return $unmanagedProxy;
@@ -3206,4 +3228,37 @@ class UnitOfWork implements PropertyChangedListener
$this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
}
}
/**
* Verifies if two given entities actually are the same based on identifier comparison
*
* @param object $entity1
* @param object $entity2
*
* @return bool
*/
private function isIdentifierEquals($entity1, $entity2)
{
if ($entity1 === $entity2) {
return true;
}
$class = $this->em->getClassMetadata(get_class($entity1));
if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
return false;
}
$oid1 = spl_object_hash($entity1);
$oid2 = spl_object_hash($entity2);
$id1 = isset($this->entityIdentifiers[$oid1])
? $this->entityIdentifiers[$oid1]
: $this->flattenIdentifier($class, $class->getIdentifierValues($entity1));
$id2 = isset($this->entityIdentifiers[$oid2])
? $this->entityIdentifiers[$oid2]
: $this->flattenIdentifier($class, $class->getIdentifierValues($entity2));
return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
}
}

View File

@@ -36,7 +36,7 @@ class Version
/**
* Current Doctrine Version
*/
const VERSION = '2.4.0-DEV';
const VERSION = '2.4.6';
/**
* Compares a Doctrine version with the current one.

View File

@@ -137,6 +137,11 @@ class ECommerceProduct
}
}
public function setCategories($categories)
{
$this->categories = $categories;
}
public function getCategories()
{
return $this->categories;
@@ -166,6 +171,9 @@ class ECommerceProduct
public function __clone()
{
$this->isCloned = true;
if ($this->categories) {
$this->categories = clone $this->categories;
}
}
/**

View File

@@ -0,0 +1,42 @@
<?php
namespace Doctrine\Tests\Models\Taxi;
/**
* @Entity
* @Table(name="taxi_car")
*/
class Car
{
/**
* @Id
* @Column(type="string", length=25)
* @GeneratedValue(strategy="NONE")
*/
private $brand;
/**
* @Column(type="string", length=255);
*/
private $model;
/**
* @OneToMany(targetEntity="Ride", mappedBy="car")
*/
private $freeCarRides;
/**
* @OneToMany(targetEntity="PaidRide", mappedBy="car")
*/
private $carRides;
public function setBrand($brand)
{
$this->brand = $brand;
}
public function setModel($model)
{
$this->model = $model;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Doctrine\Tests\Models\Taxi;
/**
* @Entity
* @Table(name="taxi_driver")
*/
class Driver
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @Column(type="string", length=255);
*/
private $name;
/**
* @OneToMany(targetEntity="Ride", mappedBy="driver")
*/
private $freeDriverRides;
/**
* @OneToMany(targetEntity="PaidRide", mappedBy="driver")
*/
private $driverRides;
public function setName($name)
{
$this->name = $name;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Doctrine\Tests\Models\Taxi;
/**
* Same as Ride but with an extra column that is not part of the composite primary key
*
* @Entity
* @Table(name="taxi_paid_ride")
*/
class PaidRide
{
/**
* @Id
* @ManyToOne(targetEntity="Driver", inversedBy="driverRides")
* @JoinColumn(name="driver_id", referencedColumnName="id")
*/
private $driver;
/**
* @Id
* @ManyToOne(targetEntity="Car", inversedBy="carRides")
* @JoinColumn(name="car", referencedColumnName="brand")
*/
private $car;
/**
* @Column(type="decimal", precision=6, scale=2)
*/
private $fare;
public function __construct(Driver $driver, Car $car)
{
$this->driver = $driver;
$this->car = $car;
}
public function setFare($fare)
{
$this->fare = $fare;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Doctrine\Tests\Models\Taxi;
/**
* Test model that contains only Id-columns
*
* @Entity
* @Table(name="taxi_ride")
*/
class Ride
{
/**
* @Id
* @ManyToOne(targetEntity="Driver", inversedBy="freeDriverRides")
* @JoinColumn(name="driver_id", referencedColumnName="id")
*/
private $driver;
/**
* @Id
* @ManyToOne(targetEntity="Car", inversedBy="freeCarRides")
* @JoinColumn(name="car", referencedColumnName="brand")
*/
private $car;
public function __construct(Driver $driver, Car $car)
{
$this->driver = $driver;
$this->car = $car;
}
}

View File

@@ -7,6 +7,8 @@ use Doctrine\ORM\OptimisticLockException;
use Doctrine\Common\EventManager;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\Tests\TestUtil;
use Doctrine\DBAL\LockMode;
use DateTime;
require_once __DIR__ . '/../../../TestInit.php';
@@ -181,13 +183,44 @@ class OptimisticTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_conn->executeQuery('UPDATE optimistic_timestamp SET version = ? WHERE id = ?', array(date($format, strtotime($test->version->format($format)) + 3600), $test->id));
// Try and update the record and it should throw an exception
$caughtException = null;
$test->name = 'Testing again';
try {
$this->_em->flush();
} catch (OptimisticLockException $e) {
$this->assertSame($test, $e->getEntity());
$caughtException = $e;
}
$this->assertNotNull($caughtException, "No OptimisticLockingException was thrown");
$this->assertSame($test, $caughtException->getEntity());
}
/**
* @depends testOptimisticTimestampSetsDefaultValue
*/
public function testOptimisticTimestampLockFailureThrowsException(OptimisticTimestamp $entity)
{
$q = $this->_em->createQuery('SELECT t FROM Doctrine\Tests\ORM\Functional\Locking\OptimisticTimestamp t WHERE t.id = :id');
$q->setParameter('id', $entity->id);
$test = $q->getSingleResult();
$this->assertInstanceOf('DateTime', $test->version);
// Try to lock the record with an older timestamp and it should throw an exception
$caughtException = null;
try {
$expectedVersionExpired = DateTime::createFromFormat('U', $test->version->getTimestamp()-3600);
$this->_em->lock($test, LockMode::OPTIMISTIC, $expectedVersionExpired);
} catch (OptimisticLockException $e) {
$caughtException = $e;
}
$this->assertNotNull($caughtException, "No OptimisticLockingException was thrown");
$this->assertSame($test, $caughtException->getEntity());
}
}
/**

View File

@@ -719,7 +719,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$selectClause = $rsm->generateSelectClause();
$this->assertEquals('u.id AS id, u.status AS status, u.username AS username, u.name AS name, u.email_id AS email_id', $selectClause);
$this->assertSQLEquals('u.id AS id, u.status AS status, u.username AS username, u.name AS name, u.email_id AS email_id', $selectClause);
}
/**
@@ -735,7 +735,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$selectClause = $rsm->generateSelectClause();
$this->assertEquals('u.id AS id1, u.status AS status, u.username AS username2, u.name AS name, u.email_id AS email_id', $selectClause);
$this->assertSQLEquals('u.id AS id1, u.status AS status, u.username AS username2, u.name AS name, u.email_id AS email_id', $selectClause);
}
/**
@@ -748,7 +748,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$selectClause = $rsm->generateSelectClause(array('u' => 'u1'));
$this->assertEquals('u1.id AS id, u1.status AS status, u1.username AS username, u1.name AS name, u1.email_id AS email_id', $selectClause);
$this->assertSQLEquals('u1.id AS id, u1.status AS status, u1.username AS username, u1.name AS name, u1.email_id AS email_id', $selectClause);
}
/**
@@ -761,7 +761,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$selectClause = $rsm->generateSelectClause();
$this->assertEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', $selectClause);
$this->assertSQLEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', $selectClause);
}
/**
@@ -772,6 +772,6 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$rsm = new ResultSetMappingBuilder($this->_em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
$rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$this->assertEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', (string)$rsm);
$this->assertSQLEquals('u.id AS id0, u.status AS status1, u.username AS username2, u.name AS name3, u.email_id AS email_id4', (string)$rsm);
}
}

View File

@@ -128,14 +128,14 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
$train = $this->_em->find(get_class($train), $train->id);
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.driver_id AS driver_id2, t3.id AS id4, t3.name AS name5, t0.owner_id AS owner_id6, t7.id AS id8, t7.name AS name9 FROM Train t0 LEFT JOIN TrainDriver t3 ON t0.driver_id = t3.id INNER JOIN TrainOwner t7 ON t0.owner_id = t7.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
$this->_em->clear();
$driver = $this->_em->find(get_class($driver), $driver->id);
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id IN (?)",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
@@ -156,13 +156,13 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$waggon = $this->_em->find(get_class($waggon), $waggon->id);
// The last query is the eager loading of the owner of the train
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id IN (?)",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
// The one before is the fetching of the waggon and train
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.train_id AS train_id2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM Waggon t0 INNER JOIN Train t3 ON t0.train_id = t3.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery - 1]['sql']
);
@@ -177,7 +177,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
$waggon = $this->_em->find(get_class($owner), $owner->id);
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);

View File

@@ -139,6 +139,18 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertTrue($query->getParameters()->isEmpty());
}
public function testQueryWalkerIsKept()
{
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u";
$query = $this->_em->createQuery($dql);
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\Tests\ORM\Functional\CustomPaginationTestTreeWalker'));
$paginator = new Paginator($query, true);
$paginator->setUseOutputWalkers(false);
$this->assertCount(1, $paginator->getIterator());
$this->assertEquals(1, $paginator->count());
}
public function populate()
{
for ($i = 0; $i < 3; $i++) {
@@ -166,3 +178,22 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase
);
}
}
class CustomPaginationTestTreeWalker extends Query\TreeWalkerAdapter
{
public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
{
$condition = new Query\AST\ConditionalPrimary();
$path = new Query\AST\PathExpression(Query\AST\PathExpression::TYPE_STATE_FIELD, 'u', 'name');
$path->type = Query\AST\PathExpression::TYPE_STATE_FIELD;
$condition->simpleConditionalExpression = new Query\AST\ComparisonExpression(
$path,
'=',
new Query\AST\Literal(Query\AST\Literal::STRING, 'Name1')
);
$selectStatement->whereClause = new Query\AST\WhereClause($condition);
}
}

View File

@@ -48,8 +48,9 @@ class ProxiesLikeEntitiesTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testPersistUpdate()
{
// Considering case (a)
$proxy = $this->_em->getProxyFactory()->getProxy('Doctrine\Tests\Models\CMS\CmsUser', array('id' => null));
$proxy = $this->_em->getProxyFactory()->getProxy('Doctrine\Tests\Models\CMS\CmsUser', array('id' => 123));
$proxy->__isInitialized__ = true;
$proxy->id = null;
$proxy->username = 'ocra';
$proxy->name = 'Marco';
$this->_em->persist($proxy);

View File

@@ -35,8 +35,8 @@ class DDC1430Test extends \Doctrine\Tests\OrmFunctionalTestCase
->orderBy('o.id')
->getQuery();
$this->assertEquals('SELECT o.id, o.date, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date ORDER BY o.id ASC', $query->getDQL());
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, COUNT(d1_.id) AS sclr2 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at ORDER BY d0_.order_id ASC', $query->getSQL());
$this->assertSQLEquals('SELECT o.id, o.date, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date ORDER BY o.id ASC', $query->getDQL());
$this->assertSQLEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, COUNT(d1_.id) AS sclr2 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at ORDER BY d0_.order_id ASC', $query->getSQL());
$result = $query->getResult();
@@ -67,8 +67,8 @@ class DDC1430Test extends \Doctrine\Tests\OrmFunctionalTestCase
->getQuery();
$this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date, o.status ORDER BY o.id ASC', $query->getDQL());
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
$this->assertSQLEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date, o.status ORDER BY o.id ASC', $query->getDQL());
$this->assertSQLEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
$result = $query->getResult();
@@ -96,8 +96,8 @@ class DDC1430Test extends \Doctrine\Tests\OrmFunctionalTestCase
->getQuery();
$this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o ORDER BY o.id ASC', $query->getDQL());
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
$this->assertSQLEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o ORDER BY o.id ASC', $query->getDQL());
$this->assertSQLEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
$result = $query->getResult();
@@ -294,4 +294,4 @@ class DDC1430OrderProduct
$this->value = $value;
}
}
}

View File

@@ -35,7 +35,7 @@ class DDC1595Test extends \Doctrine\Tests\OrmFunctionalTestCase
$entity1 = $repository->find($e1->id);
// DDC-1596
$this->assertEquals(
$this->assertSQLEquals(
"SELECT t0.id AS id1, t0.type FROM base t0 WHERE t0.id = ? AND t0.type IN ('Entity1')",
$sqlLogger->queries[count($sqlLogger->queries)]['sql']
);
@@ -52,8 +52,8 @@ class DDC1595Test extends \Doctrine\Tests\OrmFunctionalTestCase
$entity1 = $repository->find($e1->id);
$entities = $entity1->getEntities()->count();
$this->assertEquals(
"SELECT COUNT(*) FROM entity1_entity2 t WHERE parent = ?",
$this->assertSQLEquals(
"SELECT COUNT(*) FROM entity1_entity2 t WHERE t.parent = ?",
$sqlLogger->queries[count($sqlLogger->queries)]['sql']
);
}
@@ -108,4 +108,4 @@ class DDC1595InheritedEntity1 extends DDC1595BaseInheritance
*/
class DDC1595InheritedEntity2 extends DDC1595BaseInheritance
{
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\Taxi\Car,
Doctrine\Tests\Models\Taxi\Driver,
Doctrine\Tests\Models\Taxi\Ride,
Doctrine\Tests\Models\Taxi\PaidRide;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-1884
* @author Sander Coolen <sander@jibber.nl>
*/
class DDC1884Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('taxi');
parent::setUp();
list($bimmer, $crysler, $merc, $volvo) = $this->createCars('Doctrine\Tests\Models\Taxi\Car');
list($john, $foo) = $this->createDrivers('Doctrine\Tests\Models\Taxi\Driver');
$this->_em->flush();
$ride1 = new Ride($john, $bimmer);
$ride2 = new Ride($john, $merc);
$ride3 = new Ride($john, $volvo);
$ride4 = new Ride($foo, $merc);
$this->_em->persist($ride1);
$this->_em->persist($ride2);
$this->_em->persist($ride3);
$this->_em->persist($ride4);
$ride5 = new PaidRide($john, $bimmer);
$ride5->setFare(10.50);
$ride6 = new PaidRide($john, $merc);
$ride6->setFare(16.00);
$ride7 = new PaidRide($john, $volvo);
$ride7->setFare(20.70);
$ride8 = new PaidRide($foo, $merc);
$ride8->setFare(32.15);
$this->_em->persist($ride5);
$this->_em->persist($ride6);
$this->_em->persist($ride7);
$this->_em->persist($ride8);
$this->_em->flush();
}
private function createCars($class)
{
$bimmer = new $class;
$bimmer->setBrand('BMW');
$bimmer->setModel('7-Series');
$crysler = new $class;
$crysler->setBrand('Crysler');
$crysler->setModel('300');
$merc = new $class;
$merc->setBrand('Mercedes');
$merc->setModel('C-Class');
$volvo = new $class;
$volvo->setBrand('Volvo');
$volvo->setModel('XC90');
$this->_em->persist($bimmer);
$this->_em->persist($crysler);
$this->_em->persist($merc);
$this->_em->persist($volvo);
return array($bimmer, $crysler, $merc, $volvo);
}
private function createDrivers($class)
{
$john = new $class;
$john->setName('John Doe');
$foo = new $class;
$foo->setName('Foo Bar');
$this->_em->persist($foo);
$this->_em->persist($john);
return array($john, $foo);
}
/**
* 1) Ride contains only columns that are part of its composite primary key
* 2) We use fetch joins here
*/
public function testSelectFromInverseSideWithCompositePkAndSolelyIdentifierColumnsUsingFetchJoins()
{
$qb = $this->_em->createQueryBuilder();
$result = $qb->select('d, dr, c')
->from('Doctrine\Tests\Models\Taxi\Driver', 'd')
->leftJoin('d.freeDriverRides', 'dr')
->leftJoin('dr.car', 'c')
->where('d.name = ?1')
->setParameter(1, 'John Doe')
->getQuery()
->getArrayResult();
$this->assertCount(1, $result);
$this->assertArrayHasKey('freeDriverRides', $result[0]);
$this->assertCount(3, $result[0]['freeDriverRides']);
}
/**
* 1) PaidRide contains an extra column that is not part of the composite primary key
* 2) Again we will use fetch joins
*/
public function testSelectFromInverseSideWithCompositePkUsingFetchJoins()
{
$qb = $this->_em->createQueryBuilder();
$result = $qb->select('d, dr, c')
->from('Doctrine\Tests\Models\Taxi\Driver', 'd')
->leftJoin('d.driverRides', 'dr')
->leftJoin('dr.car', 'c')
->where('d.name = ?1')
->setParameter(1, 'John Doe')
->getQuery()->getArrayResult();
$this->assertCount(1, $result);
$this->assertArrayHasKey('driverRides', $result[0]);
$this->assertCount(3, $result[0]['driverRides']);
}
/**
* The other way around will fail too
*/
public function testSelectFromOwningSideUsingFetchJoins()
{
$qb = $this->_em->createQueryBuilder();
$result = $qb->select('r, d, c')
->from('Doctrine\Tests\Models\Taxi\PaidRide', 'r')
->leftJoin('r.driver', 'd')
->leftJoin('r.car', 'c')
->where('d.name = ?1')
->setParameter(1, 'John Doe')
->getQuery()->getArrayResult();
$this->assertCount(3, $result);
$this->assertArrayHasKey('driver', $result[0]);
$this->assertArrayHasKey('car', $result[0]);
}
}

View File

@@ -12,6 +12,12 @@ use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
*/
class DDC2074Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
$this->useModelSet('ecommerce');
parent::setUp();
}
public function testShouldNotScheduleDeletionOnClonedInstances()
{
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
@@ -26,4 +32,30 @@ class DDC2074Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, count($uow->getScheduledCollectionDeletions()));
}
}
public function testSavingClonedPersistentCollection()
{
$product = new ECommerceProduct();
$category = new ECommerceCategory();
$category->setName('foo');
$product->addCategory($category);
$this->_em->persist($product);
$this->_em->persist($category);
$this->_em->flush();
$newProduct = clone $product;
$this->_em->persist($newProduct);
$this->_em->flush();
$this->_em->clear();
$product1 = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $product->getId());
$product2 = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $newProduct->getId());
$this->assertCount(1, $product1->getCategories());
$this->assertCount(1, $product2->getCategories());
$this->assertSame($product1->getCategories()->get(0), $product2->getCategories()->get(0));
}
}

View File

@@ -0,0 +1,180 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* @group DDC-2579
*/
class DDC2579Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
Type::addType(DDC2579Type::NAME, DDC2579Type::CLASSNAME);
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(DDC2579Entity::CLASSNAME),
$this->_em->getClassMetadata(DDC2579EntityAssoc::CLASSNAME),
$this->_em->getClassMetadata(DDC2579AssocAssoc::CLASSNAME),
));
}
public function testIssue()
{
$id = new DDC2579Id("foo");
$assoc = new DDC2579AssocAssoc($id);
$assocAssoc = new DDC2579EntityAssoc($assoc);
$entity = new DDC2579Entity($assocAssoc);
$repository = $this->_em->getRepository(DDC2579Entity::CLASSNAME);
$this->_em->persist($assoc);
$this->_em->persist($assocAssoc);
$this->_em->persist($entity);
$this->_em->flush();
$entity->value++;
$this->_em->persist($entity);
$this->_em->flush();
$this->_em->clear();
$id = $entity->id;
$value = $entity->value;
$criteria = array('assoc' => $assoc, 'id' => $id);
$entity = $repository->findOneBy($criteria);
$this->assertInstanceOf(DDC2579Entity::CLASSNAME, $entity);
$this->assertEquals($value, $entity->value);
$this->_em->remove($entity);
$this->_em->flush();
$this->_em->clear();
$this->assertNull($repository->findOneBy($criteria));
$this->assertCount(0, $repository->findAll());
}
}
/**
* @Entity
*/
class DDC2579Entity
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @Column(type="ddc2579")
*/
public $id;
/**
* @Id
* @ManyToOne(targetEntity="DDC2579EntityAssoc")
* @JoinColumn(name="relation_id", referencedColumnName="association_id")
*/
public $assoc;
/**
* @Column(type="integer")
*/
public $value;
public function __construct(DDC2579EntityAssoc $assoc, $value = 0)
{
$this->id = $assoc->assocAssoc->associationId;
$this->assoc = $assoc;
$this->value = $value;
}
}
/**
* @Entity
*/
class DDC2579EntityAssoc
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @ManyToOne(targetEntity="DDC2579AssocAssoc")
* @JoinColumn(name="association_id", referencedColumnName="associationId")
*/
public $assocAssoc;
public function __construct(DDC2579AssocAssoc $assocAssoc)
{
$this->assocAssoc = $assocAssoc;
}
}
/**
* @Entity
*/
class DDC2579AssocAssoc
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @Column(type="ddc2579")
*/
public $associationId;
public function __construct(DDC2579Id $id)
{
$this->associationId = $id;
}
}
class DDC2579Type extends StringType
{
const NAME = 'ddc2579';
const CLASSNAME = __CLASS__;
/**
* {@inheritdoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return (string)$value;
}
public function convertToPhpValue($value, AbstractPlatform $platform)
{
return new DDC2579Id($value);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return self::NAME;
}
}
class DDC2579Id
{
const CLASSNAME = __CLASS__;
private $val;
public function __construct($val)
{
$this->val = $val;
}
public function __toString()
{
return $this->val;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-2645
*/
class DDC2645Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function testIssue()
{
$bar = new DDC2645Bar;
$bar->id = 123;
$foo = new DDC2645Foo(1, $bar, 'Foo');
$foo2 = new DDC2645Foo(1, $bar, 'Bar');
$this->_em->persist($bar);
$this->_em->persist($foo);
$foo3 = $this->_em->merge($foo2);
$this->assertSame($foo, $foo3);
$this->assertEquals('Bar', $foo->name);
}
}
/** @Entity */
class DDC2645Foo
{
/** @Id @Column(type="integer") */
private $id;
/** @Id @ManyToOne(targetEntity="DDC2645Bar") */
private $bar;
/** @Column */
public $name;
public function __construct($id, $bar, $name)
{
$this->id = $id;
$this->bar = $bar;
$this->name = $name;
}
}
/** @Entity */
class DDC2645Bar
{
/** @Id @Column(type="integer") @GeneratedValue(strategy="NONE") */
public $id;
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @group
*/
class DDC2660Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* {@inheritDoc}
*/
protected function setup()
{
parent::setup();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2660Product'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2660Customer'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2660CustomerOrder')
));
} catch(\Exception $e) {
return;
}
for ($i = 0; $i < 5; $i++) {
$product = new DDC2660Product();
$customer = new DDC2660Customer();
$order = new DDC2660CustomerOrder($product, $customer, 'name' . $i);
$this->_em->persist($product);
$this->_em->persist($customer);
$this->_em->flush();
$this->_em->persist($order);
$this->_em->flush();
}
$this->_em->clear();
}
public function testIssueWithExtraColumn()
{
$sql = "SELECT o.product_id, o.customer_id, o.name FROM ddc_2660_customer_order o";
$rsm = new ResultSetMappingBuilder($this->_getEntityManager());
$rsm->addRootEntityFromClassMetadata(__NAMESPACE__ . '\DDC2660CustomerOrder', 'c');
$query = $this->_em->createNativeQuery($sql, $rsm);
$result = $query->getResult();
$this->assertCount(5, $result);
foreach ($result as $order) {
$this->assertNotNull($order);
$this->assertInstanceOf(__NAMESPACE__ . '\\DDC2660CustomerOrder', $order);
}
}
public function testIssueWithoutExtraColumn()
{
$sql = "SELECT o.product_id, o.customer_id FROM ddc_2660_customer_order o";
$rsm = new ResultSetMappingBuilder($this->_getEntityManager());
$rsm->addRootEntityFromClassMetadata(__NAMESPACE__ . '\DDC2660CustomerOrder', 'c');
$query = $this->_em->createNativeQuery($sql, $rsm);
$result = $query->getResult();
$this->assertCount(5, $result);
foreach ($result as $order) {
$this->assertNotNull($order);
$this->assertInstanceOf(__NAMESPACE__ . '\\DDC2660CustomerOrder', $order);
}
}
}
/**
* @Entity @Table(name="ddc_2660_product")
*/
class DDC2660Product
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/** @Entity @Table(name="ddc_2660_customer") */
class DDC2660Customer
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/** @Entity @Table(name="ddc_2660_customer_order") */
class DDC2660CustomerOrder
{
/**
* @Id @ManyToOne(targetEntity="DDC2660Product")
*/
public $product;
/**
* @Id @ManyToOne(targetEntity="DDC2660Customer")
*/
public $customer;
/**
* @Column(type="string")
*/
public $name;
public function __construct(DDC2660Product $product, DDC2660Customer $customer, $name)
{
$this->product = $product;
$this->customer = $customer;
$this->name = $name;
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\PreFlushEventArgs;
/**
* @group DDC-2692
*/
class DDC2692Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* {@inheritDoc}
*/
protected function setup()
{
parent::setup();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2692Foo'),
));
} catch(\Exception $e) {
return;
}
$this->_em->clear();
}
public function testIsListenerCalledOnlyOnceOnPreFlush()
{
$listener = $this->getMock('Doctrine\Tests\ORM\Functional\Ticket\DDC2692Listener', array('preFlush'));
$listener->expects($this->once())->method('preFlush');
$this->_em->getEventManager()->addEventSubscriber($listener);
$this->_em->persist(new DDC2692Foo);
$this->_em->persist(new DDC2692Foo);
$this->_em->flush();
$this->_em->clear();
}
}
/**
* @Entity @Table(name="ddc_2692_foo")
*/
class DDC2692Foo
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
class DDC2692Listener implements EventSubscriber {
public function getSubscribedEvents() {
return array(\Doctrine\ORM\Events::preFlush);
}
public function preFlush(PreFlushEventArgs $args) {
}
}

View File

@@ -0,0 +1,121 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
/**
* @group DDC-2759
*/
class DDC2759Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* {@inheritDoc}
*/
protected function setup()
{
parent::setup();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759Qualification'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759Category'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759QualificationMetadata'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759MetadataCategory'),
));
} catch(\Exception $e) {
return;
}
$qualification = new DDC2759Qualification();
$qualificationMetadata = new DDC2759QualificationMetadata($qualification);
$category1 = new DDC2759Category();
$category2 = new DDC2759Category();
$metadataCategory1 = new DDC2759MetadataCategory($qualificationMetadata, $category1);
$metadataCategory2 = new DDC2759MetadataCategory($qualificationMetadata, $category2);
$this->_em->persist($qualification);
$this->_em->persist($qualificationMetadata);
$this->_em->persist($category1);
$this->_em->persist($category2);
$this->_em->persist($metadataCategory1);
$this->_em->persist($metadataCategory2);
$this->_em->flush();
$this->_em->clear();
}
public function testCorrectNumberOfAssociationsIsReturned()
{
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC2759Qualification');
$builder = $repository->createQueryBuilder('q')
->select('q, qm, qmc')
->innerJoin('q.metadata', 'qm')
->innerJoin('qm.metadataCategories', 'qmc');
$result = $builder->getQuery()
->getArrayResult();
$this->assertCount(2, $result[0]['metadata']['metadataCategories']);
}
}
/** @Entity @Table(name="ddc_2759_qualification") */
class DDC2759Qualification
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @OneToOne(targetEntity="DDC2759QualificationMetadata", mappedBy="content") */
public $metadata;
}
/** @Entity @Table(name="ddc_2759_category") */
class DDC2759Category
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @OneToMany(targetEntity="DDC2759MetadataCategory", mappedBy="category") */
public $metadataCategories;
}
/** @Entity @Table(name="ddc_2759_qualification_metadata") */
class DDC2759QualificationMetadata
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @OneToOne(targetEntity="DDC2759Qualification", inversedBy="metadata") */
public $content;
/** @OneToMany(targetEntity="DDC2759MetadataCategory", mappedBy="metadata") */
protected $metadataCategories;
public function __construct(DDC2759Qualification $content)
{
$this->content = $content;
}
}
/** @Entity @Table(name="ddc_2759_metadata_category") */
class DDC2759MetadataCategory
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @ManyToOne(targetEntity="DDC2759QualificationMetadata", inversedBy="metadataCategories") */
public $metadata;
/** @ManyToOne(targetEntity="DDC2759Category", inversedBy="metadataCategories") */
public $category;
public function __construct(DDC2759QualificationMetadata $metadata, DDC2759Category $category)
{
$this->metadata = $metadata;
$this->category = $category;
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* Functional tests for cascade remove with class table inheritance.
*
* @author Matthieu Napoli <matthieu@mnapoli.fr>
*/
class DDC2775Test extends OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
$this->setUpEntitySchema(array(
'Doctrine\Tests\ORM\Functional\Ticket\User',
'Doctrine\Tests\ORM\Functional\Ticket\Role',
'Doctrine\Tests\ORM\Functional\Ticket\AdminRole',
'Doctrine\Tests\ORM\Functional\Ticket\Authorization',
));
}
/**
* @group DDC-2775
*/
public function testIssueCascadeRemove()
{
$user = new User();
$role = new AdminRole();
$user->addRole($role);
$authorization = new Authorization();
$user->addAuthorization($authorization);
$role->addAuthorization($authorization);
$this->_em->persist($user);
$this->_em->flush();
// Need to clear so that associations are lazy-loaded
$this->_em->clear();
$user = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\User', $user->id);
$this->_em->remove($user);
$this->_em->flush();
// With the bug, the second flush throws an error because the cascade remove didn't work correctly
$this->_em->flush();
}
}
/**
* @Entity @Table(name="ddc2775_role")
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="role_type", type="string")
* @DiscriminatorMap({"admin"="AdminRole"})
*/
abstract class Role
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
/**
* @ManyToOne(targetEntity="User", inversedBy="roles")
*/
public $user;
/**
* @OneToMany(targetEntity="Authorization", mappedBy="role", cascade={"all"}, orphanRemoval=true)
*/
public $authorizations;
public function addAuthorization(Authorization $authorization)
{
$this->authorizations[] = $authorization;
$authorization->role = $this;
}
}
/** @Entity @Table(name="ddc2775_admin_role") */
class AdminRole extends Role
{
}
/**
* @Entity @Table(name="ddc2775_authorizations")
*/
class Authorization
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
/**
* @ManyToOne(targetEntity="User", inversedBy="authorizations")
*/
public $user;
/**
* @ManyToOne(targetEntity="Role", inversedBy="authorizations")
*/
public $role;
}
/**
* @Entity @Table(name="ddc2775_users")
*/
class User
{
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* @OneToMany(targetEntity="Role", mappedBy="user", cascade={"all"}, orphanRemoval=true)
*/
public $roles;
/**
* @OneToMany(targetEntity="Authorization", mappedBy="user", cascade={"all"}, orphanRemoval=true)
*/
public $authorizations;
public function addRole(Role $role)
{
$this->roles[] = $role;
$role->user = $this;
}
public function addAuthorization(Authorization $authorization)
{
$this->authorizations[] = $authorization;
$authorization->user = $this;
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
/**
* Class DDC2895Test
* @package Doctrine\Tests\ORM\Functional\Ticket
* @author http://github.com/gwagner
*/
class DDC2895Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2895'),
));
} catch(\Exception $e) {
}
}
public function testPostLoadOneToManyInheritance()
{
$cm = $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2895');
$this->assertEquals(
array(
"prePersist" => array("setLastModifiedPreUpdate"),
"preUpdate" => array("setLastModifiedPreUpdate"),
),
$cm->lifecycleCallbacks
);
$ddc2895 = new DDC2895();
$this->_em->persist($ddc2895);
$this->_em->flush();
$this->_em->clear();
/** @var DDC2895 $ddc2895 */
$ddc2895 = $this->_em->find(get_class($ddc2895), $ddc2895->id);
$this->assertNotNull($ddc2895->getLastModified());
}
}
/**
* @MappedSuperclass
* @HasLifecycleCallbacks
*/
abstract class AbstractDDC2895
{
/**
* @Column(name="last_modified", type="datetimetz", nullable=false)
* @var \DateTime
*/
protected $lastModified;
/**
* @PrePersist
* @PreUpdate
*/
public function setLastModifiedPreUpdate()
{
$this->setLastModified(new \DateTime());
}
/**
* @param \DateTime $lastModified
*/
public function setLastModified( $lastModified )
{
$this->lastModified = $lastModified;
}
/**
* @return \DateTime
*/
public function getLastModified()
{
return $this->lastModified;
}
}
/**
* @Entity
* @HasLifecycleCallbacks
*/
class DDC2895 extends AbstractDDC2895
{
/** @Id @GeneratedValue @Column(type="integer") */
public $id;
/**
* @param mixed $id
*/
public function setId( $id )
{
$this->id = $id;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-2931
*/
class DDC2931Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2931User'),
));
} catch (\Exception $e) {
// no action needed - schema seems to be already in place
}
}
public function testIssue()
{
$first = new DDC2931User();
$second = new DDC2931User();
$third = new DDC2931User();
$second->parent = $first;
$third->parent = $second;
$this->_em->persist($first);
$this->_em->persist($second);
$this->_em->persist($third);
$this->_em->flush();
$this->_em->clear();
$second = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC2931User', $second->id);
$this->assertSame(2, $second->getRank());
}
public function testFetchJoinedEntitiesCanBeRefreshed()
{
$first = new DDC2931User();
$second = new DDC2931User();
$third = new DDC2931User();
$second->parent = $first;
$third->parent = $second;
$first->value = 1;
$second->value = 2;
$third->value = 3;
$this->_em->persist($first);
$this->_em->persist($second);
$this->_em->persist($third);
$this->_em->flush();
$first->value = 4;
$second->value = 5;
$third->value = 6;
$refreshedSecond = $this
->_em
->createQuery(
'SELECT e, p, c FROM '
. __NAMESPACE__ . '\\DDC2931User e LEFT JOIN e.parent p LEFT JOIN e.child c WHERE e = :id'
)
->setParameter('id', $second)
->setHint(Query::HINT_REFRESH, true)
->getResult();
$this->assertCount(1, $refreshedSecond);
$this->assertSame(1, $first->value);
$this->assertSame(2, $second->value);
$this->assertSame(3, $third->value);
}
}
/** @Entity */
class DDC2931User
{
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
public $id;
/** @OneToOne(targetEntity="DDC2931User", inversedBy="child") */
public $parent;
/** @OneToOne(targetEntity="DDC2931User", mappedBy="parent") */
public $child;
/** @Column(type="integer") */
public $value = 0;
/**
* Return Rank recursively
* My rank is 1 + rank of my parent
* @return integer
*/
public function getRank()
{
return 1 + ($this->parent ? $this->parent->getRank() : 0);
}
public function __wakeup()
{
}
}

View File

@@ -0,0 +1,199 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\Type;
/**
* @group DDC-2984
*/
class DDC2984Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
if ( ! Type::hasType('ddc2984_domain_user_id')) {
Type::addType(
'ddc2984_domain_user_id',
__NAMESPACE__ . '\DDC2984UserIdCustomDbalType'
);
}
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2984User'),
));
} catch (\Exception $e) {
// no action needed - schema seems to be already in place
}
}
public function testIssue()
{
$user = new DDC2984User(new DDC2984DomainUserId('unique_id_within_a_vo'));
$user->applyName('Alex');
$this->_em->persist($user);
$this->_em->flush($user);
$repository = $this->_em->getRepository(__NAMESPACE__ . "\DDC2984User");
$sameUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
//Until know, everything works as expected
$this->assertTrue($user->sameIdentityAs($sameUser));
$this->_em->clear();
//After clearing the identity map, the UnitOfWork produces the warning described in DDC-2984
$equalUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
$this->assertNotSame($user, $equalUser);
$this->assertTrue($user->sameIdentityAs($equalUser));
}
}
/** @Entity @Table(name="users") */
class DDC2984User
{
/**
* @Id @Column(type="ddc2984_domain_user_id")
* @GeneratedValue(strategy="NONE")
*
* @var DDC2984DomainUserId
*/
private $userId;
/** @Column(type="string", length=50) */
private $name;
public function __construct(DDC2984DomainUserId $aUserId)
{
$this->userId = $aUserId;
}
/**
* @return DDC2984DomainUserId
*/
public function userId()
{
return $this->userId;
}
/**
* @return string
*/
public function name()
{
return $this->name;
}
/**
* @param string $name
*/
public function applyName($name)
{
$this->name = $name;
}
/**
* @param DDC2984User $other
* @return bool
*/
public function sameIdentityAs(DDC2984User $other)
{
return $this->userId()->sameValueAs($other->userId());
}
}
/**
* DDC2984DomainUserId ValueObject
*
* @author Alexander Miertsch <kontakt@codeliner.ws>
*/
class DDC2984DomainUserId
{
/**
* @var string
*/
private $userIdString;
/**
* @param string $aUserIdString
*/
public function __construct($aUserIdString)
{
$this->userIdString = $aUserIdString;
}
/**
* @return string
*/
public function toString()
{
return $this->userIdString;
}
/**
* @return string
*/
public function __toString()
{
return $this->toString();
}
/**
* @param DDC2984DomainUserId $other
* @return bool
*/
public function sameValueAs(DDC2984DomainUserId $other)
{
return $this->toString() === $other->toString();
}
}
/**
* Class DDC2984UserIdCustomDbalType
*
* @author Alexander Miertsch <kontakt@codeliner.ws>
*/
class DDC2984UserIdCustomDbalType extends StringType
{
public function getName()
{
return 'ddc2984_domain_user_id';
}
/**
* {@inheritDoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return ! empty($value)
? new DDC2984DomainUserId($value)
: null;
}
/**
* {@inheritDoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (empty($value)) {
return null;
}
if (is_string($value)) {
return $value;
}
if ( ! $value instanceof DDC2984DomainUserId) {
throw ConversionException::conversionFailed($value, $this->getName());
}
return $value->toString();
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* @group DDC-2996
*/
class DDC2996Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function testIssue()
{
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2996User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2996UserPreference'),
));
$pref = new DDC2996UserPreference();
$pref->user = new DDC2996User();
$pref->value = "foo";
$this->_em->persist($pref);
$this->_em->persist($pref->user);
$this->_em->flush();
$pref->value = "bar";
$this->_em->flush();
$this->assertEquals(1, $pref->user->counter);
$this->_em->clear();
$pref = $this->_em->find(__NAMESPACE__ . '\\DDC2996UserPreference', $pref->id);
$this->assertEquals(1, $pref->user->counter);
}
}
/**
* @Entity
*/
class DDC2996User
{
/**
* @Id @GeneratedValue @Column(type="integer")
*/
public $id;
/**
* @Column(type="integer")
*/
public $counter = 0;
}
/**
* @Entity @HasLifecycleCallbacks
*/
class DDC2996UserPreference
{
/**
* @Id @GeneratedValue @Column(type="integer")
*/
public $id;
/**
* @Column(type="string")
*/
public $value;
/**
* @ManyToOne(targetEntity="DDC2996User")
*/
public $user;
/**
* @PreFlush
*/
public function preFlush($event)
{
$em = $event->getEntityManager();
$uow = $em->getUnitOfWork();
if ($uow->getOriginalEntityData($this->user)) {
$this->user->counter++;
$uow->recomputeSingleEntityChangeSet(
$em->getClassMetadata(get_class($this->user)),
$this->user
);
}
}
}

View File

@@ -0,0 +1,137 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* @group DDC-3033
*/
class DDC3033Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function testIssue()
{
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC3033User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC3033Product'),
));
$user = new DDC3033User();
$user->name = "Test User";
$this->_em->persist($user);
$user2 = new DDC3033User();
$user2->name = "Test User 2";
$this->_em->persist($user2);
$product = new DDC3033Product();
$product->title = "Test product";
$product->buyers[] = $user;
$this->_em->persist($product);
$this->_em->flush();
$product->title = "Test Change title";
$product->buyers[] = $user2;
$this->_em->persist($product);
$this->_em->flush();
$expect = array(
'title' => array(
0 => 'Test product',
1 => 'Test Change title',
),
);
$this->assertEquals($expect, $product->changeSet);
}
}
/**
* @Table
* @Entity @HasLifecycleCallbacks
*/
class DDC3033Product
{
public $changeSet = array();
/**
* @var integer $id
*
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* @var string $title
*
* @Column(name="title", type="string", length=255)
*/
public $title;
/**
* @ManyToMany(targetEntity="DDC3033User")
* @JoinTable(
* name="user_purchases_3033",
* joinColumns={@JoinColumn(name="product_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="user_id", referencedColumnName="id")}
* )
*/
public $buyers;
/**
* Default constructor
*/
public function __construct()
{
$this->buyers = new ArrayCollection();
}
/**
* @PreUpdate
*/
public function preUpdate(LifecycleEventArgs $eventArgs)
{
}
/**
* @PostUpdate
*/
public function postUpdate(LifecycleEventArgs $eventArgs)
{
$em = $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();
$entity = $eventArgs->getEntity();
$classMetadata = $em->getClassMetadata(get_class($entity));
$uow->computeChangeSet($classMetadata, $entity);
$this->changeSet = $uow->getEntityChangeSet($entity);
}
}
/**
* @Table
* @Entity @HasLifecycleCallbacks
*/
class DDC3033User
{
/**
* @var integer
*
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* @var string
*
* @Column(name="title", type="string", length=255)
*/
public $name;
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* FlushEventTest
*
* @author robo
*/
class DDC3160Test extends OrmFunctionalTestCase
{
protected function setUp() {
$this->useModelSet('cms');
parent::setUp();
}
/**
* @group DDC-3160
*/
public function testNoUpdateOnInsert()
{
$listener = new DDC3160OnFlushListener();
$this->_em->getEventManager()->addEventListener(Events::onFlush, $listener);
$user = new CmsUser;
$user->username = 'romanb';
$user->name = 'Roman';
$user->status = 'Dev';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->refresh($user);
$this->assertEquals('romanc', $user->username);
$this->assertEquals(1, $listener->inserts);
$this->assertEquals(0, $listener->updates);
}
}
class DDC3160OnFlushListener
{
public $inserts = 0;
public $updates = 0;
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityInsertions() as $entity) {
$this->inserts++;
if ($entity instanceof CmsUser) {
$entity->username = 'romanc';
$cm = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($cm, $entity);
}
}
foreach ($uow->getScheduledEntityUpdates() as $entity) {
$this->updates++;
}
}
}

View File

@@ -78,7 +78,7 @@ class DDC742Test extends \Doctrine\Tests\OrmFunctionalTestCase
/**
* @Entity
* @Table(name="users")
* @Table(name="ddc742_users")
*/
class DDC742User
{
@@ -111,7 +111,7 @@ class DDC742User
/**
* @Entity
* @Table(name="comments")
* @Table(name="ddc742_comments")
*/
class DDC742Comment
{

View File

@@ -1928,4 +1928,34 @@ class ObjectHydratorTest extends HydrationTestCase
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$hydrator->hydrateAll($stmt, $rsm);
}
/**
* @group DDC-3076
*
* @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
* @expectedExceptionMessage The discriminator value "subworker" is invalid. It must be one of "person", "manager", "employee".
*/
public function testInvalidDiscriminatorValueException()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyPerson', 'p');
$rsm->addFieldResult('p', 'p__id', 'id');
$rsm->addFieldResult('p', 'p__name', 'name');
$rsm->addMetaResult('p', 'discr', 'discr');
$rsm->setDiscriminatorColumn('p', 'discr');
$resultSet = array(
array(
'p__id' => '1',
'p__name' => 'Fabio B. Silva',
'discr' => 'subworker'
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$hydrator->hydrateAll($stmt, $rsm);
}
}

View File

@@ -58,4 +58,34 @@ class SimpleObjectHydratorTest extends HydrationTestCase
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals($result[0], $expectedEntity);
}
/**
* @group DDC-3076
*
* @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
* @expectedExceptionMessage The discriminator value "subworker" is invalid. It must be one of "person", "manager", "employee".
*/
public function testInvalidDiscriminatorValueException()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyPerson', 'p');
$rsm->addFieldResult('p', 'p__id', 'id');
$rsm->addFieldResult('p', 'p__name', 'name');
$rsm->addMetaResult('p', 'discr', 'discr');
$rsm->setDiscriminatorColumn('p', 'discr');
$resultSet = array(
array(
'p__id' => '1',
'p__name' => 'Fabio B. Silva',
'discr' => 'subworker'
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator($this->_em);
$hydrator->hydrateAll($stmt, $rsm);
}
}

View File

@@ -187,12 +187,32 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($class->fieldMappings['name']['nullable']);
$this->assertTrue($class->fieldMappings['name']['unique']);
return $class;
}
/**
* @depends testEntityTableNameAndInheritance
* @param ClassMetadata $class
*/
public function testFieldOptions($class)
{
$expected = array('foo' => 'bar', 'baz' => array('key' => 'val'));
$this->assertEquals($expected, $class->fieldMappings['name']['options']);
return $class;
}
/**
* @depends testEntityTableNameAndInheritance
* @param ClassMetadata $class
*/
public function testIdFieldOptions($class)
{
$this->assertEquals(array('foo' => 'bar'), $class->fieldMappings['id']['options']);
return $class;
}
/**
* @depends testFieldMappings
* @param ClassMetadata $class
@@ -890,7 +910,7 @@ class User
{
/**
* @Id
* @Column(type="integer")
* @Column(type="integer", options={"foo": "bar"})
* @generatedValue(strategy="AUTO")
* @SequenceGenerator(sequenceName="tablename_seq", initialValue=1, allocationSize=100)
**/
@@ -971,6 +991,7 @@ class User
'fieldName' => 'id',
'type' => 'integer',
'columnName' => 'id',
'options' => array('foo' => 'bar'),
));
$metadata->mapField(array(
'fieldName' => 'name',

View File

@@ -1066,6 +1066,75 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(array('customtypeparent_source' => 'id'), $cm->associationMappings['friendsWithMe']['relationToSourceKeyColumns']);
$this->assertEquals(array('customtypeparent_target' => 'id'), $cm->associationMappings['friendsWithMe']['relationToTargetKeyColumns']);
}
/**
* @group DDC-2608
*/
public function testSetSequenceGeneratorThrowsExceptionWhenSequenceNameIsMissing()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
$cm->setSequenceGeneratorDefinition(array());
}
/**
* @group DDC-2662
*/
public function testQuotedSequenceName()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->setSequenceGeneratorDefinition(array('sequenceName' => '`foo`'));
$this->assertEquals(array('sequenceName' => 'foo', 'quoted' => true), $cm->sequenceGeneratorDefinition);
}
/**
* @group DDC-2700
*/
public function testIsIdentifierMappedSuperClass()
{
$class = new ClassMetadata(__NAMESPACE__ . '\\DDC2700MappedSuperClass');
$this->assertFalse($class->isIdentifier('foo'));
}
/**
* @group DDC-3120
*/
public function testCanInstantiateInternalPhpClassSubclass()
{
$classMetadata = new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity');
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance());
}
/**
* @group DDC-3120
*/
public function testCanInstantiateInternalPhpClassSubclassFromUnserializedMetadata()
{
/* @var $classMetadata ClassMetadata */
$classMetadata = unserialize(serialize(new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity')));
$classMetadata->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance());
}
}
/**
* @MappedSuperclass
*/
class DDC2700MappedSuperClass
{
/** @Column */
private $foo;
}
class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
@@ -1092,4 +1161,8 @@ class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
{
return strtolower($this->classToTableName($className)) . '_' . $propertyName;
}
}
}
class MyArrayObjectEntity extends \ArrayObject
{
}

View File

@@ -19,6 +19,7 @@ $metadata->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'columnName' => 'id',
'options' => array('foo' => 'bar'),
));
$metadata->mapField(array(
'fieldName' => 'name',

View File

@@ -35,6 +35,9 @@
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
<sequence-generator sequence-name="tablename_seq" allocation-size="100" initial-value="1" />
<options>
<option name="foo">bar</option>
</options>
</id>
<field name="name" column="name" type="string" length="50" nullable="true" unique="true">

View File

@@ -16,6 +16,8 @@ Doctrine\Tests\ORM\Mapping\User:
sequenceName: tablename_seq
allocationSize: 100
initialValue: 1
options:
foo: bar
fields:
name:
type: string

View File

@@ -6,16 +6,21 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Tests\Mocks\ConnectionMock;
use Doctrine\Tests\Mocks\EntityManagerMock;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
require_once __DIR__ . '/../TestInit.php';
use Doctrine\Tests\Models\ECommerce\ECommerceCart;
use Doctrine\Tests\OrmTestCase;
/**
* Tests the lazy-loading capabilities of the PersistentCollection.
* Tests the lazy-loading capabilities of the PersistentCollection and the initialization of collections.
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @author Austin Morris <austin.morris@gmail.com>
*/
class PersistentCollectionTest extends \Doctrine\Tests\OrmTestCase
class PersistentCollectionTest extends OrmTestCase
{
/**
* @var PersistentCollection
*/
protected $collection;
private $_connectionMock;
private $_emMock;
@@ -27,6 +32,17 @@ class PersistentCollectionTest extends \Doctrine\Tests\OrmTestCase
$this->_emMock = EntityManagerMock::create($this->_connectionMock);
}
/**
* Set up the PersistentCollection used for collection initialization tests.
*/
public function setUpPersistentCollection()
{
$classMetaData = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$this->collection = new PersistentCollection($this->_emMock, $classMetaData, new ArrayCollection);
$this->collection->setInitialized(false);
$this->collection->setOwner(new ECommerceCart(), $classMetaData->getAssociationMapping('products'));
}
public function testCanBePutInLazyLoadingMode()
{
$class = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
@@ -34,4 +50,34 @@ class PersistentCollectionTest extends \Doctrine\Tests\OrmTestCase
$collection->setInitialized(false);
$this->assertFalse($collection->isInitialized());
}
/**
* Test that PersistentCollection::current() initializes the collection.
*/
public function testCurrentInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->current();
$this->assertTrue($this->collection->isInitialized());
}
/**
* Test that PersistentCollection::key() initializes the collection.
*/
public function testKeyInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->key();
$this->assertTrue($this->collection->isInitialized());
}
/**
* Test that PersistentCollection::next() initializes the collection.
*/
public function testNextInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->next();
$this->assertTrue($this->collection->isInitialized());
}
}

View File

@@ -592,12 +592,20 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
}
/**
* @gorup DDC-1858
* @group DDC-1858
*/
public function testHavingSupportIsNullExpression()
{
$this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u HAVING u.username IS NULL");
}
/**
* @group DDC-3018
*/
public function testNewLiteralExpression()
{
$this->assertValidDQL("SELECT new " . __NAMESPACE__ . "\\DummyStruct(u.id, 'foo', 1, true) FROM Doctrine\Tests\Models\CMS\CmsUser u");
}
}
/** @Entity */
@@ -617,3 +625,10 @@ class DQLKeywordsModelGroup
/** @Column */
private $from;
}
class DummyStruct
{
public function __construct($id, $arg1, $arg2, $arg3)
{
}
}

View File

@@ -47,7 +47,7 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
$this->visitor = new QueryExpressionVisitor();
$this->visitor = new QueryExpressionVisitor('o');
}
/**
@@ -71,22 +71,22 @@ class QueryExpressionVisitorTest extends \PHPUnit_Framework_TestCase
$qb = new QueryBuilder();
return array(
array($cb->eq('field', 'value'), $qb->eq('field', ':field'), new Parameter('field', 'value')),
array($cb->neq('field', 'value'), $qb->neq('field', ':field'), new Parameter('field', 'value')),
array($cb->eq('field', null), $qb->isNull('field')),
array($cb->neq('field', null), $qb->isNotNull('field')),
array($cb->isNull('field'), $qb->isNull('field')),
array($cb->eq('field', 'value'), $qb->eq('o.field', ':field'), new Parameter('field', 'value')),
array($cb->neq('field', 'value'), $qb->neq('o.field', ':field'), new Parameter('field', 'value')),
array($cb->eq('field', null), $qb->isNull('o.field')),
array($cb->neq('field', null), $qb->isNotNull('o.field')),
array($cb->isNull('field'), $qb->isNull('o.field')),
array($cb->gt('field', 'value'), $qb->gt('field', ':field'), new Parameter('field', 'value')),
array($cb->gte('field', 'value'), $qb->gte('field', ':field'), new Parameter('field', 'value')),
array($cb->lt('field', 'value'), $qb->lt('field', ':field'), new Parameter('field', 'value')),
array($cb->lte('field', 'value'), $qb->lte('field', ':field'), new Parameter('field', 'value')),
array($cb->gt('field', 'value'), $qb->gt('o.field', ':field'), new Parameter('field', 'value')),
array($cb->gte('field', 'value'), $qb->gte('o.field', ':field'), new Parameter('field', 'value')),
array($cb->lt('field', 'value'), $qb->lt('o.field', ':field'), new Parameter('field', 'value')),
array($cb->lte('field', 'value'), $qb->lte('o.field', ':field'), new Parameter('field', 'value')),
array($cb->in('field', array('value')), $qb->in('field', ':field'), new Parameter('field', array('value'))),
array($cb->notIn('field', array('value')), $qb->notIn('field', ':field'), new Parameter('field', array('value'))),
array($cb->in('field', array('value')), $qb->in('o.field', ':field'), new Parameter('field', array('value'))),
array($cb->notIn('field', array('value')), $qb->notIn('o.field', ':field'), new Parameter('field', array('value'))),
// Test parameter conversion
array($cb->eq('object.field', 'value'), $qb->eq('object.field', ':object_field'), new Parameter('object_field', 'value')),
array($cb->eq('object.field', 'value'), $qb->eq('o.object.field', ':object_field'), new Parameter('object_field', 'value')),
);
}

View File

@@ -105,6 +105,8 @@ class QueryTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('bar', $q->getHint('foo'));
$this->assertEquals('baz', $q->getHint('bar'));
$this->assertEquals(array('foo' => 'bar', 'bar' => 'baz'), $q->getHints());
$this->assertTrue($q->hasHint('foo'));
$this->assertFalse($q->hasHint('barFooBaz'));
}
/**

View File

@@ -155,12 +155,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_managers c2_ INNER JOIN company_employees c3_ ON c2_.id = c3_.id INNER JOIN company_persons c4_ ON c2_.id = c4_.id AND (c0_.id = c4_.id)'
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id AND (c0_.id = c3_.id)'
);
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ INNER JOIN company_employees c3_ ON c2_.id = c3_.id INNER JOIN company_persons c4_ ON c2_.id = c4_.id ON (c0_.id = c4_.id)'
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id ON (c0_.id = c3_.id)'
);
}
@@ -394,6 +394,17 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
/**
* @group DDC-2668
*/
public function testSupportsTrimLeadingZeroString()
{
$this->assertSqlGeneration(
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(TRAILING '0' FROM u.name) != ''",
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE TRIM(TRAILING '0' FROM c0_.name) <> ''"
);
}
// Ticket 894
public function testSupportsBetweenClauseWithPositionalParameters()
{
@@ -1979,15 +1990,15 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id || c0_.name || c0_.status AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?"
);
$connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\SQLServerPlatform());
/*$connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\SQLServerPlatform());
$this->assertSqlGeneration(
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
"SELECT c0_.id AS id0 FROM cms_users c0_ WITH (NOLOCK) WHERE (c0_.name + c0_.status + 's') = ?"
"SELECT c0_.id AS id0 FROM cms_users c0_ WHERE (c0_.name + c0_.status + 's') = ?"
);
$this->assertSqlGeneration(
"SELECT CONCAT(u.id, u.name, u.status) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1",
"SELECT (c0_.id + c0_.name + c0_.status) AS sclr0 FROM cms_users c0_ WITH (NOLOCK) WHERE c0_.id = ?"
);
"SELECT (c0_.id + c0_.name + c0_.status) AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?"
);*/
$connMock->setDatabasePlatform($orgPlatform);
}
@@ -2040,6 +2051,97 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
/**
* @group DDC-2506
*/
public function testClassTableInheritanceJoinWithConditionAppliesToBaseTable()
{
$this->assertSqlGeneration(
'SELECT e.id FROM Doctrine\Tests\Models\Company\CompanyOrganization o JOIN o.events e WITH e.id = ?1',
'SELECT c0_.id AS id0 FROM company_organizations c1_ INNER JOIN company_events c0_ ON c1_.id = c0_.org_id AND (c0_.id = ?) LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceLeftJoinWithCondition()
{
// Regression test for the bug
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceLeftJoinWithConditionAndWhere()
{
// Ensure other WHERE predicates are passed through to the main WHERE clause
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id WHERE e.salary > 1000',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.salary > 1000"
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceInnerJoinWithCondition()
{
// Test inner joins too
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e INNER JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id INNER JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceLeftJoinNonAssociationWithConditionAndWhere()
{
// Test that the discriminator IN() predicate is still added into
// the where clause when not joining onto that table
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ LEFT JOIN company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceJoinCreatesOnCondition()
{
// Test that the discriminator IN() predicate is still added
// into the where clause when not joining onto a single table inheritance entity
// via a join association
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c JOIN c.salesPerson s WHERE c.completed = true',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
/**
* @group DDC-2235
*/
public function testSingleTableInheritanceCreatesOnConditionAndWhere()
{
// Test that when joining onto an entity using single table inheritance via
// a join association that the discriminator IN() predicate is placed
// into the ON clause of the join
$this->assertSqlGeneration(
'SELECT e, COUNT(c) FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN e.contracts c WHERE e.department = :department',
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, COUNT(c2_.id) AS sclr5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_contract_employees c3_ ON c1_.id = c3_.employee_id INNER JOIN company_contracts c2_ ON c2_.id = c3_.contract_id AND c2_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.department = ?",
array(),
array('department' => 'foobar')
);
}
/**
* @group DDC-1858
*/

View File

@@ -402,30 +402,39 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
public function testAddCriteriaWhere()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$criteria = new Criteria();
$criteria->where($criteria->expr()->eq('field', 'value'));
$qb->addCriteria($criteria);
$this->assertEquals('field = :field', (string) $qb->getDQLPart('where'));
$this->assertEquals('u.field = :field', (string) $qb->getDQLPart('where'));
$this->assertNotNull($qb->getParameter('field'));
}
public function testAddCriteriaOrder()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$criteria = new Criteria();
$criteria->orderBy(array('field' => Criteria::DESC));
$qb->addCriteria($criteria);
$this->assertCount(1, $orderBy = $qb->getDQLPart('orderBy'));
$this->assertEquals('field DESC', (string) $orderBy[0]);
$this->assertEquals('u.field DESC', (string) $orderBy[0]);
}
public function testAddCriteriaLimit()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$criteria = new Criteria();
$criteria->setFirstResult(2);
$criteria->setMaxResults(10);
@@ -439,7 +448,11 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
public function testAddCriteriaUndefinedLimit()
{
$qb = $this->_em->createQueryBuilder();
$qb->setFirstResult(2)->setMaxResults(10);
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->setFirstResult(2)
->setMaxResults(10);
$criteria = new Criteria();
$qb->addCriteria($criteria);

View File

@@ -516,9 +516,9 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
)),
array(array(
'fieldName' => 'decimal',
'phpType' => 'float',
'phpType' => 'string',
'dbType' => 'decimal',
'value' => 33.33
'value' => '12.34'
),
));
}

View File

@@ -209,6 +209,27 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
return $class;
}
/**
* @depends testExportDirectoryAndFilesAreCreated
*/
public function testFieldsAreProperlySerialized()
{
$type = $this->_getType();
if ($type == 'xml') {
$xml = simplexml_load_file(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.xml');
$xml->registerXPathNamespace("d", "http://doctrine-project.org/schemas/orm/doctrine-mapping");
$nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:field[@name='name' and @type='string' and @nullable='true']");
$this->assertEquals(1, count($nodes));
$nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:field[@name='name' and @type='string' and @unique='true']");
$this->assertEquals(1, count($nodes));
}
else {
$this->markTestSkipped('Test available only for '.$type.' driver');
}
}
/**
* @depends testFieldsAreExported
* @param ClassMetadataInfo $class

View File

@@ -155,7 +155,13 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
'Doctrine\Tests\Models\CompositeKeyInheritance\JoinedChildClass',
'Doctrine\Tests\Models\CompositeKeyInheritance\SingleRootClass',
'Doctrine\Tests\Models\CompositeKeyInheritance\SingleChildClass',
)
),
'taxi' => array(
'Doctrine\Tests\Models\Taxi\PaidRide',
'Doctrine\Tests\Models\Taxi\Ride',
'Doctrine\Tests\Models\Taxi\Car',
'Doctrine\Tests\Models\Taxi\Driver',
),
);
/**
@@ -284,6 +290,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
$conn->executeUpdate('DELETE FROM SingleRootClass');
}
if (isset($this->_usedModelSets['taxi'])) {
$conn->executeUpdate('DELETE FROM taxi_paid_ride');
$conn->executeUpdate('DELETE FROM taxi_ride');
$conn->executeUpdate('DELETE FROM taxi_car');
$conn->executeUpdate('DELETE FROM taxi_driver');
}
$this->_em->clear();
}
@@ -467,6 +479,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
throw $e;
}
public function assertSQLEquals($expectedSql, $actualSql)
{
return $this->assertEquals(strtolower($expectedSql), strtolower($actualSql), "Lowercase comparison of SQL statements failed.");
}
/**
* Using the SQL Logger Stack this method retrieves the current query count executed in this test.
*