mirror of
https://github.com/doctrine/orm.git
synced 2026-04-29 09:23:20 +02:00
Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 29d6da0fa0 | |||
| 69fe5c48f4 | |||
| 8e1111c8d3 | |||
| e4bccdc7b3 | |||
| 06ed21e883 | |||
| 5635fa60a4 | |||
| 4d93a4950b | |||
| a91050e7f4 | |||
| 20e5d98b7b | |||
| 2f6e914d64 | |||
| 457036aacb | |||
| 2ce72f38a2 | |||
| 1cff8b4d98 | |||
| a165f63c8c | |||
| eaf8fd3c34 | |||
| 70427871ce | |||
| 2879162015 | |||
| 3b92cfac5a | |||
| 53c9ffda30 | |||
| 647c5e2cad | |||
| 3555007f08 | |||
| 523697d0b6 | |||
| 1382d766b0 | |||
| c743bb938b | |||
| 3340234785 | |||
| a39ceb3159 | |||
| 6ff5043ce8 | |||
| 1a958f70fd | |||
| 184e8eb26c | |||
| 7903a2b513 | |||
| 52b3fc1fc3 | |||
| 09d67b10b0 | |||
| 37d7df6ac4 | |||
| 3488049c18 | |||
| a66fc03441 | |||
| 37e7e841c3 | |||
| f2f1d8986c | |||
| 7eb744126b | |||
| f16c8e3efe | |||
| 6ef48561ba | |||
| 0a90279a99 | |||
| a1355d0bb9 | |||
| 6937061b23 | |||
| c1e688fc81 | |||
| d961028b14 | |||
| d685f592fe | |||
| b15758bb42 | |||
| 3d86c82a7f | |||
| 0d834d0bd4 | |||
| 0248f743ba | |||
| ed7a4bdcf3 | |||
| 529064aff2 | |||
| 4e99c5c127 | |||
| 462173ad71 | |||
| 710d0d1109 | |||
| 4ef043fc3b | |||
| afb9c829e2 | |||
| 9bea612d74 | |||
| 77b905eaa8 | |||
| 5c7b98b2a9 | |||
| 424793c263 | |||
| 753d63c2d4 | |||
| 27511374ec | |||
| 3d6436c2f3 | |||
| a986fe013e | |||
| 4e8b787d07 | |||
| c64c149ebf | |||
| f269ecc3ac | |||
| 7af84e79e5 | |||
| e54c11e3bb | |||
| 786d904328 | |||
| 3e8796f781 |
@@ -0,0 +1,4 @@
|
||||
# for php-coveralls
|
||||
service_name: travis-ci
|
||||
src_dir: lib
|
||||
coverage_clover: build/logs/clover.xml
|
||||
+4
-4
@@ -5,9 +5,6 @@ php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: 5.5
|
||||
env:
|
||||
- DB=mysql
|
||||
- DB=pgsql
|
||||
@@ -19,6 +16,9 @@ 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
|
||||
|
||||
after_script:
|
||||
- php vendor/bin/coveralls -v
|
||||
|
||||
@@ -5,6 +5,11 @@ Master: [](http://travis-ci.org/doctrine/doctrine2)
|
||||
2.1: [](http://travis-ci.org/doctrine/doctrine2)
|
||||
|
||||
Master: [](https://coveralls.io/r/doctrine/doctrine2?branch=master)
|
||||
|
||||
[](https://packagist.org/packages/doctrine/orm) [](https://packagist.org/packages/doctrine/orm)
|
||||
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
|
||||
|
||||
+1
-9
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
+8
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"type": "library","version":"2.4.0-RC1",
|
||||
"type": "library",
|
||||
"description": "Object-Relational-Mapper for PHP",
|
||||
"keywords": ["orm", "database"],
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
@@ -11,16 +11,16 @@
|
||||
{"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": {
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
@@ -33,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"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ In order to work, this requires certain conventions:
|
||||
convention and you are not forced to do this. You can change the
|
||||
file extension easily enough.
|
||||
|
||||
-
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -47,9 +45,9 @@ Simplified YAML Driver
|
||||
The Symfony project sponsored a driver that simplifies usage of the YAML Driver.
|
||||
The changes between the original driver are:
|
||||
|
||||
1. File Extension is .orm.yml
|
||||
2. Filenames are shortened, "MyProject\Entities\User" will become User.orm.yml
|
||||
3. You can add a global file and add multiple entities in this file.
|
||||
- File Extension is .orm.yml
|
||||
- Filenames are shortened, "MyProject\\Entities\\User" will become User.orm.yml
|
||||
- You can add a global file and add multiple entities in this file.
|
||||
|
||||
Configuration of this client works a little bit different:
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ The code of this tutorial is `available on Github <https://github.com/doctrine/d
|
||||
|
||||
.. note::
|
||||
|
||||
This tutorial assumes you work with Doctrine 2.3 and above.
|
||||
This tutorial assumes you work with Doctrine 2.4 and above.
|
||||
Some of the code will not work with lower versions.
|
||||
|
||||
What is Doctrine?
|
||||
@@ -187,9 +187,7 @@ doctrine command. Its a fairly simple file:
|
||||
// cli-config.php
|
||||
require_once "bootstrap.php";
|
||||
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($entityManager)
|
||||
));
|
||||
return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
|
||||
|
||||
You can then change into your project directory and call the
|
||||
Doctrine command-line tool:
|
||||
@@ -1110,10 +1108,10 @@ the first read-only use-case:
|
||||
|
||||
foreach($bugs AS $bug) {
|
||||
echo $bug->getDescription()." - ".$bug->getCreated()->format('d.m.Y')."\n";
|
||||
echo " Reported by: ".$bug->getReporter()->name."\n";
|
||||
echo " Assigned to: ".$bug->getEngineer()->name."\n";
|
||||
echo " Reported by: ".$bug->getReporter()->getName()."\n";
|
||||
echo " Assigned to: ".$bug->getEngineer()->getName()."\n";
|
||||
foreach($bug->getProducts() AS $product) {
|
||||
echo " Platform: ".$product->name."\n";
|
||||
echo " Platform: ".$product->getName()."\n";
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -19,20 +19,22 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
|
||||
use Doctrine\ORM\Mapping\NamingStrategy;
|
||||
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
|
||||
use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
|
||||
use Doctrine\Common\Annotations\SimpleAnnotationReader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use Doctrine\Common\Annotations\CachedReader;
|
||||
use Doctrine\Common\Annotations\SimpleAnnotationReader;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
|
||||
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
|
||||
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
use Doctrine\ORM\Mapping\NamingStrategy;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
|
||||
/**
|
||||
* Configuration container for all configuration options of Doctrine.
|
||||
@@ -779,4 +781,28 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
return $this->_attributes['entityListenerResolver'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the entity repository factory.
|
||||
*
|
||||
* @since 2.4
|
||||
* @param \Doctrine\ORM\Repository\RepositoryFactory $repositoryFactory
|
||||
*/
|
||||
public function setRepositoryFactory(RepositoryFactory $repositoryFactory)
|
||||
{
|
||||
$this->_attributes['repositoryFactory'] = $repositoryFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity repository factory.
|
||||
*
|
||||
* @since 2.4
|
||||
* @return \Doctrine\ORM\Repository\RepositoryFactory
|
||||
*/
|
||||
public function getRepositoryFactory()
|
||||
{
|
||||
return isset($this->_attributes['repositoryFactory'])
|
||||
? $this->_attributes['repositoryFactory']
|
||||
: new DefaultRepositoryFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +85,6 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
*/
|
||||
private $metadataFactory;
|
||||
|
||||
/**
|
||||
* The EntityRepository instances.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $repositories = array();
|
||||
|
||||
/**
|
||||
* The UnitOfWork used to coordinate object-level transactions.
|
||||
*
|
||||
@@ -106,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.
|
||||
*
|
||||
@@ -120,6 +106,13 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
*/
|
||||
private $proxyFactory;
|
||||
|
||||
/**
|
||||
* The repository factory used to create dynamic repositories.
|
||||
*
|
||||
* @var \Doctrine\ORM\Repository\RepositoryFactory
|
||||
*/
|
||||
private $repositoryFactory;
|
||||
|
||||
/**
|
||||
* The expression builder instance used to generate query expressions.
|
||||
*
|
||||
@@ -151,9 +144,9 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
*/
|
||||
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
|
||||
@@ -161,8 +154,9 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
$this->metadataFactory->setEntityManager($this);
|
||||
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
||||
|
||||
$this->unitOfWork = new UnitOfWork($this);
|
||||
$this->proxyFactory = new ProxyFactory(
|
||||
$this->repositoryFactory = $config->getRepositoryFactory();
|
||||
$this->unitOfWork = new UnitOfWork($this);
|
||||
$this->proxyFactory = new ProxyFactory(
|
||||
$this,
|
||||
$config->getProxyDir(),
|
||||
$config->getProxyNamespace(),
|
||||
@@ -758,28 +752,11 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
*
|
||||
* @param string $entityName The name of the entity.
|
||||
*
|
||||
* @return EntityRepository The repository class.
|
||||
* @return \Doctrine\ORM\EntityRepository The repository class.
|
||||
*/
|
||||
public function getRepository($entityName)
|
||||
{
|
||||
$entityName = ltrim($entityName, '\\');
|
||||
|
||||
if (isset($this->repositories[$entityName])) {
|
||||
return $this->repositories[$entityName];
|
||||
}
|
||||
|
||||
$metadata = $this->getClassMetadata($entityName);
|
||||
$repositoryClassName = $metadata->customRepositoryClassName;
|
||||
|
||||
if ($repositoryClassName === null) {
|
||||
$repositoryClassName = $this->config->getDefaultRepositoryClassName();
|
||||
}
|
||||
|
||||
$repository = new $repositoryClassName($this, $metadata);
|
||||
|
||||
$this->repositories[$entityName] = $repository;
|
||||
|
||||
return $repository;
|
||||
return $this->repositoryFactory->getRepository($this, $entityName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -856,17 +833,15 @@ use Doctrine\Common\Util\ClassUtils;
|
||||
* This method caches the hydrator instances which is used for all queries that don't
|
||||
* selectively iterate over the result.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
*/
|
||||
public function getHydrator($hydrationMode)
|
||||
{
|
||||
if ( ! isset($this->hydrators[$hydrationMode])) {
|
||||
$this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode);
|
||||
}
|
||||
|
||||
return $this->hydrators[$hydrationMode];
|
||||
return $this->newHydrator($hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)];
|
||||
|
||||
|
||||
@@ -114,9 +114,8 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
// Convert field to a valid PHP value
|
||||
if (isset($cache[$column]['field'])) {
|
||||
$type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']);
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
if (isset($cache[$column]['type'])) {
|
||||
$value = Type::getType($cache[$column]['type'])->convertToPHPValue($value, $this->_platform);
|
||||
}
|
||||
|
||||
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||
@@ -145,44 +144,36 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
*/
|
||||
protected function hydrateColumnInfo($entityName, $column)
|
||||
{
|
||||
switch (true) {
|
||||
case (isset($this->_rsm->fieldMappings[$column])):
|
||||
$class = isset($this->declaringClasses[$column])
|
||||
? $this->declaringClasses[$column]
|
||||
: $this->class;
|
||||
|
||||
// If class is not part of the inheritance, ignore
|
||||
if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) {
|
||||
return null;
|
||||
}
|
||||
if (isset($this->_rsm->fieldMappings[$column])) {
|
||||
$name = $this->_rsm->fieldMappings[$column];
|
||||
$class = isset($this->declaringClasses[$column])
|
||||
? $this->declaringClasses[$column]
|
||||
: $this->class;
|
||||
|
||||
return array(
|
||||
'class' => $class,
|
||||
'name' => $this->_rsm->fieldMappings[$column],
|
||||
'field' => true,
|
||||
);
|
||||
|
||||
case (isset($this->_rsm->relationMap[$column])):
|
||||
$class = isset($this->_rsm->relationMap[$column])
|
||||
? $this->_rsm->relationMap[$column]
|
||||
: $this->class;
|
||||
|
||||
// If class is not self referencing, ignore
|
||||
if ( ! ($class === $entityName || is_subclass_of($entityName, $class))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Decide what to do with associations. It seems original code is incomplete.
|
||||
// One solution is to load the association, but it might require extra efforts.
|
||||
return array('name' => $column);
|
||||
|
||||
case (isset($this->_rsm->metaMappings[$column])):
|
||||
return array(
|
||||
'name' => $this->_rsm->metaMappings[$column]
|
||||
);
|
||||
|
||||
default:
|
||||
// If class is not part of the inheritance, ignore
|
||||
if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array(
|
||||
'name' => $name,
|
||||
'type' => $class->fieldMappings[$name]['type']
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($this->_rsm->metaMappings[$column])) {
|
||||
return array(
|
||||
'name' => $this->_rsm->metaMappings[$column],
|
||||
'type' => (isset($this->_rsm->typeMappings[$column]) ? $this->_rsm->typeMappings[$column] : null)
|
||||
);
|
||||
}
|
||||
|
||||
// An ObjectHydrator should be used instead of SimpleObjectHydrator
|
||||
if (isset($this->_rsm->relationMap[$column])) {
|
||||
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
/**
|
||||
* ANSI compliant quote strategy, this strategy does not apply any quote.
|
||||
* To use this strategy all mapped tables and columns should be ANSI compliant.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class AnsiQuoteStrategy implements QuoteStrategy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $class->fieldMappings[$fieldName]['columnName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $class->table['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $definition['sequenceName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $joinColumn['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $joinColumn['referencedColumnName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $association['joinTable']['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
return $class->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
|
||||
{
|
||||
return $platform->getSQLResultCasing($columnName . $counter);
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* - <b>scale</b> (integer, optional, schema-only)
|
||||
* The scale of a decimal column. Only valid if the column type is decimal.
|
||||
*
|
||||
[* - <b>'unique'] (string, optional, schema-only)</b>
|
||||
* - <b>'unique'</b> (string, optional, schema-only)
|
||||
* Whether a unique constraint should be generated for the column.
|
||||
*
|
||||
* @var array
|
||||
@@ -2790,8 +2790,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;
|
||||
}
|
||||
|
||||
@@ -3026,4 +3030,18 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
return $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMetadataValue($name) {
|
||||
|
||||
if (isset($this->$name)) {
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
@@ -84,249 +87,15 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager.
|
||||
* Set the namespace for the generated entities.
|
||||
*
|
||||
* @param array $entityTables
|
||||
* @param array $manyToManyTables
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTables($entityTables, $manyToManyTables)
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
foreach ($entityTables as $table) {
|
||||
$className = $this->getClassNameForTable($table->getName());
|
||||
$this->classToTableNames[$className] = $table->getName();
|
||||
$this->tables[$table->getName()] = $table;
|
||||
}
|
||||
foreach ($manyToManyTables as $table) {
|
||||
$this->manyToManyTables[$table->getName()] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\Mapping\MappingException
|
||||
*/
|
||||
private function reverseEngineerMappingFromDatabase()
|
||||
{
|
||||
if ($this->tables !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
foreach ($tables as $tableName => $table) {
|
||||
/* @var $table \Doctrine\DBAL\Schema\Table */
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $table->getForeignKeys();
|
||||
} else {
|
||||
$foreignKeys = array();
|
||||
}
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
if ( ! $table->hasPrimaryKey()) {
|
||||
throw new MappingException(
|
||||
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
|
||||
"support reverse engineering from tables that don't have a primary key."
|
||||
);
|
||||
}
|
||||
|
||||
$pkColumns = $table->getPrimaryKey()->getColumns();
|
||||
sort($pkColumns);
|
||||
sort($allForeignKeyColumns);
|
||||
|
||||
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
|
||||
$this->manyToManyTables[$tableName] = $table;
|
||||
} else {
|
||||
// lower-casing is necessary because of Oracle Uppercase Tablenames,
|
||||
// assumption is lower-case + underscore separated.
|
||||
$className = $this->getClassNameForTable($tableName);
|
||||
$this->tables[$tableName] = $table;
|
||||
$this->classToTableNames[$className] = $tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if (!isset($this->classToTableNames[$className])) {
|
||||
throw new \InvalidArgumentException("Unknown class " . $className);
|
||||
}
|
||||
|
||||
$tableName = $this->classToTableNames[$className];
|
||||
|
||||
$metadata->name = $className;
|
||||
$metadata->table['name'] = $tableName;
|
||||
|
||||
$columns = $this->tables[$tableName]->getColumns();
|
||||
$indexes = $this->tables[$tableName]->getIndexes();
|
||||
try {
|
||||
$primaryKeyColumns = $this->tables[$tableName]->getPrimaryKey()->getColumns();
|
||||
} catch(SchemaException $e) {
|
||||
$primaryKeyColumns = array();
|
||||
}
|
||||
|
||||
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
|
||||
} else {
|
||||
$foreignKeys = array();
|
||||
}
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
$fieldMappings = array();
|
||||
foreach ($columns as $column) {
|
||||
$fieldMapping = array();
|
||||
|
||||
if (in_array($column->getName(), $allForeignKeyColumns)) {
|
||||
continue;
|
||||
} else if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
|
||||
$fieldMapping['id'] = true;
|
||||
}
|
||||
|
||||
$fieldMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $column->getName(), false);
|
||||
$fieldMapping['columnName'] = $column->getName();
|
||||
$fieldMapping['type'] = strtolower((string) $column->getType());
|
||||
|
||||
if ($column->getType() instanceof \Doctrine\DBAL\Types\StringType) {
|
||||
$fieldMapping['length'] = $column->getLength();
|
||||
$fieldMapping['fixed'] = $column->getFixed();
|
||||
} else if ($column->getType() instanceof \Doctrine\DBAL\Types\IntegerType) {
|
||||
$fieldMapping['unsigned'] = $column->getUnsigned();
|
||||
}
|
||||
$fieldMapping['nullable'] = $column->getNotNull() ? false : true;
|
||||
|
||||
if (isset($fieldMapping['id'])) {
|
||||
$ids[] = $fieldMapping;
|
||||
} else {
|
||||
$fieldMappings[] = $fieldMapping;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ids) {
|
||||
// We need to check for the columns here, because we might have associations as id as well.
|
||||
if (count($primaryKeyColumns) == 1) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$metadata->mapField($id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fieldMappings as $fieldMapping) {
|
||||
$metadata->mapField($fieldMapping);
|
||||
}
|
||||
|
||||
foreach ($this->manyToManyTables as $manyTable) {
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
// foreign key maps to the table of the current entity, many to many association probably exists
|
||||
if (strtolower($tableName) == strtolower($foreignKey->getForeignTableName())) {
|
||||
$myFk = $foreignKey;
|
||||
$otherFk = null;
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
if ($foreignKey != $myFk) {
|
||||
$otherFk = $foreignKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$otherFk) {
|
||||
// the definition of this many to many table does not contain
|
||||
// enough foreign key information to continue reverse engineering.
|
||||
continue;
|
||||
}
|
||||
|
||||
$localColumn = current($myFk->getColumns());
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName());
|
||||
if (current($manyTable->getColumns())->getName() == $localColumn) {
|
||||
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
$associationMapping['joinTable'] = array(
|
||||
'name' => strtolower($manyTable->getName()),
|
||||
'joinColumns' => array(),
|
||||
'inverseJoinColumns' => array(),
|
||||
);
|
||||
|
||||
$fkCols = $myFk->getForeignColumns();
|
||||
$cols = $myFk->getColumns();
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
$fkCols = $otherFk->getForeignColumns();
|
||||
$cols = $otherFk->getColumns();
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['inverseJoinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
}
|
||||
$metadata->mapManyToMany($associationMapping);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$foreignTable = $foreignKey->getForeignTableName();
|
||||
$cols = $foreignKey->getColumns();
|
||||
$fkCols = $foreignKey->getForeignColumns();
|
||||
|
||||
$localColumn = current($cols);
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $localColumn, true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($foreignTable);
|
||||
|
||||
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
|
||||
$associationMapping['fieldName'] = $associationMapping['fieldName'] . "2";
|
||||
}
|
||||
|
||||
if ($primaryKeyColumns && in_array($localColumn, $primaryKeyColumns)) {
|
||||
$associationMapping['id'] = true;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
//Here we need to check if $cols are the same as $primaryKeyColumns
|
||||
if (!array_diff($cols,$primaryKeyColumns)) {
|
||||
$metadata->mapOneToOne($associationMapping);
|
||||
} else {
|
||||
$metadata->mapManyToOne($associationMapping);
|
||||
}
|
||||
}
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,6 +143,376 @@ class DatabaseDriver implements MappingDriver
|
||||
$this->fieldNamesForColumns[$tableName][$columnName] = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tables manually instead of relying on the reverse engineering capabilities of SchemaManager.
|
||||
*
|
||||
* @param array $entityTables
|
||||
* @param array $manyToManyTables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTables($entityTables, $manyToManyTables)
|
||||
{
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
|
||||
foreach ($entityTables as $table) {
|
||||
$className = $this->getClassNameForTable($table->getName());
|
||||
|
||||
$this->classToTableNames[$className] = $table->getName();
|
||||
$this->tables[$table->getName()] = $table;
|
||||
}
|
||||
|
||||
foreach ($manyToManyTables as $table) {
|
||||
$this->manyToManyTables[$table->getName()] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if ( ! isset($this->classToTableNames[$className])) {
|
||||
throw new \InvalidArgumentException("Unknown class " . $className);
|
||||
}
|
||||
|
||||
$tableName = $this->classToTableNames[$className];
|
||||
|
||||
$metadata->name = $className;
|
||||
$metadata->table['name'] = $tableName;
|
||||
|
||||
$this->buildIndexes($metadata);
|
||||
$this->buildFieldMappings($metadata);
|
||||
$this->buildToOneAssociationMappings($metadata);
|
||||
|
||||
foreach ($this->manyToManyTables as $manyTable) {
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
// foreign key maps to the table of the current entity, many to many association probably exists
|
||||
if ( ! (strtolower($tableName) === strtolower($foreignKey->getForeignTableName()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$myFk = $foreignKey;
|
||||
$otherFk = null;
|
||||
|
||||
foreach ($manyTable->getForeignKeys() as $foreignKey) {
|
||||
if ($foreignKey != $myFk) {
|
||||
$otherFk = $foreignKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $otherFk) {
|
||||
// the definition of this many to many table does not contain
|
||||
// enough foreign key information to continue reverse engineering.
|
||||
continue;
|
||||
}
|
||||
|
||||
$localColumn = current($myFk->getColumns());
|
||||
|
||||
$associationMapping = array();
|
||||
$associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true);
|
||||
$associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName());
|
||||
|
||||
if (current($manyTable->getColumns())->getName() == $localColumn) {
|
||||
$associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
$associationMapping['joinTable'] = array(
|
||||
'name' => strtolower($manyTable->getName()),
|
||||
'joinColumns' => array(),
|
||||
'inverseJoinColumns' => array(),
|
||||
);
|
||||
|
||||
$fkCols = $myFk->getForeignColumns();
|
||||
$cols = $myFk->getColumns();
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['joinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
|
||||
$fkCols = $otherFk->getForeignColumns();
|
||||
$cols = $otherFk->getColumns();
|
||||
|
||||
for ($i = 0; $i < count($cols); $i++) {
|
||||
$associationMapping['joinTable']['inverseJoinColumns'][] = array(
|
||||
'name' => $cols[$i],
|
||||
'referencedColumnName' => $fkCols[$i],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true);
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($associationMapping);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\Mapping\MappingException
|
||||
*/
|
||||
private function reverseEngineerMappingFromDatabase()
|
||||
{
|
||||
if ($this->tables !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = array();
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
|
||||
|
||||
foreach ($tables as $tableName => $table) {
|
||||
$foreignKeys = ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
|
||||
? $table->getForeignKeys()
|
||||
: array();
|
||||
|
||||
$allForeignKeyColumns = array();
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
if ( ! $table->hasPrimaryKey()) {
|
||||
throw new MappingException(
|
||||
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
|
||||
"support reverse engineering from tables that don't have a primary key."
|
||||
);
|
||||
}
|
||||
|
||||
$pkColumns = $table->getPrimaryKey()->getColumns();
|
||||
|
||||
sort($pkColumns);
|
||||
sort($allForeignKeyColumns);
|
||||
|
||||
if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
|
||||
$this->manyToManyTables[$tableName] = $table;
|
||||
} else {
|
||||
// lower-casing is necessary because of Oracle Uppercase Tablenames,
|
||||
// assumption is lower-case + underscore separated.
|
||||
$className = $this->getClassNameForTable($tableName);
|
||||
|
||||
$this->tables[$tableName] = $table;
|
||||
$this->classToTableNames[$className] = $tableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build indexes from a class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildIndexes(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$indexes = $this->tables[$tableName]->getIndexes();
|
||||
|
||||
foreach($indexes as $index){
|
||||
if ($index->isPrimary()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$indexName = $index->getName();
|
||||
$indexColumns = $index->getColumns();
|
||||
$constraintType = $index->isUnique()
|
||||
? 'uniqueConstraints'
|
||||
: 'indexes';
|
||||
|
||||
$metadata->table[$constraintType][$indexName]['columns'] = $indexColumns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build field mapping from class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildFieldMappings(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$columns = $this->tables[$tableName]->getColumns();
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
$allForeignKeys = array();
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$allForeignKeys = array_merge($allForeignKeys, $foreignKey->getLocalColumns());
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
$fieldMappings = array();
|
||||
|
||||
foreach ($columns as $column) {
|
||||
if (in_array($column->getName(), $allForeignKeys)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldMapping = $this->buildFieldMapping($tableName, $column);
|
||||
|
||||
if ($primaryKeys && in_array($column->getName(), $primaryKeys)) {
|
||||
$fieldMapping['id'] = true;
|
||||
$ids[] = $fieldMapping;
|
||||
}
|
||||
|
||||
$fieldMappings[] = $fieldMapping;
|
||||
}
|
||||
|
||||
// We need to check for the columns here, because we might have associations as id as well.
|
||||
if ($ids && count($primaryKeys) == 1) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
foreach ($fieldMappings as $fieldMapping) {
|
||||
$metadata->mapField($fieldMapping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build field mapping from a schema column definition
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param \Doctrine\DBAL\Schema\Column $column
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function buildFieldMapping($tableName, Column $column)
|
||||
{
|
||||
$fieldMapping = array(
|
||||
'fieldName' => $this->getFieldNameForColumn($tableName, $column->getName(), false),
|
||||
'columnName' => $column->getName(),
|
||||
'type' => strtolower((string) $column->getType()),
|
||||
'nullable' => ( ! $column->getNotNull()),
|
||||
);
|
||||
|
||||
// Type specific elements
|
||||
switch ($fieldMapping['type']) {
|
||||
case Type::TARRAY:
|
||||
case Type::BLOB:
|
||||
case Type::GUID:
|
||||
case Type::JSON_ARRAY:
|
||||
case Type::OBJECT:
|
||||
case Type::SIMPLE_ARRAY:
|
||||
case Type::STRING:
|
||||
case Type::TEXT:
|
||||
$fieldMapping['length'] = $column->getLength();
|
||||
$fieldMapping['fixed'] = $column->getFixed();
|
||||
break;
|
||||
|
||||
case Type::DECIMAL:
|
||||
case Type::FLOAT:
|
||||
$fieldMapping['precision'] = $column->getPrecision();
|
||||
$fieldMapping['scale'] = $column->getScale();
|
||||
break;
|
||||
|
||||
case Type::INTEGER:
|
||||
case Type::BIGINT:
|
||||
case Type::SMALLINT:
|
||||
$fieldMapping['unsigned'] = $column->getUnsigned();
|
||||
break;
|
||||
}
|
||||
|
||||
// Comment
|
||||
if (($comment = $column->getComment()) !== null) {
|
||||
$fieldMapping['comment'] = $comment;
|
||||
}
|
||||
|
||||
// Default
|
||||
if (($default = $column->getDefault()) !== null) {
|
||||
$fieldMapping['default'] = $default;
|
||||
}
|
||||
|
||||
return $fieldMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build to one (one to one, many to one) association mapping from class metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata
|
||||
*/
|
||||
private function buildToOneAssociationMappings(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$tableName = $metadata->table['name'];
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$foreignTableName = $foreignKey->getForeignTableName();
|
||||
$fkColumns = $foreignKey->getColumns();
|
||||
$fkForeignColumns = $foreignKey->getForeignColumns();
|
||||
$localColumn = current($fkColumns);
|
||||
$associationMapping = array(
|
||||
'fieldName' => $this->getFieldNameForColumn($tableName, $localColumn, true),
|
||||
'targetEntity' => $this->getClassNameForTable($foreignTableName),
|
||||
);
|
||||
|
||||
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
|
||||
$associationMapping['fieldName'] .= '2'; // "foo" => "foo2"
|
||||
}
|
||||
|
||||
if ($primaryKeys && in_array($localColumn, $primaryKeys)) {
|
||||
$associationMapping['id'] = true;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($fkColumns); $i++) {
|
||||
$associationMapping['joinColumns'][] = array(
|
||||
'name' => $fkColumns[$i],
|
||||
'referencedColumnName' => $fkForeignColumns[$i],
|
||||
);
|
||||
}
|
||||
|
||||
// Here we need to check if $fkColumns are the same as $primaryKeys
|
||||
if ( ! array_diff($fkColumns, $primaryKeys)) {
|
||||
$metadata->mapOneToOne($associationMapping);
|
||||
} else {
|
||||
$metadata->mapManyToOne($associationMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive schema table definition foreign keys.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Schema\Table $table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTableForeignKeys(Table $table)
|
||||
{
|
||||
return ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints())
|
||||
? $table->getForeignKeys()
|
||||
: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive schema table definition primary keys.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Schema\Table $table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTablePrimaryKeys(Table $table)
|
||||
{
|
||||
try {
|
||||
return $table->getPrimaryKey()->getColumns();
|
||||
} catch(SchemaException $e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version.
|
||||
*
|
||||
@@ -413,16 +552,4 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
return Inflector::camelize($columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace for the generated entities.
|
||||
*
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -517,6 +517,18 @@ final class PersistentCollection implements Collection, Selectable
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
if ( ! $this->initialized
|
||||
&& $this->association['type'] === Mapping\ClassMetadataInfo::ONE_TO_MANY
|
||||
&& $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
|
||||
&& isset($this->association['indexBy'])
|
||||
) {
|
||||
if (!$this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->association['indexBy'])) {
|
||||
return $this->em->find($this->typeClass->name, $key);
|
||||
}
|
||||
|
||||
return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key);
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
|
||||
return $this->coll->get($key);
|
||||
@@ -745,6 +757,8 @@ final class PersistentCollection implements Collection, Selectable
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
return $this->coll->key();
|
||||
}
|
||||
|
||||
@@ -753,6 +767,8 @@ final class PersistentCollection implements Collection, Selectable
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
return $this->coll->current();
|
||||
}
|
||||
|
||||
@@ -761,6 +777,8 @@ final class PersistentCollection implements Collection, Selectable
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
return $this->coll->next();
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
@@ -1334,16 +1334,22 @@ class BasicEntityPersister
|
||||
return '';
|
||||
}
|
||||
|
||||
$columnList = array();
|
||||
$columnList = array();
|
||||
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
foreach ($assoc['joinColumns'] as $joinColumn) {
|
||||
|
||||
$type = null;
|
||||
$isIdentifier = isset($assoc['id']) && $assoc['id'] === true;
|
||||
$quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
|
||||
$resultColumnName = $this->getSQLColumnAlias($joinColumn['name']);
|
||||
$columnList[] = $this->getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $quotedColumn . ' AS ' . $resultColumnName;
|
||||
|
||||
$this->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
if (isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$type = $targetClass->fieldMappings[$targetClass->fieldNames[$joinColumn['referencedColumnName']]]['type'];
|
||||
}
|
||||
|
||||
$this->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type);
|
||||
}
|
||||
|
||||
return implode(', ', $columnList);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,24 @@ use Doctrine\ORM\UnitOfWork;
|
||||
*/
|
||||
class OneToManyPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
public function get(PersistentCollection $coll, $index)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
$persister = $uow->getEntityPersister($mapping['targetEntity']);
|
||||
|
||||
if (!isset($mapping['indexBy'])) {
|
||||
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
||||
}
|
||||
|
||||
return $persister->load(array($mapping['mappedBy'] => $coll->getOwner(), $mapping['indexBy'] => $index), null, null, array(), 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the SQL UPDATE that updates a particular row's foreign
|
||||
* key to null.
|
||||
|
||||
@@ -66,6 +66,7 @@ class SqlExpressionVisitor extends ExpressionVisitor
|
||||
$value = $comparison->getValue()->getValue(); // shortcut for walkValue()
|
||||
|
||||
if (isset($this->classMetadata->associationMappings[$field]) &&
|
||||
$value !== null &&
|
||||
! is_object($value) &&
|
||||
! in_array($comparison->getOperator(), array(Comparison::IN, Comparison::NIN))) {
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\ParserResult;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ParameterTypeInferer;
|
||||
|
||||
/**
|
||||
* A Query object represents a DQL query.
|
||||
@@ -268,6 +270,10 @@ final class Query extends AbstractQuery
|
||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||
}
|
||||
|
||||
if ($this->_resultSetMapping === null) {
|
||||
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
$paramMappings = $this->_parserResult->getParameterMappings();
|
||||
|
||||
@@ -277,10 +283,6 @@ final class Query extends AbstractQuery
|
||||
|
||||
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
||||
|
||||
if ($this->_resultSetMapping === null) {
|
||||
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
||||
}
|
||||
|
||||
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
||||
}
|
||||
|
||||
@@ -299,16 +301,21 @@ final class Query extends AbstractQuery
|
||||
$types = array();
|
||||
|
||||
foreach ($this->parameters as $parameter) {
|
||||
$key = $parameter->getName();
|
||||
$key = $parameter->getName();
|
||||
$value = $parameter->getValue();
|
||||
|
||||
if ( ! isset($paramMappings[$key])) {
|
||||
throw QueryException::unknownParameter($key);
|
||||
}
|
||||
|
||||
$value = $this->processParameterValue($parameter->getValue());
|
||||
if (isset($this->_resultSetMapping->metadataParameterMapping[$key]) && $value instanceof ClassMetadata) {
|
||||
$value = $value->getMetadataValue($this->_resultSetMapping->metadataParameterMapping[$key]);
|
||||
}
|
||||
|
||||
$value = $this->processParameterValue($value);
|
||||
$type = ($parameter->getValue() === $value)
|
||||
? $parameter->getType()
|
||||
: Query\ParameterTypeInferer::inferType($value);
|
||||
: ParameterTypeInferer::inferType($value);
|
||||
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$types[$position] = $type;
|
||||
|
||||
@@ -82,7 +82,10 @@ class IdentityFunction extends FunctionNode
|
||||
}
|
||||
}
|
||||
|
||||
$tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
//The table with the relation may be a subclass, so get the table name from the association definition
|
||||
$tableName = $sqlWalker->getEntityManager()->getClassMetadata($assoc['sourceEntity'])->getTableName();
|
||||
|
||||
$tableAlias = $sqlWalker->getSQLTableAlias($tableName, $dqlAlias);
|
||||
$columnName = $quoteStrategy->getJoinColumnName($joinColumn, $targetEntity, $platform);
|
||||
|
||||
return $tableAlias . '.' . $columnName;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -670,6 +670,12 @@ class Parser
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($class->associationMappings[$field]) &&
|
||||
$class->associationMappings[$field]['isOwningSide'] &&
|
||||
$class->associationMappings[$field]['type'] & ClassMetadata::TO_ONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->semanticalError(
|
||||
"There is no mapped field named '$field' on class " . $class->name . ".", $deferredItem['token']
|
||||
);
|
||||
@@ -1538,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();
|
||||
|
||||
@@ -1616,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();
|
||||
|
||||
@@ -153,6 +153,13 @@ class ResultSetMapping
|
||||
*/
|
||||
public $newObjectMappings = array();
|
||||
|
||||
/**
|
||||
* Maps metadata parameter names to the metadata attribute.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $metadataParameterMapping = array();
|
||||
|
||||
/**
|
||||
* Adds an entity result to this ResultSetMapping.
|
||||
*
|
||||
@@ -371,6 +378,17 @@ class ResultSetMapping
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a metadata parameter mappings.
|
||||
*
|
||||
* @param mixed $parameter The parameter name in the SQL result set.
|
||||
* @param string $attribute The metadata attribute.
|
||||
*/
|
||||
public function addMetadataParameterMapping($parameter, $attribute)
|
||||
{
|
||||
$this->metadataParameterMapping[$parameter] = $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a column with a given name is mapped as a scalar result.
|
||||
*
|
||||
@@ -525,14 +543,15 @@ class ResultSetMapping
|
||||
/**
|
||||
* Adds a meta column (foreign key or discriminator column) to the result set.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param string $columnName
|
||||
* @param string $fieldName
|
||||
* @param string $alias The result alias with which the meta result should be placed in the result structure.
|
||||
* @param string $columnName The name of the column in the SQL result set.
|
||||
* @param string $fieldName The name of the field on the declaring class.
|
||||
* @param bool $isIdentifierColumn
|
||||
* @param string $type The column type
|
||||
*
|
||||
* @return ResultSetMapping This ResultSetMapping instance.
|
||||
*/
|
||||
public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn = false)
|
||||
public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn = false, $type = null)
|
||||
{
|
||||
$this->metaMappings[$columnName] = $fieldName;
|
||||
$this->columnOwnerMap[$columnName] = $alias;
|
||||
@@ -541,6 +560,10 @@ class ResultSetMapping
|
||||
$this->isIdentifierColumn[$alias][$columnName] = true;
|
||||
}
|
||||
|
||||
if ($type) {
|
||||
$this->typeMappings[$columnName] = $type;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\OptimisticLockException;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
/**
|
||||
@@ -117,6 +118,13 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
private $scalarResultAliasMap = array();
|
||||
|
||||
/**
|
||||
* Map from Table-Alias + Column-Name to OrderBy-Direction.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $orderedColumnsMap = array();
|
||||
|
||||
/**
|
||||
* Map from DQL-Alias + Field-Name to SQL Column Alias.
|
||||
*
|
||||
@@ -388,25 +396,36 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
private function _generateOrderedCollectionOrderByItems()
|
||||
{
|
||||
$sqlParts = array();
|
||||
$orderedColumns = array();
|
||||
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
$dqlAlias = $selectedClass['dqlAlias'];
|
||||
$qComp = $this->queryComponents[$dqlAlias];
|
||||
$dqlAlias = $selectedClass['dqlAlias'];
|
||||
$qComp = $this->queryComponents[$dqlAlias];
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name);
|
||||
|
||||
if ( ! isset($qComp['relation']['orderBy'])) continue;
|
||||
if ( ! isset($qComp['relation']['orderBy'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($qComp['relation']['orderBy'] as $fieldName => $orientation) {
|
||||
$columnName = $this->quoteStrategy->getColumnName($fieldName, $qComp['metadata'], $this->platform);
|
||||
$tableName = ($qComp['metadata']->isInheritanceTypeJoined())
|
||||
? $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name)->getOwningTable($fieldName)
|
||||
? $persister->getOwningTable($fieldName)
|
||||
: $qComp['metadata']->getTableName();
|
||||
|
||||
$sqlParts[] = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName . ' ' . $orientation;
|
||||
$orderedColumn = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName;
|
||||
|
||||
// OrderByClause should replace an ordered relation. see - DDC-2475
|
||||
if (isset($this->orderedColumnsMap[$orderedColumn])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->orderedColumnsMap[$orderedColumn] = $orientation;
|
||||
$orderedColumns[] = $orderedColumn . ' ' . $orientation;
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $sqlParts);
|
||||
return implode(', ', $orderedColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,44 +514,52 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkSelectStatement(AST\SelectStatement $AST)
|
||||
{
|
||||
$sql = $this->walkSelectClause($AST->selectClause);
|
||||
$sql .= $this->walkFromClause($AST->fromClause);
|
||||
$sql .= $this->walkWhereClause($AST->whereClause);
|
||||
$sql .= $AST->groupByClause ? $this->walkGroupByClause($AST->groupByClause) : '';
|
||||
$sql .= $AST->havingClause ? $this->walkHavingClause($AST->havingClause) : '';
|
||||
$limit = $this->query->getMaxResults();
|
||||
$offset = $this->query->getFirstResult();
|
||||
$lockMode = $this->query->getHint(Query::HINT_LOCK_MODE);
|
||||
$sql = $this->walkSelectClause($AST->selectClause)
|
||||
. $this->walkFromClause($AST->fromClause)
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
|
||||
if (($orderByClause = $AST->orderByClause) !== null) {
|
||||
$sql .= $AST->orderByClause ? $this->walkOrderByClause($AST->orderByClause) : '';
|
||||
} else if (($orderBySql = $this->_generateOrderedCollectionOrderByItems()) !== '') {
|
||||
if ($AST->groupByClause) {
|
||||
$sql .= $this->walkGroupByClause($AST->groupByClause);
|
||||
}
|
||||
|
||||
if ($AST->havingClause) {
|
||||
$sql .= $this->walkHavingClause($AST->havingClause);
|
||||
}
|
||||
|
||||
if ($AST->orderByClause) {
|
||||
$sql .= $this->walkOrderByClause($AST->orderByClause);
|
||||
}
|
||||
|
||||
if ( ! $AST->orderByClause && ($orderBySql = $this->_generateOrderedCollectionOrderByItems())) {
|
||||
$sql .= ' ORDER BY ' . $orderBySql;
|
||||
}
|
||||
|
||||
$sql = $this->platform->modifyLimitQuery(
|
||||
$sql, $this->query->getMaxResults(), $this->query->getFirstResult()
|
||||
);
|
||||
if ($limit !== null || $offset !== null) {
|
||||
$sql = $this->platform->modifyLimitQuery($sql, $limit, $offset);
|
||||
}
|
||||
|
||||
if (($lockMode = $this->query->getHint(Query::HINT_LOCK_MODE)) !== false) {
|
||||
switch ($lockMode) {
|
||||
case LockMode::PESSIMISTIC_READ:
|
||||
$sql .= ' ' . $this->platform->getReadLockSQL();
|
||||
break;
|
||||
if ($lockMode === false || $lockMode === LockMode::NONE) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
case LockMode::PESSIMISTIC_WRITE:
|
||||
$sql .= ' ' . $this->platform->getWriteLockSQL();
|
||||
break;
|
||||
if ($lockMode === LockMode::PESSIMISTIC_READ) {
|
||||
return $sql . ' ' . $this->platform->getReadLockSQL();
|
||||
}
|
||||
|
||||
case LockMode::OPTIMISTIC:
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
if ( ! $selectedClass['class']->isVersioned) {
|
||||
throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LockMode::NONE:
|
||||
break;
|
||||
if ($lockMode === LockMode::PESSIMISTIC_WRITE) {
|
||||
return $sql . ' ' . $this->platform->getWriteLockSQL();
|
||||
}
|
||||
|
||||
default:
|
||||
throw \Doctrine\ORM\Query\QueryException::invalidLockMode();
|
||||
if ($lockMode !== LockMode::OPTIMISTIC) {
|
||||
throw QueryException::invalidLockMode();
|
||||
}
|
||||
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
if ( ! $selectedClass['class']->isVersioned) {
|
||||
throw OptimisticLockException::lockFailed($selectedClass['class']->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,10 +842,12 @@ class SqlWalker implements TreeWalker
|
||||
$class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
|
||||
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
|
||||
$this->rootAliases[] = $dqlAlias;
|
||||
if ($rangeVariableDeclaration->isRoot) {
|
||||
$this->rootAliases[] = $dqlAlias;
|
||||
}
|
||||
|
||||
$sql = $class->getQuotedTableName($this->platform) . ' '
|
||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
$sql = $this->quoteStrategy->getTableName($class,$this->platform) . ' '
|
||||
. $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
if ($class->isInheritanceTypeJoined()) {
|
||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
||||
@@ -831,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 = '';
|
||||
|
||||
@@ -848,7 +878,7 @@ class SqlWalker implements TreeWalker
|
||||
$relation = $this->queryComponents[$joinedDqlAlias]['relation'];
|
||||
$targetClass = $this->em->getClassMetadata($relation['targetEntity']);
|
||||
$sourceClass = $this->em->getClassMetadata($relation['sourceEntity']);
|
||||
$targetTableName = $targetClass->getQuotedTableName($this->platform);
|
||||
$targetTableName = $this->quoteStrategy->getTableName($targetClass,$this->platform);
|
||||
|
||||
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias);
|
||||
$sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable);
|
||||
@@ -903,7 +933,7 @@ class SqlWalker implements TreeWalker
|
||||
// Join relation table
|
||||
$joinTable = $assoc['joinTable'];
|
||||
$joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias);
|
||||
$joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->platform);
|
||||
$joinTableName = $this->quoteStrategy->getJoinTableName($assoc, $sourceClass, $this->platform);
|
||||
|
||||
$conditions = array();
|
||||
$relationColumns = ($relation['isOwningSide'])
|
||||
@@ -952,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);
|
||||
@@ -998,12 +1035,15 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkOrderByItem($orderByItem)
|
||||
{
|
||||
$type = strtoupper($orderByItem->type);
|
||||
$expr = $orderByItem->expression;
|
||||
$sql = ($expr instanceof AST\Node)
|
||||
? $expr->dispatch($this)
|
||||
: $this->walkResultVariable($this->queryComponents[$expr]['token']['value']);
|
||||
|
||||
return $sql . ' ' . strtoupper($orderByItem->type);
|
||||
$this->orderedColumnsMap[$sql] = $type;
|
||||
|
||||
return $sql . ' ' . $type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1028,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;
|
||||
}
|
||||
|
||||
@@ -1942,24 +1995,31 @@ class SqlWalker implements TreeWalker
|
||||
$sqlParameterList = array();
|
||||
|
||||
foreach ($instanceOfExpr->value as $parameter) {
|
||||
|
||||
if ($parameter instanceof AST\InputParameter) {
|
||||
|
||||
$this->rsm->addMetadataParameterMapping($parameter->name, 'discriminatorValue');
|
||||
|
||||
$sqlParameterList[] = $this->walkInputParameter($parameter);
|
||||
} else {
|
||||
// Get name from ClassMetadata to resolve aliases.
|
||||
$entityClassName = $this->em->getClassMetadata($parameter)->name;
|
||||
|
||||
if ($entityClassName == $class->name) {
|
||||
$sqlParameterList[] = $this->conn->quote($class->discriminatorValue);
|
||||
} else {
|
||||
$discrMap = array_flip($class->discriminatorMap);
|
||||
|
||||
if (!isset($discrMap[$entityClassName])) {
|
||||
throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName);
|
||||
}
|
||||
|
||||
$sqlParameterList[] = $this->conn->quote($discrMap[$entityClassName]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get name from ClassMetadata to resolve aliases.
|
||||
$entityClassName = $this->em->getClassMetadata($parameter)->name;
|
||||
$discriminatorValue = $class->discriminatorValue;
|
||||
|
||||
if ($entityClassName !== $class->name) {
|
||||
$discrMap = array_flip($class->discriminatorMap);
|
||||
|
||||
if ( ! isset($discrMap[$entityClassName])) {
|
||||
throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName);
|
||||
}
|
||||
|
||||
$discriminatorValue = $discrMap[$entityClassName];
|
||||
}
|
||||
|
||||
$sqlParameterList[] = $this->conn->quote($discriminatorValue);
|
||||
}
|
||||
|
||||
$sql .= '(' . implode(', ', $sqlParameterList) . ')';
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* This factory is used to create default repository objects for entities at runtime.
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.4
|
||||
*/
|
||||
class DefaultRepositoryFactory implements RepositoryFactory
|
||||
{
|
||||
/**
|
||||
* The list of EntityRepository instances.
|
||||
*
|
||||
* @var array<\Doctrine\Common\Persistence\ObjectRepository>
|
||||
*/
|
||||
private $repositoryList = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRepository(EntityManagerInterface $entityManager, $entityName)
|
||||
{
|
||||
$entityName = ltrim($entityName, '\\');
|
||||
|
||||
if (isset($this->repositoryList[$entityName])) {
|
||||
return $this->repositoryList[$entityName];
|
||||
}
|
||||
|
||||
$repository = $this->createRepository($entityManager, $entityName);
|
||||
|
||||
$this->repositoryList[$entityName] = $repository;
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new repository instance for an entity class.
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $entityManager The EntityManager instance.
|
||||
* @param string $entityName The name of the entity.
|
||||
*
|
||||
* @return \Doctrine\Common\Persistence\ObjectRepository
|
||||
*/
|
||||
protected function createRepository(EntityManagerInterface $entityManager, $entityName)
|
||||
{
|
||||
$metadata = $entityManager->getClassMetadata($entityName);
|
||||
$repositoryClassName = $metadata->customRepositoryClassName;
|
||||
|
||||
if ($repositoryClassName === null) {
|
||||
$configuration = $entityManager->getConfiguration();
|
||||
$repositoryClassName = $configuration->getDefaultRepositoryClassName();
|
||||
}
|
||||
|
||||
return new $repositoryClassName($entityManager, $metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Interface for entity repository factory.
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.4
|
||||
*/
|
||||
interface RepositoryFactory
|
||||
{
|
||||
/**
|
||||
* Gets the repository for an entity class.
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $entityManager The EntityManager instance.
|
||||
* @param string $entityName The name of the entity.
|
||||
*
|
||||
* @return \Doctrine\Common\Persistence\ObjectRepository
|
||||
*/
|
||||
public function getRepository(EntityManagerInterface $entityManager, $entityName);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ EOT
|
||||
$force = true === $input->getOption('force');
|
||||
|
||||
if ($dumpSql) {
|
||||
$output->writeln(implode(';' . PHP_EOL, $sqls));
|
||||
$output->writeln(implode(';' . PHP_EOL, $sqls) . ';');
|
||||
}
|
||||
|
||||
if ($force) {
|
||||
@@ -138,7 +138,7 @@ EOT
|
||||
if ($dumpSql || $force) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
$output->writeln('<comment>ATTENTION</comment>: This operation should not be executed in a production environment.');
|
||||
$output->writeln(' Use the incremental update to detect changes during development and use');
|
||||
$output->writeln(' the SQL DDL provided to manually update your database in production.');
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -92,7 +92,25 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$innerSql = parent::walkSelectStatement($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);
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
Regular → Executable
+22
-4
@@ -121,7 +121,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
/* @var $countQuery Query */
|
||||
$countQuery = $this->cloneQuery($this->query);
|
||||
|
||||
if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
|
||||
if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) {
|
||||
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
|
||||
$countQuery->setResultSetMapping($rsm);
|
||||
} else {
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$this->appendTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker');
|
||||
}
|
||||
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
@@ -165,7 +165,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
if ($this->useOutputWalker($subQuery)) {
|
||||
$subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
|
||||
} else {
|
||||
$subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
|
||||
$this->appendTreeWalker($subQuery, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker');
|
||||
}
|
||||
|
||||
$subQuery->setFirstResult($offset)->setMaxResults($length);
|
||||
@@ -178,7 +178,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
return new \ArrayIterator(array());
|
||||
}
|
||||
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$this->appendTreeWalker($whereInQuery, 'Doctrine\ORM\Tools\Pagination\WhereInWalker');
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, count($ids));
|
||||
$whereInQuery->setFirstResult(null)->setMaxResults(null);
|
||||
$whereInQuery->setParameter(WhereInWalker::PAGINATOR_ID_ALIAS, $ids);
|
||||
@@ -231,4 +231,22 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
|
||||
return $this->useOutputWalkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a custom tree walker to the tree walkers hint.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param string $walkerClass
|
||||
*/
|
||||
private function appendTreeWalker(Query $query, $walkerClass)
|
||||
{
|
||||
$hints = $query->getHint(Query::HINT_CUSTOM_TREE_WALKERS);
|
||||
|
||||
if ($hints === false) {
|
||||
$hints = array();
|
||||
}
|
||||
|
||||
$hints[] = $walkerClass;
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class SchemaValidator
|
||||
if ($assoc['mappedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association, but as field.";
|
||||
}
|
||||
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
@@ -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.";
|
||||
}
|
||||
|
||||
@@ -2356,6 +2356,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->readOnlyObjects =
|
||||
$this->visitedCollections =
|
||||
$this->orphanRemovals = array();
|
||||
|
||||
if ($this->commitOrderCalculator !== null) {
|
||||
@@ -2773,6 +2774,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection);
|
||||
break;
|
||||
}
|
||||
|
||||
$collection->setInitialized(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.4.0-RC1';
|
||||
const VERSION = '2.4.1';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
|
||||
class DatabaseDriverTest extends DatabaseDriverTestCase
|
||||
{
|
||||
@@ -145,4 +146,70 @@ class DatabaseDriverTest extends DatabaseDriverTestCase
|
||||
|
||||
$this->assertEquals(0, count($metadatas['DbdriverBaz']->associationMappings), "no association mappings should be detected.");
|
||||
}
|
||||
|
||||
public function testLoadMetadataFromDatabaseDetail()
|
||||
{
|
||||
if ( ! $this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Platform does not support foreign keys.');
|
||||
}
|
||||
|
||||
$table = new \Doctrine\DBAL\Schema\Table("dbdriver_foo");
|
||||
|
||||
$table->addColumn('id', 'integer', array('unsigned' => true));
|
||||
$table->setPrimaryKey(array('id'));
|
||||
$table->addColumn('column_unsigned', 'integer', array('unsigned' => true));
|
||||
$table->addColumn('column_comment', 'string', array('comment' => 'test_comment'));
|
||||
$table->addColumn('column_default', 'string', array('default' => 'test_default'));
|
||||
$table->addColumn('column_decimal', 'decimal', array('precision' => 4, 'scale' => 3));
|
||||
|
||||
$table->addColumn('column_index1', 'string');
|
||||
$table->addColumn('column_index2', 'string');
|
||||
$table->addIndex(array('column_index1','column_index2'), 'index1');
|
||||
|
||||
$table->addColumn('column_unique_index1', 'string');
|
||||
$table->addColumn('column_unique_index2', 'string');
|
||||
$table->addUniqueIndex(array('column_unique_index1', 'column_unique_index2'), 'unique_index1');
|
||||
|
||||
$this->_sm->dropAndCreateTable($table);
|
||||
|
||||
$metadatas = $this->extractClassMetadata(array("DbdriverFoo"));
|
||||
|
||||
$this->assertArrayHasKey('DbdriverFoo', $metadatas);
|
||||
|
||||
$metadata = $metadatas['DbdriverFoo'];
|
||||
|
||||
$this->assertArrayHasKey('id', $metadata->fieldMappings);
|
||||
$this->assertEquals('id', $metadata->fieldMappings['id']['fieldName']);
|
||||
$this->assertEquals('id', strtolower($metadata->fieldMappings['id']['columnName']));
|
||||
$this->assertEquals('integer', (string) $metadata->fieldMappings['id']['type']);
|
||||
|
||||
// FIXME: Condition here is fugly.
|
||||
// NOTE: PostgreSQL does not support UNSIGNED
|
||||
if ( ! $this->_em->getConnection()->getDatabasePlatform() instanceof PostgreSqlPlatform) {
|
||||
$this->assertArrayHasKey('columnUnsigned', $metadata->fieldMappings);
|
||||
$this->assertTrue($metadata->fieldMappings['columnUnsigned']['unsigned']);
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey('columnComment', $metadata->fieldMappings);
|
||||
$this->assertEquals('test_comment', $metadata->fieldMappings['columnComment']['comment']);
|
||||
|
||||
$this->assertArrayHasKey('columnDefault', $metadata->fieldMappings);
|
||||
$this->assertEquals('test_default', $metadata->fieldMappings['columnDefault']['default']);
|
||||
|
||||
$this->assertArrayHasKey('columnDecimal', $metadata->fieldMappings);
|
||||
$this->assertEquals(4, $metadata->fieldMappings['columnDecimal']['precision']);
|
||||
$this->assertEquals(3, $metadata->fieldMappings['columnDecimal']['scale']);
|
||||
|
||||
$this->assertTrue( ! empty($metadata->table['indexes']['index1']['columns']));
|
||||
$this->assertEquals(
|
||||
array('column_index1','column_index2'),
|
||||
$metadata->table['indexes']['index1']['columns']
|
||||
);
|
||||
|
||||
$this->assertTrue( ! empty($metadata->table['uniqueConstraints']['unique_index1']['columns']));
|
||||
$this->assertEquals(
|
||||
array('column_unique_index1', 'column_unique_index2'),
|
||||
$metadata->table['uniqueConstraints']['unique_index1']['columns']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,6 +842,35 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2478
|
||||
*/
|
||||
public function testMatchingCriteriaNullAssocComparison()
|
||||
{
|
||||
$fixtures = $this->loadFixtureUserEmail();
|
||||
$user = $this->_em->merge($fixtures[0]);
|
||||
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$criteriaIsNull = Criteria::create()->where(Criteria::expr()->isNull('email'));
|
||||
$criteriaEqNull = Criteria::create()->where(Criteria::expr()->eq('email', null));
|
||||
|
||||
$user->setEmail(null);
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$usersIsNull = $repository->matching($criteriaIsNull);
|
||||
$usersEqNull = $repository->matching($criteriaEqNull);
|
||||
|
||||
$this->assertCount(1, $usersIsNull);
|
||||
$this->assertCount(1, $usersEqNull);
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $usersIsNull[0]);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $usersEqNull[0]);
|
||||
|
||||
$this->assertNull($usersIsNull[0]->getEmail());
|
||||
$this->assertNull($usersEqNull[0]->getEmail());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2055
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
private $groupId;
|
||||
private $articleId;
|
||||
|
||||
private $topic;
|
||||
private $phonenumber;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
@@ -24,7 +27,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
$class->associationMappings['groups']['indexBy'] = 'name';
|
||||
$class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
$class->associationMappings['articles']['indexBy'] = 'topic';
|
||||
$class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
$class->associationMappings['phonenumbers']['indexBy'] = 'phonenumber';
|
||||
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
@@ -39,6 +46,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
|
||||
$class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
|
||||
$class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
|
||||
|
||||
unset($class->associationMappings['groups']['indexBy']);
|
||||
unset($class->associationMappings['articles']['indexBy']);
|
||||
unset($class->associationMappings['phonenumbers']['indexBy']);
|
||||
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
|
||||
@@ -174,8 +186,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
|
||||
$this->assertEquals(2, count($someGroups));
|
||||
$this->assertTrue($user->groups->contains($someGroups[0]));
|
||||
$this->assertTrue($user->groups->contains($someGroups[1]));
|
||||
$this->assertTrue($user->groups->contains(array_shift($someGroups)));
|
||||
$this->assertTrue($user->groups->contains(array_shift($someGroups)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,6 +524,52 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($qc + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1398
|
||||
*/
|
||||
public function testGetIndexByIdentifier()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
/* @var $user CmsUser */
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$phonenumber = $user->phonenumbers->get($this->phonenumber);
|
||||
|
||||
$this->assertFalse($user->phonenumbers->isInitialized());
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
$this->assertSame($phonenumber, $this->_em->find('Doctrine\Tests\Models\CMS\CmsPhonenumber', $this->phonenumber));
|
||||
|
||||
$article = $user->phonenumbers->get($this->phonenumber);
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1398
|
||||
*/
|
||||
public function testGetIndexByOneToMany()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
/* @var $user CmsUser */
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$article = $user->articles->get($this->topic);
|
||||
|
||||
$this->assertFalse($user->articles->isInitialized());
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
$this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1398
|
||||
*/
|
||||
public function testGetNonExistentIndexBy()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertNull($user->articles->get(-1));
|
||||
}
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||
@@ -561,23 +619,35 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->persist($group3);
|
||||
|
||||
$article1 = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article1->topic = "Test";
|
||||
$article1->text = "Test";
|
||||
$article1->topic = "Test1";
|
||||
$article1->text = "Test1";
|
||||
$article1->setAuthor($user1);
|
||||
|
||||
$article2 = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article2->topic = "Test";
|
||||
$article2->text = "Test";
|
||||
$article2->topic = "Test2";
|
||||
$article2->text = "Test2";
|
||||
$article2->setAuthor($user1);
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
|
||||
$phonenumber1 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber();
|
||||
$phonenumber1->phonenumber = '12345';
|
||||
|
||||
$phonenumber2 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber();
|
||||
$phonenumber2->phonenumber = '67890';
|
||||
|
||||
$this->_em->persist($phonenumber1);
|
||||
$this->_em->persist($phonenumber2);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->articleId = $article1->id;
|
||||
$this->userId = $user1->getId();
|
||||
$this->groupId = $group1->id;
|
||||
|
||||
$this->topic = $article1->topic;
|
||||
$this->phonenumber = $phonenumber1->phonenumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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']
|
||||
);
|
||||
|
||||
@@ -139,6 +139,18 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertTrue($query->getParameters()->isEmpty());
|
||||
}
|
||||
|
||||
public function testQueryWalkerIsKept()
|
||||
{
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\Tests\ORM\Functional\CustomPaginationTestTreeWalker'));
|
||||
|
||||
$paginator = new Paginator($query, true);
|
||||
$paginator->setUseOutputWalkers(false);
|
||||
$this->assertCount(1, $paginator->getIterator());
|
||||
$this->assertEquals(1, $paginator->count());
|
||||
}
|
||||
|
||||
public function populate()
|
||||
{
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
@@ -166,3 +178,22 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CustomPaginationTestTreeWalker extends Query\TreeWalkerAdapter
|
||||
{
|
||||
public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
|
||||
{
|
||||
$condition = new Query\AST\ConditionalPrimary();
|
||||
|
||||
$path = new Query\AST\PathExpression(Query\AST\PathExpression::TYPE_STATE_FIELD, 'u', 'name');
|
||||
$path->type = Query\AST\PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
$condition->simpleConditionalExpression = new Query\AST\ComparisonExpression(
|
||||
$path,
|
||||
'=',
|
||||
new Query\AST\Literal(Query\AST\Literal::STRING, 'Name1')
|
||||
);
|
||||
|
||||
$selectStatement->whereClause = new Query\AST\WhereClause($condition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\Company\CompanyPerson;
|
||||
use Doctrine\Tests\Models\Company\CompanyEmployee;
|
||||
|
||||
/**
|
||||
* @group DDC-1995
|
||||
*/
|
||||
class DDC1995Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('company');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$person = new CompanyPerson;
|
||||
$person->setName('p1');
|
||||
|
||||
$employee = new CompanyEmployee;
|
||||
$employee->setName('Foo');
|
||||
$employee->setDepartment('bar');
|
||||
$employee->setSalary(1000);
|
||||
|
||||
$this->_em->persist($person);
|
||||
$this->_em->persist($employee);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = 'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1';
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee');
|
||||
|
||||
$result = $this->_em->createQuery($dql)
|
||||
->setParameter(1, $class)
|
||||
->getResult();
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[0]);
|
||||
}
|
||||
|
||||
public function testQueryCache()
|
||||
{
|
||||
$person = new CompanyPerson;
|
||||
$person->setName('p1');
|
||||
|
||||
$employee = new CompanyEmployee;
|
||||
$employee->setName('Foo');
|
||||
$employee->setDepartment('bar');
|
||||
$employee->setSalary(1000);
|
||||
|
||||
$this->_em->persist($person);
|
||||
$this->_em->persist($employee);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = 'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF :type';
|
||||
$class1 = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee');
|
||||
$class2 = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyPerson');
|
||||
|
||||
$result1 = $this->_em->createQuery($dql)
|
||||
->setParameter('type', $class1)
|
||||
->useQueryCache(true)
|
||||
->getResult();
|
||||
|
||||
$result2 = $this->_em->createQuery($dql)
|
||||
->setParameter('type', $class2)
|
||||
->useQueryCache(true)
|
||||
->getResult();
|
||||
|
||||
$this->assertCount(1, $result1);
|
||||
$this->assertCount(1, $result2);
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result1[0]);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result2[0]);
|
||||
$this->assertNotInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result2[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* Verifies that the type of parameters being bound to an SQL query is the same
|
||||
* of the identifier of the entities used as parameters in the DQL query, even
|
||||
* if the bound objects are proxies.
|
||||
*
|
||||
* @author Marco Pivetta <ocramius@gmail.com>
|
||||
*
|
||||
* @group DDC-2214
|
||||
*/
|
||||
class DDC2214Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2214Foo'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2214Bar'),
|
||||
));
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$foo = new DDC2214Foo();
|
||||
$bar = new DDC2214Bar();
|
||||
|
||||
$foo->bar = $bar;
|
||||
|
||||
$this->_em->persist($foo);
|
||||
$this->_em->persist($bar);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
/* @var $foo \Doctrine\Tests\ORM\Functional\Ticket\DDC2214Foo */
|
||||
$foo = $this->_em->find(__NAMESPACE__ . '\\DDC2214Foo', $foo->id);
|
||||
$bar = $foo->bar;
|
||||
|
||||
$logger = $this->_em->getConnection()->getConfiguration()->getSQLLogger();
|
||||
|
||||
$related = $this
|
||||
->_em
|
||||
->createQuery('SELECT b FROM '.__NAMESPACE__ . '\DDC2214Bar b WHERE b.id IN(:ids)')
|
||||
->setParameter('ids', array($bar))
|
||||
->getResult();
|
||||
|
||||
$query = end($logger->queries);
|
||||
|
||||
$this->assertEquals(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY, $query['types'][0]);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class DDC2214Foo
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
|
||||
/** @ManyToOne(targetEntity="DDC2214Bar") */
|
||||
public $bar;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class DDC2214Bar
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group DDC-2350
|
||||
*/
|
||||
class DDC2350Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2350User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2350Bug'),
|
||||
));
|
||||
}
|
||||
|
||||
public function testEagerCollectionsAreOnlyRetrievedOnce()
|
||||
{
|
||||
$user = new DDC2350User();
|
||||
$bug1 = new DDC2350Bug();
|
||||
$bug1->user = $user;
|
||||
$bug2 = new DDC2350Bug();
|
||||
$bug2->user = $user;
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($bug1);
|
||||
$this->_em->persist($bug2);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$cnt = $this->getCurrentQueryCount();
|
||||
$user = $this->_em->find(__NAMESPACE__ . '\DDC2350User', $user->id);
|
||||
|
||||
$this->assertEquals($cnt + 2, $this->getCurrentQueryCount());
|
||||
|
||||
$this->assertEquals(2, count($user->reportedBugs));
|
||||
|
||||
$this->assertEquals($cnt + 2, $this->getCurrentQueryCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC2350User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
/** @OneToMany(targetEntity="DDC2350Bug", mappedBy="user", fetch="EAGER") */
|
||||
public $reportedBugs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC2350Bug
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
/** @ManyToOne(targetEntity="DDC2350User", inversedBy="reportedBugs") */
|
||||
public $user;
|
||||
}
|
||||
@@ -19,18 +19,21 @@ class DDC2359Test extends \PHPUnit_Framework_TestCase
|
||||
$mockDriver = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\Driver\\MappingDriver');
|
||||
$mockMetadata = $this->getMock('Doctrine\\ORM\\Mapping\\ClassMetadata', array(), array(), '', false);
|
||||
$entityManager = $this->getMock('Doctrine\\ORM\\EntityManager', array(), array(), '', false);
|
||||
|
||||
/* @var $metadataFactory \Doctrine\ORM\Mapping\ClassMetadataFactory|\PHPUnit_Framework_MockObject_MockObject */
|
||||
$metadataFactory = $this->getMock(
|
||||
'Doctrine\\ORM\\Mapping\\ClassMetadataFactory',
|
||||
array('newClassMetadataInstance', 'wakeupReflection')
|
||||
);
|
||||
$configuration = $this->getMock('Doctrine\\ORM\\Configuration');
|
||||
|
||||
$configuration = $this->getMock('Doctrine\\ORM\\Configuration', array('getMetadataDriverImpl'));
|
||||
$connection = $this->getMock('Doctrine\\DBAL\\Connection', array(), array(), '', false);
|
||||
|
||||
$configuration
|
||||
->expects($this->any())
|
||||
->method('getMetadataDriverImpl')
|
||||
->will($this->returnValue($mockDriver));
|
||||
|
||||
$entityManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($configuration));
|
||||
$entityManager->expects($this->any())->method('getConnection')->will($this->returnValue($connection));
|
||||
$entityManager
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
/**
|
||||
* @group DDC-2494
|
||||
*/
|
||||
class DDC2494Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
DDC2494TinyIntType::$calls = array();
|
||||
|
||||
Type::addType('ddc2494_tinyint', __NAMESPACE__ . '\DDC2494TinyIntType');
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(DDC2494Currency::CLASSNAME),
|
||||
$this->_em->getClassMetadata(DDC2494Campaign::CLASSNAME),
|
||||
));
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$currency = new DDC2494Currency(1, 2);
|
||||
|
||||
$this->_em->persist($currency);
|
||||
$this->_em->flush();
|
||||
|
||||
$campaign = new DDC2494Campaign($currency);
|
||||
|
||||
$this->_em->persist($campaign);
|
||||
$this->_em->flush();
|
||||
$this->_em->close();
|
||||
|
||||
$this->assertArrayHasKey('convertToDatabaseValue', DDC2494TinyIntType::$calls);
|
||||
$this->assertCount(3, DDC2494TinyIntType::$calls['convertToDatabaseValue']);
|
||||
|
||||
$item = $this->_em->find(DDC2494Campaign::CLASSNAME, $campaign->getId());
|
||||
|
||||
$this->assertInstanceOf(DDC2494Campaign::CLASSNAME, $item);
|
||||
$this->assertInstanceOf(DDC2494Currency::CLASSNAME, $item->getCurrency());
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$this->assertInstanceOf('\Doctrine\Common\Proxy\Proxy', $item->getCurrency());
|
||||
$this->assertFalse($item->getCurrency()->__isInitialized());
|
||||
|
||||
$this->assertArrayHasKey('convertToPHPValue', DDC2494TinyIntType::$calls);
|
||||
$this->assertCount(1, DDC2494TinyIntType::$calls['convertToPHPValue']);
|
||||
|
||||
$this->assertInternalType('integer', $item->getCurrency()->getId());
|
||||
$this->assertCount(1, DDC2494TinyIntType::$calls['convertToPHPValue']);
|
||||
$this->assertFalse($item->getCurrency()->__isInitialized());
|
||||
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount());
|
||||
|
||||
$this->assertInternalType('integer', $item->getCurrency()->getTemp());
|
||||
$this->assertCount(3, DDC2494TinyIntType::$calls['convertToPHPValue']);
|
||||
$this->assertTrue($item->getCurrency()->__isInitialized());
|
||||
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Table(name="ddc2494_currency")
|
||||
* @Entity
|
||||
*/
|
||||
class DDC2494Currency
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer", type="ddc2494_tinyint")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @Column(name="temp", type="ddc2494_tinyint", nullable=false)
|
||||
*/
|
||||
protected $temp;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Common\Collections\Collection
|
||||
*
|
||||
* @OneToMany(targetEntity="DDC2494Campaign", mappedBy="currency")
|
||||
*/
|
||||
protected $campaigns;
|
||||
|
||||
public function __construct($id, $temp)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->temp = $temp;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTemp()
|
||||
{
|
||||
return $this->temp;
|
||||
}
|
||||
|
||||
public function getCampaigns()
|
||||
{
|
||||
return $this->campaigns;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Table(name="ddc2494_campaign")
|
||||
* @Entity
|
||||
*/
|
||||
class DDC2494Campaign
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Tests\ORM\Functional\Ticket\DDC2494Currency
|
||||
*
|
||||
* @ManyToOne(targetEntity="DDC2494Currency", inversedBy="campaigns")
|
||||
* @JoinColumn(name="currency_id", referencedColumnName="id", nullable=false)
|
||||
*/
|
||||
protected $currency;
|
||||
|
||||
public function __construct(DDC2494Currency $currency)
|
||||
{
|
||||
$this->currency = $currency;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\Tests\ORM\Functional\Ticket\DDC2494Currency
|
||||
*/
|
||||
public function getCurrency()
|
||||
{
|
||||
return $this->currency;
|
||||
}
|
||||
}
|
||||
|
||||
class DDC2494TinyIntType extends Type
|
||||
{
|
||||
public static $calls = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
$return = (string) $value;
|
||||
|
||||
self::$calls[__FUNCTION__][] = array(
|
||||
'value' => $value,
|
||||
'return' => $return,
|
||||
'platform' => $platform,
|
||||
);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
$return = (integer) $value;
|
||||
|
||||
self::$calls[__FUNCTION__][] = array(
|
||||
'value' => $value,
|
||||
'return' => $return,
|
||||
'platform' => $platform,
|
||||
);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'ddc2494_tinyint';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\Legacy\LegacyUser;
|
||||
use Doctrine\Tests\Models\Legacy\LegacyUserReference;
|
||||
|
||||
/**
|
||||
* @group DDC-2519
|
||||
*/
|
||||
class DDC2519Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
private $userId;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('legacy');
|
||||
parent::setUp();
|
||||
|
||||
$this->loadFixture();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2519
|
||||
*/
|
||||
public function testIssue()
|
||||
{
|
||||
$dql = 'SELECT PARTIAL l.{_source, _target} FROM Doctrine\Tests\Models\Legacy\LegacyUserReference l';
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertCount(2, $result);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUserReference', $result[0]);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUserReference', $result[1]);
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUser', $result[0]->source());
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUser', $result[0]->target());
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUser', $result[1]->source());
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Legacy\LegacyUser', $result[1]->target());
|
||||
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[0]->source());
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[0]->target());
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[1]->source());
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[1]->target());
|
||||
|
||||
$this->assertFalse($result[0]->target()->__isInitialized());
|
||||
$this->assertFalse($result[0]->source()->__isInitialized());
|
||||
$this->assertFalse($result[1]->target()->__isInitialized());
|
||||
$this->assertFalse($result[1]->source()->__isInitialized());
|
||||
|
||||
$this->assertNotNull($result[0]->source()->getId());
|
||||
$this->assertNotNull($result[0]->target()->getId());
|
||||
$this->assertNotNull($result[1]->source()->getId());
|
||||
$this->assertNotNull($result[1]->target()->getId());
|
||||
}
|
||||
|
||||
public function loadFixture()
|
||||
{
|
||||
$user1 = new LegacyUser();
|
||||
$user1->_username = 'FabioBatSilva';
|
||||
$user1->_name = 'Fabio B. Silva';
|
||||
$user1->_status = 'active';
|
||||
|
||||
$user2 = new LegacyUser();
|
||||
$user2->_username = 'doctrinebot';
|
||||
$user2->_name = 'Doctrine Bot';
|
||||
$user2->_status = 'active';
|
||||
|
||||
$user3 = new LegacyUser();
|
||||
$user3->_username = 'test';
|
||||
$user3->_name = 'Tester';
|
||||
$user3->_status = 'active';
|
||||
|
||||
$this->_em->persist($user1);
|
||||
$this->_em->persist($user2);
|
||||
$this->_em->persist($user3);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->persist(new LegacyUserReference($user1, $user2, 'foo'));
|
||||
$this->_em->persist(new LegacyUserReference($user1, $user3, 'bar'));
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Mapping;
|
||||
|
||||
use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
/**
|
||||
* @group DDC-1845
|
||||
* @group DDC-2459
|
||||
*/
|
||||
class AnsiQuoteStrategyTest extends OrmTestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\DefaultQuoteStrategy
|
||||
*/
|
||||
private $strategy;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
|
||||
*/
|
||||
private $platform;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$em = $this->_getTestEntityManager();
|
||||
$this->platform = $em->getConnection()->getDatabasePlatform();
|
||||
$this->strategy = new AnsiQuoteStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
private function createClassMetadata($className)
|
||||
{
|
||||
$class = new ClassMetadata($className);
|
||||
$class->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
public function testGetColumnName()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$class->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
|
||||
$class->mapField(array('fieldName' => 'id', 'columnName' => 'id', 'id' => true));
|
||||
|
||||
$this->assertEquals('id' ,$this->strategy->getColumnName('id', $class, $this->platform));
|
||||
$this->assertEquals('name' ,$this->strategy->getColumnName('name', $class, $this->platform));
|
||||
}
|
||||
|
||||
public function testGetTableName()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$class->setPrimaryTable(array('name'=>'cms_user'));
|
||||
$this->assertEquals('cms_user' ,$this->strategy->getTableName($class, $this->platform));
|
||||
}
|
||||
|
||||
public function testJoinTableName()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
|
||||
$class->mapManyToMany(array(
|
||||
'fieldName' => 'user',
|
||||
'targetEntity' => 'CmsUser',
|
||||
'inversedBy' => 'users',
|
||||
'joinTable' => array(
|
||||
'name' => 'cmsaddress_cmsuser'
|
||||
)
|
||||
));
|
||||
|
||||
$this->assertEquals('cmsaddress_cmsuser', $this->strategy->getJoinTableName($class->associationMappings['user'], $class, $this->platform));
|
||||
|
||||
}
|
||||
|
||||
public function testIdentifierColumnNames()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
|
||||
$class->mapField(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
'columnName' => 'id',
|
||||
));
|
||||
|
||||
$this->assertEquals(array('id'), $this->strategy->getIdentifierColumnNames($class, $this->platform));
|
||||
}
|
||||
|
||||
|
||||
public function testColumnAlias()
|
||||
{
|
||||
$this->assertEquals('columnName1', $this->strategy->getColumnAlias('columnName', 1, $this->platform));
|
||||
}
|
||||
|
||||
public function testJoinColumnName()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
|
||||
|
||||
$class->mapOneToOne(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'article',
|
||||
'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
|
||||
'joinColumns' => array(array(
|
||||
'name' => 'article'
|
||||
)),
|
||||
));
|
||||
|
||||
$joinColumn = $class->associationMappings['article']['joinColumns'][0];
|
||||
$this->assertEquals('article',$this->strategy->getJoinColumnName($joinColumn, $class, $this->platform));
|
||||
}
|
||||
|
||||
public function testReferencedJoinColumnName()
|
||||
{
|
||||
$cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
|
||||
|
||||
$cm->mapOneToOne(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'article',
|
||||
'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
|
||||
'joinColumns' => array(array(
|
||||
'name' => 'article'
|
||||
)),
|
||||
));
|
||||
|
||||
$joinColumn = $cm->associationMappings['article']['joinColumns'][0];
|
||||
$this->assertEquals('id',$this->strategy->getReferencedJoinColumnName($joinColumn, $cm, $this->platform));
|
||||
}
|
||||
|
||||
public function testGetSequenceName()
|
||||
{
|
||||
$class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$definition = array(
|
||||
'sequenceName' => 'user_id_seq',
|
||||
'allocationSize' => 1,
|
||||
'initialValue' => 2
|
||||
);
|
||||
|
||||
$class->setSequenceGeneratorDefinition($definition);
|
||||
|
||||
$this->assertEquals('user_id_seq',$this->strategy->getSequenceName($definition, $class, $this->platform));
|
||||
}
|
||||
}
|
||||
@@ -1066,6 +1066,31 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
|
||||
@@ -1092,4 +1117,4 @@ class MyPrefixNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
|
||||
{
|
||||
return strtolower($this->classToTableName($className)) . '_' . $propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +590,14 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertValidDQL("select COALESCE(NULLIF(u.name, ''), u.username) as Display FROM Doctrine\Tests\Models\CMS\CmsUser u");
|
||||
}
|
||||
|
||||
/**
|
||||
* @gorup DDC-1858
|
||||
*/
|
||||
public function testHavingSupportIsNullExpression()
|
||||
{
|
||||
$this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u HAVING u.username IS NULL");
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
@@ -1292,6 +1303,22 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2519
|
||||
*/
|
||||
public function testPartialWithAssociationIdentifier()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT PARTIAL l.{_source, _target} FROM Doctrine\Tests\Models\Legacy\LegacyUserReference l",
|
||||
'SELECT l0_.iUserIdSource AS iUserIdSource0, l0_.iUserIdTarget AS iUserIdTarget1 FROM legacy_users_reference l0_'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT PARTIAL l.{_description, _source, _target} FROM Doctrine\Tests\Models\Legacy\LegacyUserReference l",
|
||||
'SELECT l0_.description AS description0, l0_.iUserIdSource AS iUserIdSource1, l0_.iUserIdTarget AS iUserIdTarget2 FROM legacy_users_reference l0_'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1339
|
||||
*/
|
||||
@@ -1303,6 +1330,21 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testIdentityFunctionInJoinedSubclass()
|
||||
{
|
||||
//relation is in the subclass (CompanyManager) we are querying
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT m, IDENTITY(m.car) as car_id FROM Doctrine\Tests\Models\Company\CompanyManager m',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c2_.car_id AS sclr6, c0_.discr AS discr7 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
|
||||
);
|
||||
|
||||
//relation is in the base class (CompanyPerson).
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT m, IDENTITY(m.spouse) as spouse_id FROM Doctrine\Tests\Models\Company\CompanyManager m',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.spouse_id AS sclr6, c0_.discr AS discr7 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1339
|
||||
*/
|
||||
@@ -1831,6 +1873,17 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1845
|
||||
*/
|
||||
public function testQuotedTableDeclaration()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT u FROM Doctrine\Tests\Models\Quote\User u',
|
||||
'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1 FROM "quote-user" q0_'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1845
|
||||
*/
|
||||
@@ -1916,7 +1969,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$connMock = $this->_em->getConnection();
|
||||
$orgPlatform = $connMock->getDatabasePlatform();
|
||||
|
||||
|
||||
$connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform);
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
|
||||
@@ -1926,7 +1979,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT CONCAT(u.id, u.name, u.status) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1",
|
||||
"SELECT CONCAT(c0_.id, c0_.name, c0_.status) AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?"
|
||||
);
|
||||
|
||||
|
||||
$connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
|
||||
@@ -1936,7 +1989,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"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_ WHERE c0_.id = ?"
|
||||
);
|
||||
|
||||
|
||||
$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",
|
||||
@@ -1946,7 +1999,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"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 = ?"
|
||||
);
|
||||
|
||||
|
||||
$connMock->setDatabasePlatform($orgPlatform);
|
||||
}
|
||||
|
||||
@@ -1971,6 +2024,134 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-2475
|
||||
*/
|
||||
public function testOrderByClauseShouldReplaceOrderByRelationMapping()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT r, b FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.bookings b',
|
||||
'SELECT r0_.id AS id0, r1_.id AS id1, r1_.passengerName AS passengerName2 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName ASC'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT r, b FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.bookings b ORDER BY b.passengerName DESC',
|
||||
'SELECT r0_.id AS id0, r1_.id AS id1, r1_.passengerName AS passengerName2 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName DESC'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1858
|
||||
*/
|
||||
public function testHavingSupportIsNullExpression()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u HAVING u.username IS NULL',
|
||||
'SELECT c0_.name AS name0 FROM cms_users c0_ HAVING c0_.username IS NULL'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
public function testHavingSupportResultVariableInExpression()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT u.name AS foo FROM Doctrine\Tests\Models\CMS\CmsUser u HAVING foo IN (?1)',
|
||||
'SELECT c0_.name AS name0 FROM cms_users c0_ HAVING name0 IN (?)'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
||||
|
||||
@@ -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'
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -74,6 +74,25 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
$this->entityManager->getConnection()->setDatabasePlatform($odp);
|
||||
}
|
||||
|
||||
public function testLimitSubqueryWithHiddenScalarSortPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\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'
|
||||
);
|
||||
$limitQuery = clone $query;
|
||||
$limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT DISTINCT id1, sclr0 FROM (SELECT COUNT(g0_.id) AS sclr0, u1_.id AS id1, g0_.id AS id2 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id ORDER BY sclr0 ASC, u1_.id DESC) dctrn_result ORDER BY sclr0 ASC, id1 DESC",
|
||||
$limitQuery->getSql()
|
||||
);
|
||||
|
||||
$this->entityManager->getConnection()->setDatabasePlatform($odp);
|
||||
}
|
||||
|
||||
public function testLimitSubqueryPg()
|
||||
{
|
||||
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
<var name="tmpdb_port" value="3306"/>
|
||||
</php>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-clover" target="../../build/logs/clover.xml"/>
|
||||
</logging>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine ORM Test Suite">
|
||||
<directory>./../Doctrine/Tests/ORM</directory>
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
<var name="tmpdb_name" value="doctrine_tests_tmp" />
|
||||
<var name="tmpdb_port" value="5432"/>
|
||||
</php>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-clover" target="../../build/logs/clover.xml"/>
|
||||
</logging>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine ORM Test Suite">
|
||||
<directory>./../Doctrine/Tests/ORM</directory>
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit>
|
||||
|
||||
<logging>
|
||||
<log type="coverage-clover" target="../../build/logs/clover.xml"/>
|
||||
</logging>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine ORM Test Suite">
|
||||
<directory>./../Doctrine/Tests/ORM</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>performance</group>
|
||||
|
||||
Reference in New Issue
Block a user