Compare commits

...

111 Commits

Author SHA1 Message Date
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
64 changed files with 2058 additions and 313 deletions

View File

@@ -16,7 +16,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

@@ -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

@@ -1031,9 +1031,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 +2488,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 +2799,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;
}

View File

@@ -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

@@ -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'];

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);
@@ -1736,6 +1736,8 @@ class UnitOfWork implements PropertyChangedListener
$associatedId = $this->getEntityIdentifier($idValue);
$flatId[$idField] = $associatedId[$targetClassMetadata->identifier[0]];
} else {
$flatId[$idField] = $idValue;
}
}
@@ -2231,6 +2233,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 +2247,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);
}
}
/**
@@ -2490,14 +2498,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 +3214,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.2';
/**
* Compares a Doctrine version with the current one.

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

@@ -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

@@ -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,119 @@
<?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()
{
echo 'foo';
}
}

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,50 @@ 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'));
}
}
/**
* @MappedSuperclass
*/
class DDC2700MappedSuperClass
{
/** @Column */
private $foo;
}
class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
@@ -1092,4 +1136,4 @@ class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
{
return strtolower($this->classToTableName($className)) . '_' . $propertyName;
}
}
}

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

@@ -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()
{
@@ -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

@@ -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.
*