mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
202 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc4ff3cab | ||
|
|
39f2f0eb91 | ||
|
|
a5a7c879fc | ||
|
|
5670912d0d | ||
|
|
fae0f6a29a | ||
|
|
f45cf2629e | ||
|
|
4d846c1992 | ||
|
|
37516d7548 | ||
|
|
24c4ec91e5 | ||
|
|
f31f088f0b | ||
|
|
51da937bbc | ||
|
|
801e7f0ef7 | ||
|
|
f0e6408005 | ||
|
|
c398f8c2c2 | ||
|
|
060bbb1366 | ||
|
|
34fad084a7 | ||
|
|
bdc54d481c | ||
|
|
60462919f2 | ||
|
|
5a8a017a66 | ||
|
|
c701e8b9a6 | ||
|
|
df99353f19 | ||
|
|
8b5dae30a5 | ||
|
|
78770f9da8 | ||
|
|
2f57c4fef9 | ||
|
|
684ae859ce | ||
|
|
5f9dc2e5bc | ||
|
|
2dbe28a150 | ||
|
|
ea3856673d | ||
|
|
7c02af8896 | ||
|
|
61c18ce046 | ||
|
|
7f5620a41c | ||
|
|
ae198d5e45 | ||
|
|
705c33bc35 | ||
|
|
3cef0fdbfa | ||
|
|
ccbe849a72 | ||
|
|
2b8e03ff12 | ||
|
|
c4e93cf68c | ||
|
|
cfdef3bf19 | ||
|
|
8bb1d5448b | ||
|
|
bebacf79d8 | ||
|
|
d46fa4adeb | ||
|
|
64061bafaf | ||
|
|
a69584a841 | ||
|
|
8fc1c34b29 | ||
|
|
0d683c1897 | ||
|
|
60b75fefed | ||
|
|
0a7e0617cc | ||
|
|
072e1eee7b | ||
|
|
c0d3cdbdfb | ||
|
|
a50ae2c898 | ||
|
|
dbbe7a4be5 | ||
|
|
406e177062 | ||
|
|
fc19c3b53d | ||
|
|
5c5abb6771 | ||
|
|
42226dadd1 | ||
|
|
84f8ef5ca4 | ||
|
|
8a13376d42 | ||
|
|
8b5632cb65 | ||
|
|
859465b691 | ||
|
|
530c01b5e3 | ||
|
|
63c5758070 | ||
|
|
0fb236f451 | ||
|
|
2a9a53ae9d | ||
|
|
0081319712 | ||
|
|
78ceda7ecf | ||
|
|
1f4810e370 | ||
|
|
376a3ac3b6 | ||
|
|
ab87dd6325 | ||
|
|
2ae245db30 | ||
|
|
9d36e855c0 | ||
|
|
f7c87cddd8 | ||
|
|
1566b8a057 | ||
|
|
333fa1090a | ||
|
|
0262b083bb | ||
|
|
60c9c27c08 | ||
|
|
8b75e3563a | ||
|
|
cbf16f1cf8 | ||
|
|
b84c828ea1 | ||
|
|
55b7e4cff2 | ||
|
|
e38af55100 | ||
|
|
7338c2d1f8 | ||
|
|
0ff3cdf150 | ||
|
|
24c5c54c1e | ||
|
|
6bb367f488 | ||
|
|
213cc5c695 | ||
|
|
a949e87ca8 | ||
|
|
f18d0e093b | ||
|
|
0e139055f9 | ||
|
|
b9c6659b70 | ||
|
|
5c06121d94 | ||
|
|
5bfa56aee0 | ||
|
|
0363a5548d | ||
|
|
3764e49e6c | ||
|
|
6ee20204a5 | ||
|
|
d9b0c87ded | ||
|
|
8594e5c4da | ||
|
|
5f821f3b98 | ||
|
|
b566525099 | ||
|
|
215c4a03e1 | ||
|
|
b3ccd6466b | ||
|
|
b596bbb29f | ||
|
|
c204e6c6a1 | ||
|
|
0bc94589e1 | ||
|
|
f37856829f | ||
|
|
157c793810 | ||
|
|
72d838a804 | ||
|
|
58f8dc5d4c | ||
|
|
7d3ecd9481 | ||
|
|
1bb55703a7 | ||
|
|
56cbcec13d | ||
|
|
837c19bfc0 | ||
|
|
7b8f09ee4a | ||
|
|
488a4dc78a | ||
|
|
1364b6acc6 | ||
|
|
3dbe181762 | ||
|
|
a3acaab65c | ||
|
|
f183d25a33 | ||
|
|
7c8350094e | ||
|
|
c613410ba6 | ||
|
|
6bb7581dd7 | ||
|
|
ab71dab7d1 | ||
|
|
2c114756bd | ||
|
|
45496f040d | ||
|
|
b40866c624 | ||
|
|
a89cc7abea | ||
|
|
5ac111e5f8 | ||
|
|
c5f66e6e7f | ||
|
|
b59f495875 | ||
|
|
3829b9c28b | ||
|
|
65bcdbf4c7 | ||
|
|
95d000e51b | ||
|
|
3657df3b01 | ||
|
|
1661ffae9a | ||
|
|
b424a5cf14 | ||
|
|
2767a4eec4 | ||
|
|
9486867279 | ||
|
|
6f2bb08972 | ||
|
|
da2d3b406e | ||
|
|
c4b7d3fbea | ||
|
|
84373d05a4 | ||
|
|
e82e7147fa | ||
|
|
e23ed2250d | ||
|
|
192bb6fd21 | ||
|
|
0f3679f034 | ||
|
|
1d2cd82706 | ||
|
|
b983d86612 | ||
|
|
b11f01643c | ||
|
|
b58fb8f5d4 | ||
|
|
925a22b71d | ||
|
|
0f0d8abd67 | ||
|
|
470c15ce05 | ||
|
|
3cc5fc0252 | ||
|
|
fd0657089a | ||
|
|
de3b237292 | ||
|
|
1221cc3a2a | ||
|
|
9efbc1fa71 | ||
|
|
57705e0d78 | ||
|
|
82bb6b78cd | ||
|
|
64c56b21aa | ||
|
|
b04e2e6364 | ||
|
|
a70f9b7f49 | ||
|
|
c88a7c1ffe | ||
|
|
c206728c96 | ||
|
|
e8d420c641 | ||
|
|
fdcab7eae8 | ||
|
|
45d7d5234f | ||
|
|
159ca79b81 | ||
|
|
2b148a27e0 | ||
|
|
0aef57f60c | ||
|
|
fef1e0286c | ||
|
|
4a38534150 | ||
|
|
1de22adb16 | ||
|
|
62b4160887 | ||
|
|
dbb7c4d2bf | ||
|
|
e8978ee365 | ||
|
|
c095b88804 | ||
|
|
efe4208ba6 | ||
|
|
453a56670d | ||
|
|
ec36e2c866 | ||
|
|
e250572cb4 | ||
|
|
758955e183 | ||
|
|
5b8d6a1486 | ||
|
|
3f1003fee9 | ||
|
|
7e241e89b8 | ||
|
|
67c1e1d2b1 | ||
|
|
261eacdbfc | ||
|
|
43df821691 | ||
|
|
11d09702da | ||
|
|
f9f14139cf | ||
|
|
39f4d46d36 | ||
|
|
1dae8d318f | ||
|
|
a361a7c1cb | ||
|
|
6a73608baf | ||
|
|
f9955152b2 | ||
|
|
5aad1df149 | ||
|
|
243832555b | ||
|
|
ae12fa6b5b | ||
|
|
edaf9b6813 | ||
|
|
b324a21abf | ||
|
|
ff34aaaa2c | ||
|
|
9767a814a6 | ||
|
|
e6007575e1 |
@@ -4,6 +4,7 @@ php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
|
||||
env:
|
||||
- DB=mysql
|
||||
@@ -16,7 +17,7 @@ before_script:
|
||||
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi"
|
||||
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi"
|
||||
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi"
|
||||
- composer install --prefer-source --dev
|
||||
- composer install --prefer-dist --dev
|
||||
|
||||
script: phpunit --configuration tests/travis/$DB.travis.xml
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
199
build.xml
@@ -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>
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ Doctrine ORM don't panic. You can get help from different sources:
|
||||
|
||||
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
|
||||
- The `Doctrine Mailing List <http://groups.google.com/group/doctrine-user>`_
|
||||
- Internet Relay Chat (IRC) in `#doctrine on Freenode <irc://irc.freenode.net/doctrine>`_
|
||||
- Internet Relay Chat (IRC) in #doctrine on Freenode
|
||||
- Report a bug on `JIRA <http://www.doctrine-project.org/jira>`_.
|
||||
- On `Twitter <https://twitter.com/search/%23doctrine2>`_ with ``#doctrine2``
|
||||
- On `StackOverflow <http://stackoverflow.com/questions/tagged/doctrine2>`_
|
||||
@@ -120,3 +120,4 @@ Cookbook
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
.. include:: toc.rst
|
||||
|
||||
@@ -106,7 +106,7 @@ Redis
|
||||
In order to use the Redis cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about what is Redis
|
||||
`from here <http://redis.io/>`_. Also check
|
||||
`here <https://github.com/nicolasff/phpredis/>`_ for how you can use
|
||||
`A PHP extension for Redis <https://github.com/nicolasff/phpredis/>`_ for how you can use
|
||||
and install Redis PHP extension.
|
||||
|
||||
Below is a simple example of how you could use the Redis cache
|
||||
|
||||
@@ -100,7 +100,7 @@ Doctrine ships with a number of command line tools that are very helpful
|
||||
during development. You can call this command from the Composer binary
|
||||
directory:
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: sh
|
||||
|
||||
$ php vendor/bin/doctrine
|
||||
|
||||
|
||||
@@ -207,10 +207,13 @@ listeners:
|
||||
|
||||
|
||||
- Lifecycle Callbacks are methods on the entity classes that are
|
||||
called when the event is triggered. They receives some kind of ``EventArgs``.
|
||||
called when the event is triggered. As of v2.4 they receive some kind
|
||||
of ``EventArgs`` instance.
|
||||
- Lifecycle Event Listeners and Subscribers are classes with specific callback
|
||||
methods that receives some kind of ``EventArgs`` instance which
|
||||
give access to the entity, EntityManager or other relevant data.
|
||||
methods that receives some kind of ``EventArgs`` instance.
|
||||
|
||||
The EventArgs instance received by the listener gives access to the entity,
|
||||
EntityManager and other relevant data.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -224,10 +227,11 @@ listeners:
|
||||
Lifecycle Callbacks
|
||||
-------------------
|
||||
|
||||
A lifecycle event is a regular event with the additional feature of
|
||||
providing a mechanism to register direct callbacks inside the
|
||||
corresponding entity classes that are executed when the lifecycle
|
||||
event occurs.
|
||||
Lifecycle Callbacks are defined on an entity class. They allow you to
|
||||
trigger callbacks whenever an instance of that entity class experiences
|
||||
a relevant lifecycle event. More than one callback can be defined for each
|
||||
lifecycle event. Lifecycle Callbacks are best used for simple operations
|
||||
specific to a particular entity class's lifecycle.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -277,8 +281,9 @@ event occurs.
|
||||
}
|
||||
}
|
||||
|
||||
Note that when using annotations you have to apply the
|
||||
@HasLifecycleCallbacks marker annotation on the entity class.
|
||||
Note that the methods set as lifecycle callbacks need to be public and,
|
||||
when using these annotations, you have to apply the
|
||||
``@HasLifecycleCallbacks`` marker annotation on the entity class.
|
||||
|
||||
If you want to register lifecycle callbacks from YAML or XML you
|
||||
can do it with the following.
|
||||
@@ -295,6 +300,10 @@ can do it with the following.
|
||||
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
|
||||
postPersist: [ doStuffOnPostPersist ]
|
||||
|
||||
In YAML the ``key`` of the lifecycleCallbacks entry is the event that you
|
||||
are triggering on and the value is the method (or methods) to call. The allowed
|
||||
event types are the ones listed in the previous Lifecycle Events section.
|
||||
|
||||
XML would look something like this:
|
||||
|
||||
.. code-block:: xml
|
||||
@@ -317,9 +326,14 @@ XML would look something like this:
|
||||
|
||||
</doctrine-mapping>
|
||||
|
||||
You just need to make sure a public ``doStuffOnPrePersist()`` and
|
||||
``doStuffOnPostPersist()`` method is defined on your ``User``
|
||||
model.
|
||||
In XML the ``type`` of the lifecycle-callback entry is the event that you
|
||||
are triggering on and the ``method`` is the method to call. The allowed event
|
||||
types are the ones listed in the previous Lifecycle Events section.
|
||||
|
||||
When using YAML or XML you need to remember to create public methods to match the
|
||||
callback names you defined. E.g. in these examples ``doStuffOnPrePersist()``,
|
||||
``doOtherStuffOnPrePersist()`` and ``doStuffOnPostPersist()`` methods need to be
|
||||
defined on your ``User`` model.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -375,8 +389,10 @@ Listening and subscribing to Lifecycle Events
|
||||
|
||||
Lifecycle event listeners are much more powerful than the simple
|
||||
lifecycle callbacks that are defined on the entity classes. They
|
||||
allow to implement re-usable behaviors between different entity
|
||||
classes, yet require much more detailed knowledge about the inner
|
||||
sit at a level above the entities and allow you to implement re-usable
|
||||
behaviors across different entity classes.
|
||||
|
||||
Note that they require much more detailed knowledge about the inner
|
||||
workings of the EntityManager and UnitOfWork. Please read the
|
||||
*Implementing Event Listeners* section carefully if you are trying
|
||||
to write your own listener.
|
||||
@@ -476,8 +492,8 @@ data and lost updates/persists/removes.
|
||||
|
||||
For the described events that are also lifecycle callback events
|
||||
the restrictions apply as well, with the additional restriction
|
||||
that you do not have access to the EntityManager or UnitOfWork APIs
|
||||
inside these events.
|
||||
that (prior to version 2.4) you do not have access to the
|
||||
EntityManager or UnitOfWork APIs inside these events.
|
||||
|
||||
prePersist
|
||||
~~~~~~~~~~
|
||||
@@ -501,11 +517,9 @@ The following restrictions apply to ``prePersist``:
|
||||
- If you are using a PrePersist Identity Generator such as
|
||||
sequences the ID value will *NOT* be available within any
|
||||
PrePersist events.
|
||||
- Doctrine will not recognize changes made to relations in a pre
|
||||
persist event called by "reachability" through a cascade persist
|
||||
unless you use the internal ``UnitOfWork`` API. We do not recommend
|
||||
such operations in the persistence by reachability context, so do
|
||||
this at your own risk and possibly supported by unit-tests.
|
||||
- Doctrine will not recognize changes made to relations in a prePersist
|
||||
event. This includes modifications to
|
||||
collections such as additions, removals or replacement.
|
||||
|
||||
preRemove
|
||||
~~~~~~~~~
|
||||
@@ -699,7 +713,8 @@ Restrictions for this event:
|
||||
recognized by the flush operation anymore.
|
||||
- Changes to fields of the passed entities are not recognized by
|
||||
the flush operation anymore, use the computed change-set passed to
|
||||
the event to modify primitive field values.
|
||||
the event to modify primitive field values, e.g. use
|
||||
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
|
||||
- Any calls to ``EntityManager#persist()`` or
|
||||
``EntityManager#remove()``, even in combination with the UnitOfWork
|
||||
API are strongly discouraged and don't work as expected outside the
|
||||
@@ -769,9 +784,10 @@ An ``Entity Listener`` could be any class, by default it should be a class with
|
||||
|
||||
- Different from :ref:`reference-events-implementing-listeners` an ``Entity Listener`` is invoked just to the specified entity
|
||||
- An entity listener method receives two arguments, the entity instance and the lifecycle event.
|
||||
- A callback method could be defined by naming convention or specifying a method mapping.
|
||||
- When the listener mapping is not given the parser will lookup for methods that match with the naming convention.
|
||||
- When the listener mapping is given the parser won't lookup for any naming convention.
|
||||
- The callback method can be defined by naming convention or specifying a method mapping.
|
||||
- When a listener mapping is not given the parser will use the naming convention to look for a matching method,
|
||||
e.g. it will look for a public ``preUpdate()`` method if you are listening to the ``preUpdate`` event.
|
||||
- When a listener mapping is given the parser will not look for any methods using the naming convention.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ See the documentation chapter on :doc:`inheritance mapping <inheritance-mapping>
|
||||
the details.
|
||||
|
||||
Why does Doctrine not create proxy objects for my inheritance hierarchy?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you set a many-to-one or one-to-one association target-entity to any parent class of
|
||||
an inheritance hierarchy Doctrine does not know what PHP class the foreign is actually of.
|
||||
|
||||
@@ -8,12 +8,14 @@ Tutorials
|
||||
:maxdepth: 1
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/in-ten-quick-steps
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination.rst
|
||||
|
||||
Reference Guide
|
||||
---------------
|
||||
@@ -22,9 +24,9 @@ Reference Guide
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
reference/introduction
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/installation
|
||||
reference/configuration.rst
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
@@ -51,9 +53,9 @@ Reference Guide
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination.rst
|
||||
reference/filters.rst
|
||||
reference/namingstrategy.rst
|
||||
reference/advanced-configuration.rst
|
||||
|
||||
|
||||
Cookbook
|
||||
@@ -63,6 +65,7 @@ Cookbook
|
||||
:maxdepth: 1
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
@@ -70,6 +73,7 @@ Cookbook
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/implementing-wakeup-or-clone
|
||||
cookbook/integrating-with-codeigniter
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -172,9 +165,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database connection object used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\DBAL\Connection
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
@@ -192,18 +183,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ExpressionBuilder used for object-oriented construction of query expressions.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <code>
|
||||
* $qb = $em->createQueryBuilder();
|
||||
* $expr = $em->getExpressionBuilder();
|
||||
* $qb->select('u')->from('User', 'u')
|
||||
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
|
||||
* </code>
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\Expr
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getExpressionBuilder()
|
||||
{
|
||||
@@ -215,9 +195,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a transaction on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function beginTransaction()
|
||||
{
|
||||
@@ -225,18 +203,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a function in a transaction.
|
||||
*
|
||||
* The function gets passed this EntityManager instance as an (optional) parameter.
|
||||
*
|
||||
* {@link flush} is invoked prior to transaction commit.
|
||||
*
|
||||
* If an exception occurs during execution of the function or flushing or transaction commit,
|
||||
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
|
||||
*
|
||||
* @param callable $func The function to execute transactionally.
|
||||
*
|
||||
* @return mixed The non-empty value returned from the closure or true instead.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function transactional($func)
|
||||
{
|
||||
@@ -262,9 +229,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits a transaction on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
@@ -272,9 +237,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a rollback on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
@@ -303,11 +266,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Query object.
|
||||
*
|
||||
* @param string $dql The DQL string.
|
||||
*
|
||||
* @return \Doctrine\ORM\Query
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQuery($dql = '')
|
||||
{
|
||||
@@ -321,11 +280,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query from a named query.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return \Doctrine\ORM\Query
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedQuery($name)
|
||||
{
|
||||
@@ -333,12 +288,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a native SQL query.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param ResultSetMapping $rsm The ResultSetMapping to use.
|
||||
*
|
||||
* @return NativeQuery
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNativeQuery($sql, ResultSetMapping $rsm)
|
||||
{
|
||||
@@ -351,11 +301,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NativeQuery from a named native query.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return \Doctrine\ORM\NativeQuery
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedNativeQuery($name)
|
||||
{
|
||||
@@ -365,9 +311,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a QueryBuilder instance
|
||||
*
|
||||
* @return QueryBuilder
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQueryBuilder()
|
||||
{
|
||||
@@ -487,15 +431,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
*
|
||||
* @return object The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReference($entityName, $id)
|
||||
{
|
||||
@@ -536,24 +472,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a partial reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* The returned reference may be a partial object if the entity is not yet loaded/managed.
|
||||
* If it is a partial object it will not initialize the rest of the entity state on access.
|
||||
* Thus you can only ever safely access the identifier of an entity obtained through
|
||||
* this method.
|
||||
*
|
||||
* The use-cases for partial references involve maintaining bidirectional associations
|
||||
* without loading one side of the association or to update an entity without loading it.
|
||||
* Note, however, that in the latter case the original (persistent) entity data will
|
||||
* never be visible to the application (especially not event listeners) as it will
|
||||
* never be loaded in the first place.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return object The (partial) entity reference.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPartialReference($entityName, $identifier)
|
||||
{
|
||||
@@ -592,11 +511,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the EntityManager. All entities that are currently managed
|
||||
* by this EntityManager become detached. The EntityManager may no longer
|
||||
* be used after it is closed.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -720,14 +635,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the given entity. Can create a shallow or a deep copy.
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @param boolean $deep FALSE for a shallow copy, TRUE for a deep copy.
|
||||
*
|
||||
* @return object The new entity.
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e:
|
||||
* Fatal error: Maximum function nesting level of '100' reached, aborting!
|
||||
@@ -738,16 +646,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire a lock on the given entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param int $lockMode
|
||||
* @param int|null $lockVersion
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws PessimisticLockException
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock($entity, $lockMode, $lockVersion = null)
|
||||
{
|
||||
@@ -781,9 +680,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EventManager used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\Common\EventManager
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getEventManager()
|
||||
{
|
||||
@@ -791,9 +688,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Configuration used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\Configuration
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
@@ -815,9 +710,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Entity manager is open or closed.
|
||||
*
|
||||
* @return bool
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isOpen()
|
||||
{
|
||||
@@ -825,9 +718,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
|
||||
*
|
||||
* @return \Doctrine\ORM\UnitOfWork
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getUnitOfWork()
|
||||
{
|
||||
@@ -835,32 +726,15 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hydrator for the given hydration mode.
|
||||
*
|
||||
* This method caches the hydrator instances which is used for all queries that don't
|
||||
* selectively iterate over the result.
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getHydrator($hydrationMode)
|
||||
{
|
||||
if ( ! isset($this->hydrators[$hydrationMode])) {
|
||||
$this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode);
|
||||
}
|
||||
|
||||
return $this->hydrators[$hydrationMode];
|
||||
return $this->newHydrator($hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance for the given hydration mode.
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
*
|
||||
* @throws ORMException
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function newHydrator($hydrationMode)
|
||||
{
|
||||
@@ -890,9 +764,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the proxy factory used by the EntityManager to create entity proxies.
|
||||
*
|
||||
* @return ProxyFactory
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getProxyFactory()
|
||||
{
|
||||
@@ -900,13 +772,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a lazy loading proxy or persistent collection.
|
||||
*
|
||||
* This method is a no-op for other objects
|
||||
*
|
||||
* @param object $obj
|
||||
*
|
||||
* @return void
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initializeObject($obj)
|
||||
{
|
||||
@@ -952,9 +818,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enabled filters.
|
||||
*
|
||||
* @return FilterCollection The active filter collection.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
@@ -966,9 +830,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the state of the filter collection is clean.
|
||||
*
|
||||
* @return boolean True, if the filter collection is clean.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isFiltersStateClean()
|
||||
{
|
||||
@@ -976,9 +838,7 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Entity Manager has filters.
|
||||
*
|
||||
* @return boolean True, if the EM has a filter collection.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasFilters()
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
|
||||
/**
|
||||
@@ -31,30 +30,258 @@ use Doctrine\ORM\Query\ResultSetMapping;
|
||||
*/
|
||||
interface EntityManagerInterface extends ObjectManager
|
||||
{
|
||||
/**
|
||||
* Gets the database connection object used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\DBAL\Connection
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
/**
|
||||
* Gets an ExpressionBuilder used for object-oriented construction of query expressions.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <code>
|
||||
* $qb = $em->createQueryBuilder();
|
||||
* $expr = $em->getExpressionBuilder();
|
||||
* $qb->select('u')->from('User', 'u')
|
||||
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
|
||||
* </code>
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\Expr
|
||||
*/
|
||||
public function getExpressionBuilder();
|
||||
|
||||
/**
|
||||
* Starts a transaction on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function beginTransaction();
|
||||
|
||||
/**
|
||||
* Executes a function in a transaction.
|
||||
*
|
||||
* The function gets passed this EntityManager instance as an (optional) parameter.
|
||||
*
|
||||
* {@link flush} is invoked prior to transaction commit.
|
||||
*
|
||||
* If an exception occurs during execution of the function or flushing or transaction commit,
|
||||
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
|
||||
*
|
||||
* @param callable $func The function to execute transactionally.
|
||||
*
|
||||
* @return mixed The non-empty value returned from the closure or true instead.
|
||||
*/
|
||||
public function transactional($func);
|
||||
|
||||
/**
|
||||
* Commits a transaction on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function commit();
|
||||
|
||||
/**
|
||||
* Performs a rollback on the underlying database connection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rollback();
|
||||
|
||||
/**
|
||||
* Creates a new Query object.
|
||||
*
|
||||
* @param string $dql The DQL string.
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function createQuery($dql = '');
|
||||
|
||||
/**
|
||||
* Creates a Query from a named query.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function createNamedQuery($name);
|
||||
|
||||
/**
|
||||
* Creates a native SQL query.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param ResultSetMapping $rsm The ResultSetMapping to use.
|
||||
*
|
||||
* @return NativeQuery
|
||||
*/
|
||||
public function createNativeQuery($sql, ResultSetMapping $rsm);
|
||||
|
||||
/**
|
||||
* Creates a NativeQuery from a named native query.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return NativeQuery
|
||||
*/
|
||||
public function createNamedNativeQuery($name);
|
||||
|
||||
/**
|
||||
* Create a QueryBuilder instance
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function createQueryBuilder();
|
||||
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
*
|
||||
* @return object The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
*/
|
||||
public function getReference($entityName, $id);
|
||||
|
||||
/**
|
||||
* Gets a partial reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* The returned reference may be a partial object if the entity is not yet loaded/managed.
|
||||
* If it is a partial object it will not initialize the rest of the entity state on access.
|
||||
* Thus you can only ever safely access the identifier of an entity obtained through
|
||||
* this method.
|
||||
*
|
||||
* The use-cases for partial references involve maintaining bidirectional associations
|
||||
* without loading one side of the association or to update an entity without loading it.
|
||||
* Note, however, that in the latter case the original (persistent) entity data will
|
||||
* never be visible to the application (especially not event listeners) as it will
|
||||
* never be loaded in the first place.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return object The (partial) entity reference.
|
||||
*/
|
||||
public function getPartialReference($entityName, $identifier);
|
||||
|
||||
/**
|
||||
* Closes the EntityManager. All entities that are currently managed
|
||||
* by this EntityManager become detached. The EntityManager may no longer
|
||||
* be used after it is closed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* Creates a copy of the given entity. Can create a shallow or a deep copy.
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @param boolean $deep FALSE for a shallow copy, TRUE for a deep copy.
|
||||
*
|
||||
* @return object The new entity.
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function copy($entity, $deep = false);
|
||||
|
||||
/**
|
||||
* Acquire a lock on the given entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param int $lockMode
|
||||
* @param int|null $lockVersion
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws PessimisticLockException
|
||||
*/
|
||||
public function lock($entity, $lockMode, $lockVersion = null);
|
||||
|
||||
/**
|
||||
* Gets the EventManager used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\Common\EventManager
|
||||
*/
|
||||
public function getEventManager();
|
||||
|
||||
/**
|
||||
* Gets the Configuration used by the EntityManager.
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function getConfiguration();
|
||||
|
||||
/**
|
||||
* Check if the Entity manager is open or closed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOpen();
|
||||
|
||||
/**
|
||||
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
|
||||
*
|
||||
* @return UnitOfWork
|
||||
*/
|
||||
public function getUnitOfWork();
|
||||
|
||||
/**
|
||||
* Gets a hydrator for the given hydration mode.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Create a new instance for the given hydration mode.
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
*
|
||||
* @throws ORMException
|
||||
*/
|
||||
public function newHydrator($hydrationMode);
|
||||
|
||||
/**
|
||||
* Gets the proxy factory used by the EntityManager to create entity proxies.
|
||||
*
|
||||
* @return \Doctrine\ORM\Proxy\ProxyFactory
|
||||
*/
|
||||
public function getProxyFactory();
|
||||
|
||||
/**
|
||||
* Gets the enabled filters.
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\FilterCollection The active filter collection.
|
||||
*/
|
||||
public function getFilters();
|
||||
|
||||
/**
|
||||
* Checks whether the state of the filter collection is clean.
|
||||
*
|
||||
* @return boolean True, if the filter collection is clean.
|
||||
*/
|
||||
public function isFiltersStateClean();
|
||||
|
||||
/**
|
||||
* Checks whether the Entity Manager has filters.
|
||||
*
|
||||
* @return boolean True, if the EM has a filter collection.
|
||||
*/
|
||||
public function hasFilters();
|
||||
}
|
||||
|
||||
@@ -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)];
|
||||
|
||||
|
||||
@@ -88,4 +88,18 @@ class HydrationException extends \Doctrine\ORM\ORMException
|
||||
$discrColumnName, $entityName, $dqlAlias
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $discrValue
|
||||
* @param array $discrMap
|
||||
*
|
||||
* @return HydrationException
|
||||
*/
|
||||
public static function invalidDiscriminatorValue($discrValue, $discrMap)
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The discriminator value "%s" is invalid. It must be one of "%s".',
|
||||
$discrValue, implode('", "', $discrMap)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,13 @@ class ObjectHydrator extends AbstractHydrator
|
||||
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
|
||||
}
|
||||
|
||||
$className = $this->ce[$className]->discriminatorMap[$data[$discrColumn]];
|
||||
$discrMap = $this->ce[$className]->discriminatorMap;
|
||||
|
||||
if ( ! isset($discrMap[$data[$discrColumn]])) {
|
||||
throw HydrationException::invalidDiscriminatorValue($data[$discrColumn], array_keys($discrMap));
|
||||
}
|
||||
|
||||
$className = $discrMap[$data[$discrColumn]];
|
||||
|
||||
unset($data[$discrColumn]);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,13 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
|
||||
}
|
||||
|
||||
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
|
||||
$discrMap = $this->class->discriminatorMap;
|
||||
|
||||
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
|
||||
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
|
||||
}
|
||||
|
||||
$entityName = $discrMap[$sqlResult[$discrColumnName]];
|
||||
|
||||
unset($sqlResult[$discrColumnName]);
|
||||
}
|
||||
|
||||
@@ -866,7 +866,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function newInstance()
|
||||
{
|
||||
if ($this->_prototype === null) {
|
||||
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
||||
if (PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513 || PHP_VERSION_ID >= 50600) {
|
||||
$this->_prototype = $this->reflClass->newInstanceWithoutConstructor();
|
||||
} else {
|
||||
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
||||
}
|
||||
}
|
||||
|
||||
return clone $this->_prototype;
|
||||
@@ -1031,9 +1035,14 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function isIdentifier($fieldName)
|
||||
{
|
||||
if ( ! $this->identifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->isIdentifierComposite) {
|
||||
return $fieldName === $this->identifier[0];
|
||||
}
|
||||
|
||||
return in_array($fieldName, $this->identifier);
|
||||
}
|
||||
|
||||
@@ -2483,6 +2492,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function addLifecycleCallback($callback, $event)
|
||||
{
|
||||
if(isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->lifecycleCallbacks[$event][] = $callback;
|
||||
}
|
||||
|
||||
@@ -2790,8 +2803,12 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function setSequenceGeneratorDefinition(array $definition)
|
||||
{
|
||||
if (isset($definition['name']) && $definition['name'] == '`') {
|
||||
$definition['name'] = trim($definition['name'], '`');
|
||||
if ( ! isset($definition['sequenceName'])) {
|
||||
throw MappingException::missingSequenceName($this->name);
|
||||
}
|
||||
|
||||
if ($definition['sequenceName'][0] == '`') {
|
||||
$definition['sequenceName'] = trim($definition['sequenceName'], '`');
|
||||
$definition['quoted'] = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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'])) {
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ class BasicEntityPersister
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$params[] = $value;
|
||||
$set[] = $column . ' = ' . $placeholder;
|
||||
$types[] = $this->columnTypes[$columnName];
|
||||
@@ -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]);
|
||||
@@ -850,7 +850,7 @@ class BasicEntityPersister
|
||||
$sql = $this->getSelectSQL($id, null, $lockMode);
|
||||
list($params, $types) = $this->expandParameters($id);
|
||||
$stmt = $this->conn->executeQuery($sql, $params, $types);
|
||||
|
||||
|
||||
$hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
$hydrator->hydrateAll($stmt, $this->rsm, array(Query::HINT_REFRESH => true));
|
||||
}
|
||||
@@ -1130,7 +1130,7 @@ class BasicEntityPersister
|
||||
$tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
|
||||
|
||||
if ('' !== $filterSql) {
|
||||
$conditionSql = $conditionSql
|
||||
$conditionSql = $conditionSql
|
||||
? $conditionSql . ' AND ' . $filterSql
|
||||
: $filterSql;
|
||||
}
|
||||
@@ -1283,7 +1283,7 @@ class BasicEntityPersister
|
||||
if ($assoc['isOwningSide']) {
|
||||
$tableAlias = $this->getSQLTableAlias($association['targetEntity'], $assocAlias);
|
||||
$this->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']);
|
||||
|
||||
|
||||
foreach ($association['joinColumns'] as $joinColumn) {
|
||||
$sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
|
||||
$targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->class, $this->platform);
|
||||
@@ -1415,7 +1415,7 @@ class BasicEntityPersister
|
||||
foreach ($columns as $column) {
|
||||
$placeholder = '?';
|
||||
|
||||
if (isset($this->class->fieldNames[$column])
|
||||
if (isset($this->class->fieldNames[$column])
|
||||
&& isset($this->columnTypes[$this->class->fieldNames[$column]])
|
||||
&& isset($this->class->fieldMappings[$this->class->fieldNames[$column]]['requireSQLConversion'])) {
|
||||
|
||||
@@ -1488,7 +1488,7 @@ class BasicEntityPersister
|
||||
$columnName = $this->quoteStrategy->getColumnName($field, $class, $this->platform);
|
||||
$sql = $tableAlias . '.' . $columnName;
|
||||
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
|
||||
|
||||
|
||||
$this->rsm->addFieldResult($alias, $columnAlias, $field);
|
||||
|
||||
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
|
||||
@@ -1550,7 +1550,7 @@ class BasicEntityPersister
|
||||
break;
|
||||
}
|
||||
|
||||
$lock = $this->platform->appendLockHint($this->getLockTablesSql(), $lockMode);
|
||||
$lock = $this->getLockTablesSql($lockMode);
|
||||
$where = ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ';
|
||||
$sql = 'SELECT 1 '
|
||||
. $lock
|
||||
@@ -1565,13 +1565,18 @@ class BasicEntityPersister
|
||||
/**
|
||||
* Gets the FROM and optionally JOIN conditions to lock the entity managed by this persister.
|
||||
*
|
||||
* @param integer $lockMode One of the Doctrine\DBAL\LockMode::* constants.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getLockTablesSql()
|
||||
protected function getLockTablesSql($lockMode)
|
||||
{
|
||||
return 'FROM '
|
||||
. $this->quoteStrategy->getTableName($this->class, $this->platform) . ' '
|
||||
. $this->getSQLTableAlias($this->class->name);
|
||||
return $this->platform->appendLockHint(
|
||||
'FROM '
|
||||
. $this->quoteStrategy->getTableName($this->class, $this->platform) . ' '
|
||||
. $this->getSQLTableAlias($this->class->name),
|
||||
$lockMode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1910,7 +1915,7 @@ class BasicEntityPersister
|
||||
$alias = $this->getSQLTableAlias($this->class->name);
|
||||
|
||||
$sql = 'SELECT 1 '
|
||||
. $this->getLockTablesSql()
|
||||
. $this->getLockTablesSql(null)
|
||||
. ' WHERE ' . $this->getSelectConditionSQL($criteria);
|
||||
|
||||
if ($filterSql = $this->generateFilterConditionSQL($this->class, $alias)) {
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -288,7 +288,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
foreach ($this->class->parentClasses as $parentClass) {
|
||||
$parentMetadata = $this->em->getClassMetadata($parentClass);
|
||||
$parentTable = $this->quoteStrategy->getTableName($parentMetadata, $this->platform);
|
||||
|
||||
|
||||
$this->conn->delete($parentTable, $id);
|
||||
}
|
||||
}
|
||||
@@ -342,7 +342,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// If the current class in the root entity, add the filters
|
||||
if ($filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName))) {
|
||||
$conditionSql .= $conditionSql
|
||||
$conditionSql .= $conditionSql
|
||||
? ' AND ' . $filterSql
|
||||
: $filterSql;
|
||||
}
|
||||
@@ -387,16 +387,13 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the FROM and optionally JOIN conditions to lock the entity managed by this persister.
|
||||
*
|
||||
* @return string
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLockTablesSql()
|
||||
protected function getLockTablesSql($lockMode)
|
||||
{
|
||||
$joinSql = '';
|
||||
$identifierColumns = $this->class->getIdentifierColumnNames();
|
||||
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
|
||||
$quotedTableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
|
||||
|
||||
// INNER JOIN parent tables
|
||||
foreach ($this->class->parentClasses as $parentClassName) {
|
||||
@@ -412,7 +409,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$joinSql .= implode(' AND ', $conditions);
|
||||
}
|
||||
|
||||
return 'FROM ' . $quotedTableName . ' ' . $baseTableAlias . $joinSql;
|
||||
return parent::getLockTablesSql($lockMode) . $joinSql;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -488,8 +485,8 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Add join columns (foreign keys)
|
||||
foreach ($subClass->associationMappings as $mapping) {
|
||||
if ( ! $mapping['isOwningSide']
|
||||
|| ! ($mapping['type'] & ClassMetadata::TO_ONE)
|
||||
if ( ! $mapping['isOwningSide']
|
||||
|| ! ($mapping['type'] & ClassMetadata::TO_ONE)
|
||||
|| isset($mapping['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
@@ -505,17 +502,17 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
$this->selectColumnListSql = implode(', ', $columnList);
|
||||
|
||||
|
||||
return $this->selectColumnListSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getInsertColumnList()
|
||||
{
|
||||
// Identifier columns must always come first in the column list of subclasses.
|
||||
$columns = $this->class->parentClasses
|
||||
$columns = $this->class->parentClasses
|
||||
? $this->class->getIdentifierColumnNames()
|
||||
: array();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +456,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
$sqlParts[] = (($this->useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '')
|
||||
. $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||
. $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
$sql = implode(' AND ', $sqlParts);
|
||||
@@ -496,7 +496,7 @@ class SqlWalker implements TreeWalker
|
||||
default:
|
||||
//@todo: throw exception?
|
||||
return '';
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
$filterClauses = array();
|
||||
@@ -574,7 +574,7 @@ class SqlWalker implements TreeWalker
|
||||
$this->useSqlTableAliases = false;
|
||||
|
||||
return $this->walkUpdateClause($AST->updateClause)
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,7 +585,7 @@ class SqlWalker implements TreeWalker
|
||||
$this->useSqlTableAliases = false;
|
||||
|
||||
return $this->walkDeleteClause($AST->deleteClause)
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,10 +700,10 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
$addMetaColumns = ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
|
||||
$this->query->getHydrationMode() == Query::HYDRATE_OBJECT
|
||||
||
|
||||
$this->query->getHydrationMode() != Query::HYDRATE_OBJECT &&
|
||||
$this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS);
|
||||
$this->query->getHydrationMode() == Query::HYDRATE_OBJECT
|
||||
||
|
||||
$this->query->getHydrationMode() != Query::HYDRATE_OBJECT &&
|
||||
$this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS);
|
||||
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
$class = $selectedClass['class'];
|
||||
@@ -801,10 +801,7 @@ class SqlWalker implements TreeWalker
|
||||
$sqlParts = array();
|
||||
|
||||
foreach ($identificationVarDecls as $identificationVariableDecl) {
|
||||
$sql = $this->platform->appendLockHint(
|
||||
$this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration),
|
||||
$this->query->getHint(Query::HINT_LOCK_MODE)
|
||||
);
|
||||
$sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration);
|
||||
|
||||
foreach ($identificationVariableDecl->joins as $join) {
|
||||
$sql .= $this->walkJoin($join);
|
||||
@@ -842,10 +839,15 @@ 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);
|
||||
$sql = $this->platform->appendLockHint(
|
||||
$this->quoteStrategy->getTableName($class, $this->platform) . ' ' .
|
||||
$this->getSQLTableAlias($class->getTableName(), $dqlAlias),
|
||||
$this->query->getHint(Query::HINT_LOCK_MODE)
|
||||
);
|
||||
|
||||
if ($class->isInheritanceTypeJoined()) {
|
||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $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 = '';
|
||||
|
||||
@@ -896,7 +899,7 @@ class SqlWalker implements TreeWalker
|
||||
case ($assoc['type'] & ClassMetadata::TO_ONE):
|
||||
$conditions = array();
|
||||
|
||||
foreach ($assoc['joinColumns'] as $joinColumn) {
|
||||
foreach ($assoc['joinColumns'] as $joinColumn) {
|
||||
$quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
|
||||
$quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1416,10 +1439,7 @@ class SqlWalker implements TreeWalker
|
||||
$sqlParts = array ();
|
||||
|
||||
foreach ($identificationVarDecls as $subselectIdVarDecl) {
|
||||
$sql = $this->platform->appendLockHint(
|
||||
$this->walkRangeVariableDeclaration($subselectIdVarDecl->rangeVariableDeclaration),
|
||||
$this->query->getHint(Query::HINT_LOCK_MODE)
|
||||
);
|
||||
$sql = $this->walkRangeVariableDeclaration($subselectIdVarDecl->rangeVariableDeclaration);
|
||||
|
||||
foreach ($subselectIdVarDecl->joins as $join) {
|
||||
$sql .= $this->walkJoin($join);
|
||||
@@ -1437,7 +1457,7 @@ class SqlWalker implements TreeWalker
|
||||
public function walkSimpleSelectClause($simpleSelectClause)
|
||||
{
|
||||
return 'SELECT' . ($simpleSelectClause->isDistinct ? ' DISTINCT' : '')
|
||||
. $this->walkSimpleSelectExpression($simpleSelectClause->simpleSelectExpression);
|
||||
. $this->walkSimpleSelectExpression($simpleSelectClause->simpleSelectExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1474,6 +1494,7 @@ class SqlWalker implements TreeWalker
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldType = 'string';
|
||||
switch (true) {
|
||||
case ($e instanceof AST\PathExpression):
|
||||
$fieldName = $e->field;
|
||||
@@ -1494,10 +1515,6 @@ class SqlWalker implements TreeWalker
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$fieldType = 'string';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
@@ -1572,7 +1589,7 @@ class SqlWalker implements TreeWalker
|
||||
public function walkAggregateExpression($aggExpression)
|
||||
{
|
||||
return $aggExpression->functionName . '(' . ($aggExpression->isDistinct ? 'DISTINCT ' : '')
|
||||
. $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) . ')';
|
||||
. $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1867,7 +1884,7 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
// join to target table
|
||||
$sql .= $this->quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $this->platform) . ' ' . $joinTableAlias
|
||||
. ' INNER JOIN ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' ON ';
|
||||
. ' INNER JOIN ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' ON ';
|
||||
|
||||
// join conditions
|
||||
$joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns'];
|
||||
@@ -2047,7 +2064,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($betweenExpr->not) $sql .= ' NOT';
|
||||
|
||||
$sql .= ' BETWEEN ' . $this->walkArithmeticExpression($betweenExpr->leftBetweenExpression)
|
||||
. ' AND ' . $this->walkArithmeticExpression($betweenExpr->rightBetweenExpression);
|
||||
. ' AND ' . $this->walkArithmeticExpression($betweenExpr->rightBetweenExpression);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
@@ -894,8 +894,8 @@ class QueryBuilder
|
||||
*/
|
||||
public function andWhere($where)
|
||||
{
|
||||
$where = $this->getDQLPart('where');
|
||||
$args = func_get_args();
|
||||
$where = $this->getDQLPart('where');
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
$where->addMultiple($args);
|
||||
@@ -927,8 +927,8 @@ class QueryBuilder
|
||||
*/
|
||||
public function orWhere($where)
|
||||
{
|
||||
$where = $this->getDqlPart('where');
|
||||
$args = func_get_args();
|
||||
$where = $this->getDqlPart('where');
|
||||
|
||||
if ($where instanceof Expr\Orx) {
|
||||
$where->addMultiple($args);
|
||||
@@ -1007,8 +1007,8 @@ class QueryBuilder
|
||||
*/
|
||||
public function andHaving($having)
|
||||
{
|
||||
$having = $this->getDqlPart('having');
|
||||
$args = func_get_args();
|
||||
$having = $this->getDqlPart('having');
|
||||
|
||||
if ($having instanceof Expr\Andx) {
|
||||
$having->addMultiple($args);
|
||||
@@ -1030,8 +1030,8 @@ class QueryBuilder
|
||||
*/
|
||||
public function orHaving($having)
|
||||
{
|
||||
$having = $this->getDqlPart('having');
|
||||
$args = func_get_args();
|
||||
$having = $this->getDqlPart('having');
|
||||
|
||||
if ($having instanceof Expr\Orx) {
|
||||
$having->addMultiple($args);
|
||||
@@ -1087,7 +1087,8 @@ class QueryBuilder
|
||||
*/
|
||||
public function addCriteria(Criteria $criteria)
|
||||
{
|
||||
$visitor = new QueryExpressionVisitor();
|
||||
$rootAlias = $this->getRootAlias();
|
||||
$visitor = new QueryExpressionVisitor($rootAlias);
|
||||
|
||||
if ($whereExpression = $criteria->getWhereExpression()) {
|
||||
$this->andWhere($visitor->dispatch($whereExpression));
|
||||
@@ -1098,7 +1099,7 @@ class QueryBuilder
|
||||
|
||||
if ($criteria->getOrderings()) {
|
||||
foreach ($criteria->getOrderings() as $sort => $order) {
|
||||
$this->addOrderBy($sort, $order);
|
||||
$this->addOrderBy($rootAlias . '.' . $sort, $order);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Doctrine\ORM\Tools\Console;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Doctrine\ORM\Version;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
|
||||
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
|
||||
@@ -35,10 +35,10 @@ class ConsoleRunner
|
||||
/**
|
||||
* Create a Symfony Console HelperSet
|
||||
*
|
||||
* @param EntityManager $entityManager
|
||||
* @param EntityManagerInterface $entityManager
|
||||
* @return HelperSet
|
||||
*/
|
||||
public static function createHelperSet(EntityManager $entityManager)
|
||||
public static function createHelperSet(EntityManagerInterface $entityManager)
|
||||
{
|
||||
return new HelperSet(array(
|
||||
'db' => new ConnectionHelper($entityManager->getConnection()),
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -193,7 +193,7 @@ class XmlExporter extends AbstractExporter
|
||||
}
|
||||
|
||||
if (isset($field['unique']) && $field['unique']) {
|
||||
$fieldXml->addAttribute('unique', $field['unique']);
|
||||
$fieldXml->addAttribute('unique', $field['unique'] ? 'true' : 'false');
|
||||
}
|
||||
|
||||
if (isset($field['options'])) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
@@ -92,25 +93,22 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
if ($this->platform instanceof PostgreSqlPlatform) {
|
||||
// Set every select expression as visible(hidden = false) to
|
||||
// make $AST to have scalar mappings properly
|
||||
$hiddens = array();
|
||||
foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
|
||||
$hiddens[$idx] = $expr->hiddenAliasResultVariable;
|
||||
$expr->hiddenAliasResultVariable = false;
|
||||
}
|
||||
|
||||
$innerSql = parent::walkSelectStatement($AST);
|
||||
|
||||
// Restore hiddens
|
||||
foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
|
||||
$expr->hiddenAliasResultVariable = $hiddens[$idx];
|
||||
}
|
||||
} else {
|
||||
$innerSql = parent::walkSelectStatement($AST);
|
||||
// Set every select expression as visible(hidden = false) to
|
||||
// make $AST have scalar mappings properly - this is relevant for referencing selected
|
||||
// fields from outside the subquery, for example in the ORDER BY segment
|
||||
$hiddens = array();
|
||||
|
||||
foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
|
||||
$hiddens[$idx] = $expr->hiddenAliasResultVariable;
|
||||
$expr->hiddenAliasResultVariable = false;
|
||||
}
|
||||
|
||||
$innerSql = parent::walkSelectStatement($AST);
|
||||
|
||||
// Restore hiddens
|
||||
foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
|
||||
$expr->hiddenAliasResultVariable = $hiddens[$idx];
|
||||
}
|
||||
|
||||
// Find out the SQL alias of the identifier column of the root entity.
|
||||
// It may be possible to make this work with multiple root entities but that
|
||||
@@ -160,11 +158,8 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
|
||||
implode(', ', $sqlIdentifier), $innerSql);
|
||||
|
||||
if ($this->platform instanceof PostgreSqlPlatform ||
|
||||
$this->platform instanceof OraclePlatform) {
|
||||
//http://www.doctrine-project.org/jira/browse/DDC-1958
|
||||
$this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql);
|
||||
}
|
||||
// http://www.doctrine-project.org/jira/browse/DDC-1958
|
||||
$sql = $this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql);
|
||||
|
||||
// Apply the limit and offset.
|
||||
$sql = $this->platform->modifyLimitQuery(
|
||||
@@ -181,7 +176,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates new SQL for Postgresql or Oracle if necessary.
|
||||
*
|
||||
@@ -192,19 +187,21 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, &$sql)
|
||||
public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, $sql)
|
||||
{
|
||||
// For every order by, find out the SQL alias by inspecting the ResultSetMapping.
|
||||
$sqlOrderColumns = array();
|
||||
$orderBy = array();
|
||||
if (isset($AST->orderByClause)) {
|
||||
foreach ($AST->orderByClause->orderByItems as $item) {
|
||||
$possibleAliases = (is_object($item->expression))
|
||||
? array_keys($this->rsm->fieldMappings, $item->expression->field)
|
||||
: array_keys($this->rsm->scalarMappings, $item->expression);
|
||||
$expression = $item->expression;
|
||||
|
||||
$possibleAliases = $expression instanceof PathExpression
|
||||
? array_keys($this->rsm->fieldMappings, $expression->field)
|
||||
: array_keys($this->rsm->scalarMappings, $expression);
|
||||
|
||||
foreach ($possibleAliases as $alias) {
|
||||
if (!is_object($item->expression) || $this->rsm->columnOwnerMap[$alias] == $item->expression->identificationVariable) {
|
||||
if (!is_object($expression) || $this->rsm->columnOwnerMap[$alias] == $expression->identificationVariable) {
|
||||
$sqlOrderColumns[] = $alias;
|
||||
$orderBy[] = $alias . ' ' . $item->type;
|
||||
break;
|
||||
@@ -215,11 +212,6 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
|
||||
}
|
||||
|
||||
// We don't need orderBy in inner query.
|
||||
// However at least on 5.4.6 I'm getting a segmentation fault and thus we don't clear it for now.
|
||||
/*$AST->orderByClause = null;
|
||||
$innerSql = parent::walkSelectStatement($AST);*/
|
||||
|
||||
if (count($orderBy)) {
|
||||
$sql = sprintf(
|
||||
'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
|
||||
@@ -228,5 +220,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
implode(', ', $orderBy)
|
||||
);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
94
lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Normal file → Executable file
94
lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Normal file → Executable file
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
@@ -118,31 +119,8 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
public function count()
|
||||
{
|
||||
if ($this->count === null) {
|
||||
/* @var $countQuery Query */
|
||||
$countQuery = $this->cloneQuery($this->query);
|
||||
|
||||
if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
|
||||
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
}
|
||||
|
||||
if ($this->useOutputWalker($countQuery)) {
|
||||
$platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
$rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count');
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
try {
|
||||
$data = $countQuery->getScalarResult();
|
||||
$data = array_map('current', $data);
|
||||
$this->count = array_sum($data);
|
||||
$this->count = array_sum(array_map('current', $this->getCountQuery()->getScalarResult()));
|
||||
} catch(NoResultException $e) {
|
||||
$this->count = 0;
|
||||
}
|
||||
@@ -165,7 +143,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 +156,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 +209,68 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Query prepared to count.
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
private function getCountQuery()
|
||||
{
|
||||
/* @var $countQuery Query */
|
||||
$countQuery = $this->cloneQuery($this->query);
|
||||
|
||||
if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) {
|
||||
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
}
|
||||
|
||||
if ($this->useOutputWalker($countQuery)) {
|
||||
$platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
$rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count');
|
||||
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
|
||||
$countQuery->setResultSetMapping($rsm);
|
||||
} else {
|
||||
$this->appendTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker');
|
||||
}
|
||||
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$parser = new Parser($countQuery);
|
||||
$parameterMappings = $parser->parse()->getParameterMappings();
|
||||
/* @var $parameters \Doctrine\Common\Collections\Collection|\Doctrine\ORM\Query\Parameter[] */
|
||||
$parameters = $countQuery->getParameters();
|
||||
|
||||
foreach ($parameters as $key => $parameter) {
|
||||
$parameterName = $parameter->getName();
|
||||
|
||||
if( ! (isset($parameterMappings[$parameterName]) || array_key_exists($parameterName, $parameterMappings))) {
|
||||
unset($parameters[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$countQuery->setParameters($parameters);
|
||||
|
||||
return $countQuery;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -430,7 +430,7 @@ class SchemaTool
|
||||
$knownOptions = array('comment', 'unsigned', 'fixed', 'default');
|
||||
|
||||
foreach ($knownOptions as $knownOption) {
|
||||
if ( isset($mapping['options'][$knownOption])) {
|
||||
if (array_key_exists($knownOption, $mapping['options'])) {
|
||||
$options[$knownOption] = $mapping['options'][$knownOption];
|
||||
|
||||
unset($mapping['options'][$knownOption]);
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
|
||||
@@ -530,7 +530,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$class = $this->em->getClassMetadata(get_class($entity));
|
||||
}
|
||||
|
||||
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush);
|
||||
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::preFlush) & ~ListenersInvoker::INVOKE_MANAGER;
|
||||
|
||||
if ($invoke !== ListenersInvoker::INVOKE_NONE) {
|
||||
$this->listenersInvoker->invoke($class, Events::preFlush, $entity, new PreFlushEventArgs($this->em), $invoke);
|
||||
@@ -541,7 +541,15 @@ class UnitOfWork implements PropertyChangedListener
|
||||
foreach ($class->reflFields as $name => $refProp) {
|
||||
$value = $refProp->getValue($entity);
|
||||
|
||||
if ($class->isCollectionValuedAssociation($name) && $value !== null && ! ($value instanceof PersistentCollection)) {
|
||||
if ($class->isCollectionValuedAssociation($name) && $value !== null) {
|
||||
if ($value instanceof PersistentCollection) {
|
||||
if ($value->getOwner() === $entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = new ArrayCollection($value->getValues());
|
||||
}
|
||||
|
||||
// If $value is not a Collection then use an ArrayCollection.
|
||||
if ( ! $value instanceof Collection) {
|
||||
$value = new ArrayCollection($value);
|
||||
@@ -894,20 +902,24 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$actualData = array();
|
||||
|
||||
foreach ($class->reflFields as $name => $refProp) {
|
||||
if ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) {
|
||||
if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity())
|
||||
&& ($name !== $class->versionField)
|
||||
&& ! $class->isCollectionValuedAssociation($name)) {
|
||||
$actualData[$name] = $refProp->getValue($entity);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($this->originalEntityData[$oid])) {
|
||||
throw new \RuntimeException('Cannot call recomputeSingleEntityChangeSet before computeChangeSet on an entity.');
|
||||
}
|
||||
|
||||
$originalData = $this->originalEntityData[$oid];
|
||||
$changeSet = array();
|
||||
|
||||
foreach ($actualData as $propName => $actualValue) {
|
||||
$orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
|
||||
|
||||
if (is_object($orgValue) && $orgValue !== $actualValue) {
|
||||
$changeSet[$propName] = array($orgValue, $actualValue);
|
||||
} else if ($orgValue != $actualValue || ($orgValue === null ^ $actualValue === null)) {
|
||||
if ($orgValue !== $actualValue) {
|
||||
$changeSet[$propName] = array($orgValue, $actualValue);
|
||||
}
|
||||
}
|
||||
@@ -915,8 +927,10 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ($changeSet) {
|
||||
if (isset($this->entityChangeSets[$oid])) {
|
||||
$this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
|
||||
} else if ( ! isset($this->entityInsertions[$oid])) {
|
||||
$this->entityChangeSets[$oid] = $changeSet;
|
||||
$this->entityUpdates[$oid] = $entity;
|
||||
}
|
||||
|
||||
$this->originalEntityData[$oid] = $actualData;
|
||||
}
|
||||
}
|
||||
@@ -1736,6 +1750,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$associatedId = $this->getEntityIdentifier($idValue);
|
||||
|
||||
$flatId[$idField] = $associatedId[$targetClassMetadata->identifier[0]];
|
||||
} else {
|
||||
$flatId[$idField] = $idValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2231,6 +2247,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
function ($assoc) { return $assoc['isCascadeRemove']; }
|
||||
);
|
||||
|
||||
$entitiesToCascade = array();
|
||||
|
||||
foreach ($associationMappings as $assoc) {
|
||||
if ($entity instanceof Proxy && !$entity->__isInitialized__) {
|
||||
$entity->__load();
|
||||
@@ -2243,18 +2261,22 @@ class UnitOfWork implements PropertyChangedListener
|
||||
case (is_array($relatedEntities)):
|
||||
// If its a PersistentCollection initialization is intended! No unwrap!
|
||||
foreach ($relatedEntities as $relatedEntity) {
|
||||
$this->doRemove($relatedEntity, $visited);
|
||||
$entitiesToCascade[] = $relatedEntity;
|
||||
}
|
||||
break;
|
||||
|
||||
case ($relatedEntities !== null):
|
||||
$this->doRemove($relatedEntities, $visited);
|
||||
$entitiesToCascade[] = $relatedEntities;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($entitiesToCascade as $relatedEntity) {
|
||||
$this->doRemove($relatedEntity, $visited);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2471,16 +2493,16 @@ class UnitOfWork implements PropertyChangedListener
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName];
|
||||
}
|
||||
|
||||
$idHash = implode(' ', $id);
|
||||
} else {
|
||||
$idHash = isset($class->associationMappings[$class->identifier[0]])
|
||||
$id = isset($class->associationMappings[$class->identifier[0]])
|
||||
? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]
|
||||
: $data[$class->identifier[0]];
|
||||
|
||||
$id = array($class->identifier[0] => $idHash);
|
||||
$id = array($class->identifier[0] => $id);
|
||||
}
|
||||
|
||||
$idHash = implode(' ', $id);
|
||||
|
||||
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
|
||||
$entity = $this->identityMap[$class->rootEntityName][$idHash];
|
||||
$oid = spl_object_hash($entity);
|
||||
@@ -2490,14 +2512,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
&& isset($hints[Query::HINT_REFRESH_ENTITY])
|
||||
&& ($unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY]) !== $entity
|
||||
&& $unmanagedProxy instanceof Proxy
|
||||
&& (($unmanagedProxyClass = $this->em->getClassMetadata(get_class($unmanagedProxy))) === $class)
|
||||
&& $this->isIdentifierEquals($unmanagedProxy, $entity)
|
||||
) {
|
||||
// DDC-1238 - we have a managed instance, but it isn't the provided one.
|
||||
// Therefore we clear its identifier. Also, we must re-fetch metadata since the
|
||||
// refreshed object may be anything
|
||||
|
||||
foreach ($unmanagedProxyClass->identifier as $fieldName) {
|
||||
$unmanagedProxyClass->reflFields[$fieldName]->setValue($unmanagedProxy, null);
|
||||
foreach ($class->identifier as $fieldName) {
|
||||
$class->reflFields[$fieldName]->setValue($unmanagedProxy, null);
|
||||
}
|
||||
|
||||
return $unmanagedProxy;
|
||||
@@ -3206,4 +3228,37 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->evm->dispatchEvent(Events::postFlush, new PostFlushEventArgs($this->em));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if two given entities actually are the same based on identifier comparison
|
||||
*
|
||||
* @param object $entity1
|
||||
* @param object $entity2
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isIdentifierEquals($entity1, $entity2)
|
||||
{
|
||||
if ($entity1 === $entity2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$class = $this->em->getClassMetadata(get_class($entity1));
|
||||
|
||||
if ($class !== $this->em->getClassMetadata(get_class($entity2))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$oid1 = spl_object_hash($entity1);
|
||||
$oid2 = spl_object_hash($entity2);
|
||||
|
||||
$id1 = isset($this->entityIdentifiers[$oid1])
|
||||
? $this->entityIdentifiers[$oid1]
|
||||
: $this->flattenIdentifier($class, $class->getIdentifierValues($entity1));
|
||||
$id2 = isset($this->entityIdentifiers[$oid2])
|
||||
? $this->entityIdentifiers[$oid2]
|
||||
: $this->flattenIdentifier($class, $class->getIdentifierValues($entity2));
|
||||
|
||||
return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.4.0-DEV';
|
||||
const VERSION = '2.4.7';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
||||
@@ -83,7 +83,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fetchColumn($statement, array $params = array(), $colnum = 0)
|
||||
public function fetchColumn($statement, array $params = array(), $column = 0, array $types = array())
|
||||
{
|
||||
return $this->_fetchOneResult;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,11 @@ class ECommerceProduct
|
||||
}
|
||||
}
|
||||
|
||||
public function setCategories($categories)
|
||||
{
|
||||
$this->categories = $categories;
|
||||
}
|
||||
|
||||
public function getCategories()
|
||||
{
|
||||
return $this->categories;
|
||||
@@ -166,6 +171,9 @@ class ECommerceProduct
|
||||
public function __clone()
|
||||
{
|
||||
$this->isCloned = true;
|
||||
if ($this->categories) {
|
||||
$this->categories = clone $this->categories;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\NullDefault;
|
||||
|
||||
/** @Entity */
|
||||
class NullDefaultColumn
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
public $id;
|
||||
|
||||
/** @Column(options={"default":NULL}) */
|
||||
public $nullDefault;
|
||||
}
|
||||
42
tests/Doctrine/Tests/Models/Taxi/Car.php
Normal file
42
tests/Doctrine/Tests/Models/Taxi/Car.php
Normal 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;
|
||||
}
|
||||
}
|
||||
37
tests/Doctrine/Tests/Models/Taxi/Driver.php
Normal file
37
tests/Doctrine/Tests/Models/Taxi/Driver.php
Normal 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;
|
||||
}
|
||||
}
|
||||
42
tests/Doctrine/Tests/Models/Taxi/PaidRide.php
Normal file
42
tests/Doctrine/Tests/Models/Taxi/PaidRide.php
Normal 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;
|
||||
}
|
||||
}
|
||||
32
tests/Doctrine/Tests/Models/Taxi/Ride.php
Normal file
32
tests/Doctrine/Tests/Models/Taxi/Ride.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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']
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ use Doctrine\Tests\Models\CMS\CmsGroup;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\Tests\Models\CMS\CmsComment;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use ReflectionMethod;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
@@ -139,6 +140,48 @@ 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 testCountQueryStripsParametersInSelect()
|
||||
{
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT u, (CASE WHEN u.id < :vipMaxId THEN 1 ELSE 0 END) AS hidden promotedFirst
|
||||
FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u
|
||||
WHERE u.id < :id or 1=1'
|
||||
);
|
||||
$query->setParameter('vipMaxId', 10);
|
||||
$query->setParameter('id', 100);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$paginator = new Paginator($query);
|
||||
|
||||
$getCountQuery = new ReflectionMethod($paginator, 'getCountQuery');
|
||||
|
||||
$getCountQuery->setAccessible(true);
|
||||
|
||||
$this->assertCount(2, $getCountQuery->invoke($paginator)->getParameters());
|
||||
$this->assertCount(3, $paginator);
|
||||
|
||||
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Query\SqlWalker');
|
||||
|
||||
$paginator = new Paginator($query);
|
||||
|
||||
// if select part of query is replaced with count(...) paginator should remove
|
||||
// parameters from query object not used in new query.
|
||||
$this->assertCount(1, $getCountQuery->invoke($paginator)->getParameters());
|
||||
$this->assertCount(3, $paginator);
|
||||
}
|
||||
|
||||
public function populate()
|
||||
{
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
@@ -166,3 +209,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,9 @@ class ProxiesLikeEntitiesTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testPersistUpdate()
|
||||
{
|
||||
// Considering case (a)
|
||||
$proxy = $this->_em->getProxyFactory()->getProxy('Doctrine\Tests\Models\CMS\CmsUser', array('id' => null));
|
||||
$proxy = $this->_em->getProxyFactory()->getProxy('Doctrine\Tests\Models\CMS\CmsUser', array('id' => 123));
|
||||
$proxy->__isInitialized__ = true;
|
||||
$proxy->id = null;
|
||||
$proxy->username = 'ocra';
|
||||
$proxy->name = 'Marco';
|
||||
$this->_em->persist($proxy);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
158
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php
Normal file
158
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1884Test.php
Normal 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]);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,12 @@ use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
|
||||
*/
|
||||
class DDC2074Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('ecommerce');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testShouldNotScheduleDeletionOnClonedInstances()
|
||||
{
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
|
||||
@@ -26,4 +32,30 @@ class DDC2074Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertEquals(0, count($uow->getScheduledCollectionDeletions()));
|
||||
}
|
||||
}
|
||||
|
||||
public function testSavingClonedPersistentCollection()
|
||||
{
|
||||
$product = new ECommerceProduct();
|
||||
$category = new ECommerceCategory();
|
||||
$category->setName('foo');
|
||||
$product->addCategory($category);
|
||||
|
||||
$this->_em->persist($product);
|
||||
$this->_em->persist($category);
|
||||
$this->_em->flush();
|
||||
|
||||
$newProduct = clone $product;
|
||||
|
||||
$this->_em->persist($newProduct);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$product1 = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $product->getId());
|
||||
$product2 = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $newProduct->getId());
|
||||
|
||||
$this->assertCount(1, $product1->getCategories());
|
||||
$this->assertCount(1, $product2->getCategories());
|
||||
|
||||
$this->assertSame($product1->getCategories()->get(0), $product2->getCategories()->get(0));
|
||||
}
|
||||
}
|
||||
|
||||
180
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2579Test.php
Normal file
180
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2579Test.php
Normal 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;
|
||||
}
|
||||
}
|
||||
55
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2645Test.php
Normal file
55
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2645Test.php
Normal 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;
|
||||
}
|
||||
122
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2660Test.php
Normal file
122
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2660Test.php
Normal 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;
|
||||
}
|
||||
}
|
||||
63
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2692Test.php
Normal file
63
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2692Test.php
Normal 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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2759Test.php
Normal file
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2759Test.php
Normal 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;
|
||||
}
|
||||
}
|
||||
146
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2775Test.php
Normal file
146
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2775Test.php
Normal 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;
|
||||
}
|
||||
}
|
||||
112
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2895Test.php
Normal file
112
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2895Test.php
Normal 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;
|
||||
}
|
||||
}
|
||||
118
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2931Test.php
Executable file
118
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2931Test.php
Executable file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-2931
|
||||
*/
|
||||
class DDC2931Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2931User'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
// no action needed - schema seems to be already in place
|
||||
}
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$first = new DDC2931User();
|
||||
$second = new DDC2931User();
|
||||
$third = new DDC2931User();
|
||||
|
||||
$second->parent = $first;
|
||||
$third->parent = $second;
|
||||
|
||||
$this->_em->persist($first);
|
||||
$this->_em->persist($second);
|
||||
$this->_em->persist($third);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$second = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC2931User', $second->id);
|
||||
|
||||
$this->assertSame(2, $second->getRank());
|
||||
}
|
||||
|
||||
public function testFetchJoinedEntitiesCanBeRefreshed()
|
||||
{
|
||||
$first = new DDC2931User();
|
||||
$second = new DDC2931User();
|
||||
$third = new DDC2931User();
|
||||
|
||||
$second->parent = $first;
|
||||
$third->parent = $second;
|
||||
|
||||
$first->value = 1;
|
||||
$second->value = 2;
|
||||
$third->value = 3;
|
||||
|
||||
$this->_em->persist($first);
|
||||
$this->_em->persist($second);
|
||||
$this->_em->persist($third);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$first->value = 4;
|
||||
$second->value = 5;
|
||||
$third->value = 6;
|
||||
|
||||
$refreshedSecond = $this
|
||||
->_em
|
||||
->createQuery(
|
||||
'SELECT e, p, c FROM '
|
||||
. __NAMESPACE__ . '\\DDC2931User e LEFT JOIN e.parent p LEFT JOIN e.child c WHERE e = :id'
|
||||
)
|
||||
->setParameter('id', $second)
|
||||
->setHint(Query::HINT_REFRESH, true)
|
||||
->getResult();
|
||||
|
||||
$this->assertCount(1, $refreshedSecond);
|
||||
$this->assertSame(1, $first->value);
|
||||
$this->assertSame(2, $second->value);
|
||||
$this->assertSame(3, $third->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @Entity */
|
||||
class DDC2931User
|
||||
{
|
||||
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
|
||||
/** @OneToOne(targetEntity="DDC2931User", inversedBy="child") */
|
||||
public $parent;
|
||||
|
||||
/** @OneToOne(targetEntity="DDC2931User", mappedBy="parent") */
|
||||
public $child;
|
||||
|
||||
/** @Column(type="integer") */
|
||||
public $value = 0;
|
||||
|
||||
/**
|
||||
* Return Rank recursively
|
||||
* My rank is 1 + rank of my parent
|
||||
* @return integer
|
||||
*/
|
||||
public function getRank()
|
||||
{
|
||||
return 1 + ($this->parent ? $this->parent->getRank() : 0);
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
}
|
||||
}
|
||||
199
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2984Test.php
Normal file
199
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2984Test.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\ConversionException;
|
||||
use Doctrine\DBAL\Types\StringType;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* @group DDC-2984
|
||||
*/
|
||||
class DDC2984Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if ( ! Type::hasType('ddc2984_domain_user_id')) {
|
||||
Type::addType(
|
||||
'ddc2984_domain_user_id',
|
||||
__NAMESPACE__ . '\DDC2984UserIdCustomDbalType'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2984User'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
// no action needed - schema seems to be already in place
|
||||
}
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$user = new DDC2984User(new DDC2984DomainUserId('unique_id_within_a_vo'));
|
||||
$user->applyName('Alex');
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush($user);
|
||||
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . "\DDC2984User");
|
||||
|
||||
$sameUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
|
||||
|
||||
//Until know, everything works as expected
|
||||
$this->assertTrue($user->sameIdentityAs($sameUser));
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
//After clearing the identity map, the UnitOfWork produces the warning described in DDC-2984
|
||||
$equalUser = $repository->find(new DDC2984DomainUserId('unique_id_within_a_vo'));
|
||||
|
||||
$this->assertNotSame($user, $equalUser);
|
||||
$this->assertTrue($user->sameIdentityAs($equalUser));
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity @Table(name="users") */
|
||||
class DDC2984User
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="ddc2984_domain_user_id")
|
||||
* @GeneratedValue(strategy="NONE")
|
||||
*
|
||||
* @var DDC2984DomainUserId
|
||||
*/
|
||||
private $userId;
|
||||
|
||||
/** @Column(type="string", length=50) */
|
||||
private $name;
|
||||
|
||||
public function __construct(DDC2984DomainUserId $aUserId)
|
||||
{
|
||||
$this->userId = $aUserId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DDC2984DomainUserId
|
||||
*/
|
||||
public function userId()
|
||||
{
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function applyName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DDC2984User $other
|
||||
* @return bool
|
||||
*/
|
||||
public function sameIdentityAs(DDC2984User $other)
|
||||
{
|
||||
return $this->userId()->sameValueAs($other->userId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DDC2984DomainUserId ValueObject
|
||||
*
|
||||
* @author Alexander Miertsch <kontakt@codeliner.ws>
|
||||
*/
|
||||
class DDC2984DomainUserId
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $userIdString;
|
||||
|
||||
/**
|
||||
* @param string $aUserIdString
|
||||
*/
|
||||
public function __construct($aUserIdString)
|
||||
{
|
||||
$this->userIdString = $aUserIdString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->userIdString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DDC2984DomainUserId $other
|
||||
* @return bool
|
||||
*/
|
||||
public function sameValueAs(DDC2984DomainUserId $other)
|
||||
{
|
||||
return $this->toString() === $other->toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class DDC2984UserIdCustomDbalType
|
||||
*
|
||||
* @author Alexander Miertsch <kontakt@codeliner.ws>
|
||||
*/
|
||||
class DDC2984UserIdCustomDbalType extends StringType
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'ddc2984_domain_user_id';
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return ! empty($value)
|
||||
? new DDC2984DomainUserId($value)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ( ! $value instanceof DDC2984DomainUserId) {
|
||||
throw ConversionException::conversionFailed($value, $this->getName());
|
||||
}
|
||||
|
||||
return $value->toString();
|
||||
}
|
||||
}
|
||||
90
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2996Test.php
Normal file
90
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2996Test.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
|
||||
/**
|
||||
* @group DDC-2996
|
||||
*/
|
||||
class DDC2996Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function testIssue()
|
||||
{
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2996User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC2996UserPreference'),
|
||||
));
|
||||
|
||||
$pref = new DDC2996UserPreference();
|
||||
$pref->user = new DDC2996User();
|
||||
$pref->value = "foo";
|
||||
|
||||
$this->_em->persist($pref);
|
||||
$this->_em->persist($pref->user);
|
||||
$this->_em->flush();
|
||||
|
||||
$pref->value = "bar";
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertEquals(1, $pref->user->counter);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$pref = $this->_em->find(__NAMESPACE__ . '\\DDC2996UserPreference', $pref->id);
|
||||
$this->assertEquals(1, $pref->user->counter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC2996User
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
public $counter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity @HasLifecycleCallbacks
|
||||
*/
|
||||
class DDC2996UserPreference
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC2996User")
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @PreFlush
|
||||
*/
|
||||
public function preFlush($event)
|
||||
{
|
||||
$em = $event->getEntityManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
|
||||
if ($uow->getOriginalEntityData($this->user)) {
|
||||
$this->user->counter++;
|
||||
$uow->recomputeSingleEntityChangeSet(
|
||||
$em->getClassMetadata(get_class($this->user)),
|
||||
$this->user
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
137
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3033Test.php
Normal file
137
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3033Test.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
|
||||
/**
|
||||
* @group DDC-3033
|
||||
*/
|
||||
class DDC3033Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function testIssue()
|
||||
{
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC3033User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC3033Product'),
|
||||
));
|
||||
|
||||
$user = new DDC3033User();
|
||||
$user->name = "Test User";
|
||||
$this->_em->persist($user);
|
||||
|
||||
$user2 = new DDC3033User();
|
||||
$user2->name = "Test User 2";
|
||||
$this->_em->persist($user2);
|
||||
|
||||
$product = new DDC3033Product();
|
||||
$product->title = "Test product";
|
||||
$product->buyers[] = $user;
|
||||
|
||||
$this->_em->persist($product);
|
||||
$this->_em->flush();
|
||||
|
||||
$product->title = "Test Change title";
|
||||
$product->buyers[] = $user2;
|
||||
|
||||
$this->_em->persist($product);
|
||||
$this->_em->flush();
|
||||
|
||||
$expect = array(
|
||||
'title' => array(
|
||||
0 => 'Test product',
|
||||
1 => 'Test Change title',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEquals($expect, $product->changeSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Table
|
||||
* @Entity @HasLifecycleCallbacks
|
||||
*/
|
||||
class DDC3033Product
|
||||
{
|
||||
public $changeSet = array();
|
||||
|
||||
/**
|
||||
* @var integer $id
|
||||
*
|
||||
* @Column(name="id", type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string $title
|
||||
*
|
||||
* @Column(name="title", type="string", length=255)
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC3033User")
|
||||
* @JoinTable(
|
||||
* name="user_purchases_3033",
|
||||
* joinColumns={@JoinColumn(name="product_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="user_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
public $buyers;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->buyers = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @PreUpdate
|
||||
*/
|
||||
public function preUpdate(LifecycleEventArgs $eventArgs)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @PostUpdate
|
||||
*/
|
||||
public function postUpdate(LifecycleEventArgs $eventArgs)
|
||||
{
|
||||
$em = $eventArgs->getEntityManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
$entity = $eventArgs->getEntity();
|
||||
$classMetadata = $em->getClassMetadata(get_class($entity));
|
||||
|
||||
$uow->computeChangeSet($classMetadata, $entity);
|
||||
$this->changeSet = $uow->getEntityChangeSet($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Table
|
||||
* @Entity @HasLifecycleCallbacks
|
||||
*/
|
||||
class DDC3033User
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*
|
||||
* @Column(name="id", type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @Column(name="title", type="string", length=255)
|
||||
*/
|
||||
public $name;
|
||||
}
|
||||
70
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3160Test.php
Normal file
70
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3160Test.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* FlushEventTest
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class DDC3160Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() {
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3160
|
||||
*/
|
||||
public function testNoUpdateOnInsert()
|
||||
{
|
||||
$listener = new DDC3160OnFlushListener();
|
||||
$this->_em->getEventManager()->addEventListener(Events::onFlush, $listener);
|
||||
|
||||
$user = new CmsUser;
|
||||
$user->username = 'romanb';
|
||||
$user->name = 'Roman';
|
||||
$user->status = 'Dev';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->refresh($user);
|
||||
|
||||
$this->assertEquals('romanc', $user->username);
|
||||
$this->assertEquals(1, $listener->inserts);
|
||||
$this->assertEquals(0, $listener->updates);
|
||||
}
|
||||
}
|
||||
|
||||
class DDC3160OnFlushListener
|
||||
{
|
||||
public $inserts = 0;
|
||||
public $updates = 0;
|
||||
|
||||
public function onFlush(OnFlushEventArgs $args)
|
||||
{
|
||||
$em = $args->getEntityManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
|
||||
foreach ($uow->getScheduledEntityInsertions() as $entity) {
|
||||
$this->inserts++;
|
||||
if ($entity instanceof CmsUser) {
|
||||
$entity->username = 'romanc';
|
||||
$cm = $em->getClassMetadata(get_class($entity));
|
||||
$uow->recomputeSingleEntityChangeSet($cm, $entity);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($uow->getScheduledEntityUpdates() as $entity) {
|
||||
$this->updates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class DDC742Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="users")
|
||||
* @Table(name="ddc742_users")
|
||||
*/
|
||||
class DDC742User
|
||||
{
|
||||
@@ -111,7 +111,7 @@ class DDC742User
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="comments")
|
||||
* @Table(name="ddc742_comments")
|
||||
*/
|
||||
class DDC742Comment
|
||||
{
|
||||
|
||||
@@ -1928,4 +1928,34 @@ class ObjectHydratorTest extends HydrationTestCase
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
|
||||
$hydrator->hydrateAll($stmt, $rsm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3076
|
||||
*
|
||||
* @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
|
||||
* @expectedExceptionMessage The discriminator value "subworker" is invalid. It must be one of "person", "manager", "employee".
|
||||
*/
|
||||
public function testInvalidDiscriminatorValueException()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyPerson', 'p');
|
||||
|
||||
$rsm->addFieldResult('p', 'p__id', 'id');
|
||||
$rsm->addFieldResult('p', 'p__name', 'name');
|
||||
$rsm->addMetaResult('p', 'discr', 'discr');
|
||||
$rsm->setDiscriminatorColumn('p', 'discr');
|
||||
|
||||
$resultSet = array(
|
||||
array(
|
||||
'p__id' => '1',
|
||||
'p__name' => 'Fabio B. Silva',
|
||||
'discr' => 'subworker'
|
||||
),
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
|
||||
$hydrator->hydrateAll($stmt, $rsm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,4 +58,34 @@ class SimpleObjectHydratorTest extends HydrationTestCase
|
||||
$result = $hydrator->hydrateAll($stmt, $rsm);
|
||||
$this->assertEquals($result[0], $expectedEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3076
|
||||
*
|
||||
* @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException
|
||||
* @expectedExceptionMessage The discriminator value "subworker" is invalid. It must be one of "person", "manager", "employee".
|
||||
*/
|
||||
public function testInvalidDiscriminatorValueException()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyPerson', 'p');
|
||||
|
||||
$rsm->addFieldResult('p', 'p__id', 'id');
|
||||
$rsm->addFieldResult('p', 'p__name', 'name');
|
||||
$rsm->addMetaResult('p', 'discr', 'discr');
|
||||
$rsm->setDiscriminatorColumn('p', 'discr');
|
||||
|
||||
$resultSet = array(
|
||||
array(
|
||||
'p__id' => '1',
|
||||
'p__name' => 'Fabio B. Silva',
|
||||
'discr' => 'subworker'
|
||||
),
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator($this->_em);
|
||||
$hydrator->hydrateAll($stmt, $rsm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1066,6 +1066,75 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals(array('customtypeparent_source' => 'id'), $cm->associationMappings['friendsWithMe']['relationToSourceKeyColumns']);
|
||||
$this->assertEquals(array('customtypeparent_target' => 'id'), $cm->associationMappings['friendsWithMe']['relationToTargetKeyColumns']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2608
|
||||
*/
|
||||
public function testSetSequenceGeneratorThrowsExceptionWhenSequenceNameIsMissing()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
|
||||
$cm->setSequenceGeneratorDefinition(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2662
|
||||
*/
|
||||
public function testQuotedSequenceName()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
$cm->setSequenceGeneratorDefinition(array('sequenceName' => '`foo`'));
|
||||
|
||||
$this->assertEquals(array('sequenceName' => 'foo', 'quoted' => true), $cm->sequenceGeneratorDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2700
|
||||
*/
|
||||
public function testIsIdentifierMappedSuperClass()
|
||||
{
|
||||
$class = new ClassMetadata(__NAMESPACE__ . '\\DDC2700MappedSuperClass');
|
||||
|
||||
$this->assertFalse($class->isIdentifier('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3120
|
||||
*/
|
||||
public function testCanInstantiateInternalPhpClassSubclass()
|
||||
{
|
||||
$classMetadata = new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity');
|
||||
|
||||
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3120
|
||||
*/
|
||||
public function testCanInstantiateInternalPhpClassSubclassFromUnserializedMetadata()
|
||||
{
|
||||
/* @var $classMetadata ClassMetadata */
|
||||
$classMetadata = unserialize(serialize(new ClassMetadata(__NAMESPACE__ . '\\MyArrayObjectEntity')));
|
||||
|
||||
$classMetadata->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\\MyArrayObjectEntity', $classMetadata->newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
class DDC2700MappedSuperClass
|
||||
{
|
||||
/** @Column */
|
||||
private $foo;
|
||||
}
|
||||
|
||||
class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
|
||||
@@ -1092,4 +1161,8 @@ class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
|
||||
{
|
||||
return strtolower($this->classToTableName($className)) . '_' . $propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyArrayObjectEntity extends \ArrayObject
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ $metadata->mapField(array(
|
||||
'fieldName' => 'id',
|
||||
'type' => 'integer',
|
||||
'columnName' => 'id',
|
||||
'options' => array('foo' => 'bar'),
|
||||
));
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'name',
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -16,6 +16,8 @@ Doctrine\Tests\ORM\Mapping\User:
|
||||
sequenceName: tablename_seq
|
||||
allocationSize: 100
|
||||
initialValue: 1
|
||||
options:
|
||||
foo: bar
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,12 +592,20 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @gorup DDC-1858
|
||||
* @group DDC-1858
|
||||
*/
|
||||
public function testHavingSupportIsNullExpression()
|
||||
{
|
||||
$this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u HAVING u.username IS NULL");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3018
|
||||
*/
|
||||
public function testNewLiteralExpression()
|
||||
{
|
||||
$this->assertValidDQL("SELECT new " . __NAMESPACE__ . "\\DummyStruct(u.id, 'foo', 1, true) FROM Doctrine\Tests\Models\CMS\CmsUser u");
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
@@ -617,3 +625,10 @@ class DQLKeywordsModelGroup
|
||||
/** @Column */
|
||||
private $from;
|
||||
}
|
||||
|
||||
class DummyStruct
|
||||
{
|
||||
public function __construct($id, $arg1, $arg2, $arg3)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
@@ -1982,11 +1993,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
$connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\SQLServerPlatform());
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
|
||||
"SELECT c0_.id AS id0 FROM cms_users c0_ WITH (NOLOCK) WHERE (c0_.name + c0_.status + 's') = ?"
|
||||
"SELECT c0_.id AS id0 FROM cms_users c0_ WHERE (c0_.name + c0_.status + 's') = ?"
|
||||
);
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT CONCAT(u.id, u.name, u.status) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1",
|
||||
"SELECT (c0_.id + c0_.name + c0_.status) AS sclr0 FROM cms_users c0_ WITH (NOLOCK) WHERE c0_.id = ?"
|
||||
"SELECT (c0_.id + c0_.name + c0_.status) AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?"
|
||||
);
|
||||
|
||||
$connMock->setDatabasePlatform($orgPlatform);
|
||||
@@ -2040,6 +2051,97 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2506
|
||||
*/
|
||||
public function testClassTableInheritanceJoinWithConditionAppliesToBaseTable()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e.id FROM Doctrine\Tests\Models\Company\CompanyOrganization o JOIN o.events e WITH e.id = ?1',
|
||||
'SELECT c0_.id AS id0 FROM company_organizations c1_ INNER JOIN company_events c0_ ON c1_.id = c0_.org_id AND (c0_.id = ?) LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceLeftJoinWithCondition()
|
||||
{
|
||||
// Regression test for the bug
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceLeftJoinWithConditionAndWhere()
|
||||
{
|
||||
// Ensure other WHERE predicates are passed through to the main WHERE clause
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id WHERE e.salary > 1000',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.salary > 1000"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceInnerJoinWithCondition()
|
||||
{
|
||||
// Test inner joins too
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e INNER JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id INNER JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceLeftJoinNonAssociationWithConditionAndWhere()
|
||||
{
|
||||
// Test that the discriminator IN() predicate is still added into
|
||||
// the where clause when not joining onto that table
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ LEFT JOIN company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceJoinCreatesOnCondition()
|
||||
{
|
||||
// Test that the discriminator IN() predicate is still added
|
||||
// into the where clause when not joining onto a single table inheritance entity
|
||||
// via a join association
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c JOIN c.salesPerson s WHERE c.completed = true',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2235
|
||||
*/
|
||||
public function testSingleTableInheritanceCreatesOnConditionAndWhere()
|
||||
{
|
||||
// Test that when joining onto an entity using single table inheritance via
|
||||
// a join association that the discriminator IN() predicate is placed
|
||||
// into the ON clause of the join
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e, COUNT(c) FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN e.contracts c WHERE e.department = :department',
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, COUNT(c2_.id) AS sclr5, c0_.discr AS discr6 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_contract_employees c3_ ON c1_.id = c3_.employee_id INNER JOIN company_contracts c2_ ON c2_.id = c3_.contract_id AND c2_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.department = ?",
|
||||
array(),
|
||||
array('department' => 'foobar')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1858
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -209,6 +209,27 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testExportDirectoryAndFilesAreCreated
|
||||
*/
|
||||
public function testFieldsAreProperlySerialized()
|
||||
{
|
||||
$type = $this->_getType();
|
||||
if ($type == 'xml') {
|
||||
$xml = simplexml_load_file(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.xml');
|
||||
|
||||
$xml->registerXPathNamespace("d", "http://doctrine-project.org/schemas/orm/doctrine-mapping");
|
||||
$nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:field[@name='name' and @type='string' and @nullable='true']");
|
||||
$this->assertEquals(1, count($nodes));
|
||||
|
||||
$nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:field[@name='name' and @type='string' and @unique='true']");
|
||||
$this->assertEquals(1, count($nodes));
|
||||
}
|
||||
else {
|
||||
$this->markTestSkipped('Test available only for '.$type.' driver');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testFieldsAreExported
|
||||
* @param ClassMetadataInfo $class
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
@@ -22,7 +25,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithSortPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
|
||||
@@ -39,7 +42,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithScalarSortPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'
|
||||
@@ -58,7 +61,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithMixedSortPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
|
||||
@@ -77,7 +80,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithHiddenScalarSortPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g, COUNT(g.id) AS hidden g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
|
||||
@@ -96,7 +99,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform);
|
||||
|
||||
$this->testLimitSubquery();
|
||||
|
||||
@@ -106,7 +109,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithSortOracle()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\OraclePlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
|
||||
@@ -124,7 +127,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithScalarSortOracle()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\OraclePlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'
|
||||
@@ -144,7 +147,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryWithMixedSortOracle()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\OraclePlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'
|
||||
@@ -164,7 +167,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
public function testLimitSubqueryOracle()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\OraclePlatform);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
|
||||
@@ -179,7 +182,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
$this->entityManager->getConnection()->setDatabasePlatform($odp);
|
||||
}
|
||||
|
||||
public function testCountQuery_MixedResultsWithName()
|
||||
public function testCountQueryMixedResultsWithName()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a');
|
||||
@@ -190,5 +193,40 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
"SELECT DISTINCT id0 FROM (SELECT a0_.id AS id0, a0_.name AS name1, sum(a0_.name) AS sclr2 FROM Author a0_) dctrn_result", $limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3336
|
||||
*/
|
||||
public function testCountQueryWithArithmeticOrderByCondition()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY (1 - 1000) * 1 DESC'
|
||||
);
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new MySqlPlatform());
|
||||
|
||||
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
|
||||
|
||||
$this->assertSame(
|
||||
'SELECT DISTINCT id0 FROM (SELECT a0_.id AS id0, a0_.name AS name1 FROM Author a0_ ORDER BY (1 - 1000) * 1 DESC) dctrn_result',
|
||||
$query->getSQL()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3434
|
||||
*/
|
||||
public function testLimitSubqueryWithHiddenSelectionInOrderBy()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a, a.name AS HIDDEN ord FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY ord DESC'
|
||||
);
|
||||
|
||||
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
|
||||
|
||||
$this->assertEquals(
|
||||
'SELECT DISTINCT id0, name2 FROM (SELECT a0_.id AS id0, a0_.name AS name1, a0_.name AS name2 FROM Author a0_ ORDER BY name2 DESC) dctrn_result ORDER BY name2 DESC',
|
||||
$query->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
abstract class PaginationTestCase extends OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
public $entityManager;
|
||||
|
||||
public function setUp()
|
||||
|
||||
@@ -101,6 +101,23 @@ class SchemaToolTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals(count($classes), $listener->tableCalls);
|
||||
$this->assertTrue($listener->schemaCalled);
|
||||
}
|
||||
|
||||
public function testNullDefaultNotAddedToCustomSchemaOptions()
|
||||
{
|
||||
$em = $this->_getTestEntityManager();
|
||||
$schemaTool = new SchemaTool($em);
|
||||
|
||||
$classes = array(
|
||||
$em->getClassMetadata('Doctrine\Tests\Models\NullDefault\NullDefaultColumn'),
|
||||
);
|
||||
|
||||
$customSchemaOptions = $schemaTool->getSchemaFromMetadata($classes)
|
||||
->getTable('NullDefaultColumn')
|
||||
->getColumn('nullDefault')
|
||||
->getCustomSchemaOptions();
|
||||
|
||||
$this->assertSame(array(), $customSchemaOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user