Compare commits

..

81 Commits
2.2.1 ... 2.1.2

Author SHA1 Message Date
Benjamin Eberlei
144d0de0ab Release 2.1.2 2011-09-25 18:24:18 +00:00
Benjamin Eberlei
5c6164ce07 Bump Dev Version to 2.1.3-DEV 2011-09-25 18:23:05 +00:00
Benjamin Eberlei
e960ba24eb Release 2.1.2 2011-09-25 18:21:30 +00:00
Benjamin Eberlei
e55b700670 Update dependencies of Common and ORM 2011-09-25 20:20:17 +02:00
Benjamin Eberlei
e4dd5e83e4 Merge branch 'DDC-1381' into 2.1.x 2011-09-25 19:11:00 +02:00
Fabien Pennequin
082c2ded8d Fixed php notice in ClassMetadataFactory 2011-09-25 19:10:32 +02:00
Benjamin Eberlei
7f9cb9567a DDC-1337 - Fix MultiTableDeleteExecutor and MultiTableUpdateExecutor in MySQL transaction case 2011-09-25 19:08:16 +02:00
Benjamin Eberlei
90c50b013d Merge branch 'DDC-1392' into 2.1.x 2011-09-25 18:09:43 +02:00
Benjamin Eberlei
6a05e7f393 DDC-1392 - Fix bug with merging unitialized proxies 2011-09-25 18:09:13 +02:00
Benjamin Eberlei
a8e4d8f52d Merge branch 'DDC-1367' into 2.1.x 2011-09-25 16:41:12 +02:00
Benjamin Eberlei
47314c116c DDC-1367 - Bugfix 2011-09-25 16:40:14 +02:00
Benjamin Eberlei
c2eb6e6104 Merge branch 'DDC-1346' into 2.1.x 2011-09-25 15:11:58 +02:00
Guilherme Blanco
3b6a1e11f3 Added support for ResultVariable referencing in ArithmeticPrimary. Fixes DDC-1346. 2011-09-25 15:11:36 +02:00
Benjamin Eberlei
87650428b2 Merge branch 'DDC-1321' into 2.1.x 2011-09-25 15:07:12 +02:00
Guilherme Blanco
1de27437b5 Fixed bug with orphanRemoval not removing associated Entity on OneToMany and OneToOne relationships. As defined in ClassMatedataInfo, in these situations, when orphanRemoval=true, cascade=remove is implicit. This fixes DDC-1321. 2011-09-25 15:07:00 +02:00
Benjamin Eberlei
cf10ee4d02 Merge branch 'DDC-1356' into 2.1.x 2011-09-04 14:33:00 +02:00
Guilherme Blanco
1faa3a945e Added support to user provide an array of Entities as a DQL parameter. Fixes DDC-1356. 2011-09-04 14:32:45 +02:00
Benjamin Eberlei
22f37d4178 Merge branch 'DDC-1354' into 2.1.x 2011-09-04 14:30:38 +02:00
Guilherme Blanco
6ad21462fe Fixes DDC-1354. 2011-09-04 14:30:16 +02:00
Benjamin Eberlei
e9c29135f7 Merge branch 'DDC-1350' into 2.1.x 2011-08-30 20:41:10 +02:00
Benjamin Eberlei
12af7d24c0 DDC-1350 - Bugfixes in Doctrine\ORM\Tools\Setup 2011-08-30 20:41:02 +02:00
Benjamin Eberlei
4f3282d328 Bump DBAL dependency to 2.1.2 2011-08-29 23:00:27 +02:00
Benjamin Eberlei
60e7efa5b9 Merge branch 'DDC-1225' into 2.1.x 2011-08-29 21:55:51 +02:00
Guilherme Blanco
0a4c1028a1 Fixed issue with duplicated commas if Entity has no fields. 2011-08-29 21:54:41 +02:00
Benjamin Eberlei
2c3757d087 Merge branch 'DDC-1341' into 2.1.x 2011-08-28 21:50:04 +02:00
Benjamin Eberlei
bf892a8ece Namespace shortcut for repository was not merged into 2.1.x yet 2011-08-28 21:49:53 +02:00
Guilherme Blanco
878710d013 Fixed issue with CTI during DQL update that was incorrectly setting parameter types during multi table execution. Fixes DDC-1341. 2011-08-28 21:48:24 +02:00
Benjamin Eberlei
be800a991c Merge branch 'FixPostgresFailures' into 2.1.x 2011-08-28 15:57:44 +02:00
Benjamin Eberlei
e295168c19 DDC-1348 - Fix bug with UnitOfWork::getEntityState() 2011-08-28 15:57:33 +02:00
Benjamin Eberlei
c03d7dd086 Merge branch 'DDC-1306' into 2.1.x 2011-08-27 20:46:09 +02:00
Benjamin Eberlei
70938fa7f9 DDC-1306, DDC-1113 - Fix issues with inheritance and commit order 2011-08-27 20:44:47 +02:00
Benjamin Eberlei
83dbde9cda Bump Dev Version to 2.1.2-DEV 2011-08-26 06:11:43 +00:00
Benjamin Eberlei
05d12e20be Release 2.1.1 2011-08-26 06:07:58 +00:00
Benjamin Eberlei
9b3b6052da Fix tests after updating to latest DBAL 2.1.1 release 2011-08-26 08:03:25 +02:00
Benjamin Eberlei
ffdc5e8d32 Merge remote-tracking branch 'origin/2.1.x' into 2.1.x 2011-08-24 20:45:45 +02:00
Benjamin Eberlei
6380795827 Merge branch 'DDC-1333' into 2.1.x 2011-08-21 15:06:57 +02:00
Benjamin Eberlei
6e9575b121 DDC-1333 - Fix bug in xsd 2011-08-21 15:06:50 +02:00
Benjamin Eberlei
099e2c1bd3 Merge branch 'DDC-1340' into 2.1.x 2011-08-21 15:02:47 +02:00
Benjamin Eberlei
90c47a0510 DDC-1340 - Fix bug with merge() and optimistic lock exception 2011-08-21 15:02:39 +02:00
Alexander
67133f8886 [DDC-1301] Fixed tests teardown for mysql suite 2011-08-14 19:28:15 +02:00
Benjamin Eberlei
4b4efe5483 Merge branch 'DDC-1300' into 2.1.x 2011-08-06 20:25:35 +02:00
Benjamin Eberlei
6291139dd1 DDC-1300 - Fix bug in fetch join hydration of entities with foreign key identifier 2011-08-06 20:23:47 +02:00
Benjamin Eberlei
90f96c4fba Add phar packaging target and distribute phar into download folder 2011-08-01 23:09:17 +02:00
Benjamin Eberlei
23de4a0fe4 DDC-1313 - Optimize behavior of DriverChain::getAllClassNames() 2011-08-01 21:46:41 +02:00
Benjamin Eberlei
68faa589f5 Merge branch 'DDC-1302' into 2.1.x 2011-07-31 11:35:25 +02:00
Benjamin Eberlei
7633f7b7ae DDC-1302 - Fix bug in XmlDriver not handling orphan removal 2011-07-31 11:34:56 +02:00
Benjamin Eberlei
5f665a9f3c Merge branch 'DDC-1301' into 2.1.x 2011-07-28 23:27:04 +02:00
Alexander
4819594a71 [DDC-1301] Prefixed all Legacy models properties with _ 2011-07-28 23:26:43 +02:00
Alexander
64d3715e79 [DDC-1301] Fixed count() for fetch="EXTRA_LAZY" on OneToMany association 2011-07-28 23:26:43 +02:00
Alexander
b22f692406 [DDC-1301] Added tests for fetch="EXTRA_LAZY" count() on a "legacy" database 2011-07-28 23:26:43 +02:00
Benjamin Eberlei
a1ed28a39b Merge branch 'DDC-1275' into 2.1.x 2011-07-28 23:24:38 +02:00
Michael Ridgway
9b41b6106c F[DDC-1275] ixed check for owning side of a toOne relationship 2011-07-28 23:23:28 +02:00
Michael Ridgway
a24557bc27 Removing debug comment 2011-07-28 23:23:28 +02:00
Michael Ridgway
295281c890 DDC-1275: Added join columns to result set mapping 2011-07-28 23:23:28 +02:00
Benjamin Eberlei
57c5491494 Merge branch 'DDC-1298' into 2.1.x 2011-07-27 23:29:06 +02:00
Benjamin Eberlei
b43fffce8b DDC-1298 - Fix bug in SQLWalker with derived entities that have no fields of their own. 2011-07-27 23:28:40 +02:00
Benjamin Eberlei
e426c26ade Merge branch 'DDC-1238' into 2.1.x 2011-07-27 20:52:39 +02:00
Benjamin Eberlei
e23f5bc825 DDC-1238 - Fixed a bug introduced when refactoring persisters hydration. This occurs when you call $em->clear() and you start accessing a proxy. 2011-07-27 20:52:16 +02:00
Benjamin Eberlei
ce4f98aaab Update tests 2011-07-27 20:52:16 +02:00
Benjamin Eberlei
16d18c7f83 DDC-1238 - Reproducible case, its correct through 2011-07-27 20:52:16 +02:00
Benjamin Eberlei
6d62484065 Started trying to reproduce this issue 2011-07-27 20:52:15 +02:00
Benjamin Eberlei
6d1067b90c Merge branch 'DDC-1215' into 2.1.x 2011-07-26 23:01:07 +02:00
Benjamin Eberlei
3c3e5cbf41 [DDC-1215] Fix EntityGenerator inheritance regenerating properties and methods 2011-07-26 23:00:53 +02:00
Benjamin Eberlei
aabf39940a Merge branch 'DDC-1280' into 2.1.x 2011-07-26 22:31:16 +02:00
Benjamin Eberlei
1fedd0e7d3 [DDC-1280] Only generate linefeeds in proxies for consistency. 2011-07-26 22:31:06 +02:00
Benjamin Eberlei
a0a03947a3 Merge branch 'DDC-1276' into 2.1.x 2011-07-26 22:16:31 +02:00
Benjamin Eberlei
420da54620 DDC-1276 - Fix bug where merge managed and new entitiy share the same collection that is cascaded, cleared during the process and then empty afterwards. 2011-07-26 22:16:16 +02:00
Benjamin Eberlei
7bb77fc437 Merge branch 'EntityGenerator' into 2.1.x 2011-07-12 23:47:01 +02:00
Benjamin Eberlei
bb3f6957d4 DDC-1244 - Fix bug with entities without namespace 2011-07-12 23:46:53 +02:00
Benjamin Eberlei
5ef63c1c0d DDC-1254 - Dont throw exception about missing id in disconnected metadata factory 2011-07-12 23:46:53 +02:00
Benjamin Eberlei
09c957fdc0 DDC-1268 - Singular add*() method name through using targetEntity shortname 2011-07-12 23:46:53 +02:00
Benjamin Eberlei
64bc782bdb Merge branch 'DDC-1240' into 2.1.x 2011-07-12 22:51:48 +02:00
Benjamin Eberlei
8fb5b40fc1 DDC-1240 - Fix optimistic lock exception loosing the message 2011-07-12 22:51:40 +02:00
Benjamin Eberlei
448811eb6a Merge branch 'DDC-1250' into 2.1.x 2011-07-09 22:14:02 +02:00
Benjamin Eberlei
ecc79c8ca0 DDC-1250 - Fix bug with inverse one to one loading and ambigious column names in certain scenarios 2011-07-09 22:13:54 +02:00
Benjamin Eberlei
d2320128cf Merge branch 'DDC-1257' into 2.1.x 2011-07-09 15:15:05 +02:00
Benjamin Eberlei
e5df347ea3 DDC-1257 - Fix bug where validation callbacks are added multiple times in EntityGenerator 2011-07-09 15:14:55 +02:00
Benjamin Eberlei
9e2b98ca16 Merge branch 'DDC-1251' into 2.1.x 2011-07-09 14:54:27 +02:00
Benjamin Eberlei
515b44126b DDC-1251 - Fix bug in token parsing of EntityGenerator 2011-07-09 14:54:10 +02:00
Benjamin Eberlei
1feac7ae9e DDC-1022 - Call __wakeup() with the same semantics then ClassMetadata::newInstance() does inside UnitOfWork 2011-07-09 12:24:47 +02:00
Benjamin Eberlei
1929ab6a75 Set DEV Version 2011-07-04 21:37:08 +00:00
486 changed files with 7252 additions and 24646 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,4 @@
build.properties
build/
logs/
reports/
@@ -6,6 +7,3 @@ download/
lib/api/
lib/Doctrine/Common
lib/Doctrine/DBAL
/.settings/
.buildpath
.project

3
.gitmodules vendored
View File

@@ -10,6 +10,3 @@
[submodule "lib/vendor/Symfony/Component/Yaml"]
path = lib/vendor/Symfony/Component/Yaml
url = git://github.com/symfony/Yaml.git
[submodule "lib/vendor/doctrine-build-common"]
path = lib/vendor/doctrine-build-common
url = https://github.com/doctrine/doctrine-build-common.git

View File

@@ -1,19 +0,0 @@
language: php
php:
- 5.3
- 5.4
env:
- DB=mysql
- DB=pgsql
- DB=sqlite
before_script:
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests_tmp;' -U postgres; fi"
- 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"
- git submodule update --init
script: phpunit --configuration tests/travis/$DB.travis.xml

View File

@@ -1,18 +1,14 @@
# Doctrine 2 ORM
Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2)
2.1.x: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.0+ 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),
inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
without requiring unnecessary code duplication.
## More resources:
More resources:
* [Website](http://www.doctrine-project.org)
* [Documentation](http://www.doctrine-project.org/projects/orm/2.0/docs/reference/introduction/en)
* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DDC)
* [Downloads](http://github.com/doctrine/doctrine2/downloads)
* [Downloads](http://github.com/doctrine/doctrine2/downloads)

View File

@@ -9,7 +9,6 @@ The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepo
The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way:
// new call to the AnnotationRegistry
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
$reader = new \Doctrine\Common\Annotations\AnnotationReader();

View File

@@ -1,76 +0,0 @@
# ResultCache implementation rewritten
The result cache is completely rewritten and now works on the database result level, not inside the ORM AbstractQuery
anymore. This means that for result cached queries the hydration will now always be performed again, regardless of
the hydration mode. Affected areas are:
1. Fixes the problem that entities coming from the result cache were not registered in the UnitOfWork
leading to problems during EntityManager#flush. Calls to EntityManager#merge are not necessary anymore.
2. Affects the array hydrator which now includes the overhead of hydration compared to caching the final result.
The API is backwards compatible however most of the getter methods on the `AbstractQuery` object are now
deprecated in favor of calling AbstractQuery#getQueryCacheProfile(). This method returns a `Doctrine\DBAL\Cache\QueryCacheProfile`
instance with access to result cache driver, lifetime and cache key.
# EntityManager#getPartialReference() creates read-only entity
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
haven't been in the identity map before. This means objects of this kind never lead to changes
in the UnitOfWork.
# Fields omitted in a partial DQL query or a native query are never updated
Fields of an entity that are not returned from a partial DQL Query or native SQL query
will never be updated through an UPDATE statement.
# Removed support for onUpdate in @JoinColumn
The onUpdate foreign key handling makes absolutely no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
# Changes in Annotation Handling
There have been some changes to the annotation handling in Common 2.2 again, that affect how people with old configurations
from 2.0 have to configure the annotation driver if they don't use `Configuration::newDefaultAnnotationDriver()`:
// Register the ORM Annotations in the AnnotationRegistry
AnnotationRegistry::registerFile('path/to/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
$reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
$driver = new AnnotationDriver($reader, (array)$paths);
$config->setMetadataDriverImpl($driver);
# Scalar mappings can now be ommitted from DQL result
You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore.
Example:
SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10
Your result will be a collection of Users, and not an array with key 0 as User object instance and "numArticles" as the number of articles per user
# Map entities as scalars in DQL result
When hydrating to array or even a mixed result in object hydrator, previously you had the 0 index holding you entity instance.
You are now allowed to alias this, providing more flexibility for you code.
Example:
SELECT u AS user FROM User u
Will now return a collection of arrays with index "user" pointing to the User object instance.
# Performance optimizations
Thousands of lines were completely reviewed and optimized for best performance.
Removed redundancy and improved code readability made now internal Doctrine code easier to understand.
Also, Doctrine 2.2 now is around 10-15% faster than 2.1.

View File

@@ -1,11 +0,0 @@
# 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_file = lib/Doctrine/ORM/Version.php

View File

@@ -8,7 +8,6 @@ report.dir=reports
log.archive.dir=logs
project.pirum_dir=
project.download_dir=
project.xsd_dir=
test.phpunit_configuration_file=
test.phpunit_generate_coverage=0
test.pmd_reports=0

221
build.xml
View File

@@ -1,7 +1,11 @@
<?xml version="1.0"?>
<project name="DoctrineORM" default="build" basedir=".">
<!--
Doctrine 2 build file.
-->
<project name="Doctrine2" 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" />
@@ -10,8 +14,6 @@
-->
<fileset id="shared-artifacts" dir=".">
<include name="LICENSE"/>
<include name="UPGRADE*" />
<include name="doctrine-mapping.xsd" />
</fileset>
<!--
@@ -49,34 +51,118 @@
-->
<fileset id="symfony-sources" dir="./lib/vendor">
<include name="Symfony/Component/**"/>
<exclude name="**/.git/**" />
</fileset>
<!--
Clean the directory for the next build.
-->
<target name="clean">
<available file="./build.properties" property="build_properties_exist" value="true"/>
<fail unless="build_properties_exist" message="The build.properties file is missing." />
<delete dir="${build.dir}" includeemptydirs="true" />
<delete dir="${dist.dir}" includeemptydirs="true" />
<delete dir="${report.dir}" includeemptydirs="true" />
</target>
<!--
Prepare the new build directories after cleaning
-->
<target name="prepare" depends="clean">
<echo msg="Creating build directory: ${build.dir}" />
<mkdir dir="${build.dir}" />
<echo msg="Creating distribution directory: ${dist.dir}" />
<mkdir dir="${dist.dir}" />
<echo msg="Creating report directory: ${report.dir}" />
<mkdir dir="${report.dir}" />
<mkdir dir="${build.dir}/logs"/>
<mkdir dir="${report.dir}/tests"/>
</target>
<!--
Builds ORM package, preparing it for distribution.
-->
<target name="copy-files" depends="prepare">
<copy todir="${build.dir}/${project.name}-${version}">
<target name="build-orm" depends="prepare">
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<copy todir="${build.dir}/doctrine-orm">
<fileset refid="shared-artifacts"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}">
<copy todir="${build.dir}/doctrine-orm">
<fileset refid="common-sources"/>
<fileset refid="dbal-sources"/>
<fileset refid="orm-sources"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}/Doctrine">
<copy todir="${build.dir}/doctrine-orm/Doctrine">
<fileset refid="symfony-sources"/>
</copy>
<copy todir="${build.dir}/${project.name}-${version}/bin">
<copy todir="${build.dir}/doctrine-orm/bin">
<fileset refid="bin-scripts"/>
</copy>
<exec command="sed 's/${version}-DEV/${version}/' ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php > ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${build.dir}/doctrine-orm/Doctrine/ORM/Version2.php ${build.dir}/doctrine-orm/Doctrine/ORM/Version.php" passthru="true" />
<delete dir="${build.dir}/doctrine-orm/Doctrine/Symfony/Component/Yaml/.git" includeemptydirs="true"/>
<delete dir="${build.dir}/doctrine-orm/Doctrine/Symfony/Component/Console/.git" includeemptydirs="true"/>
</target>
<target name="build" depends="test, build-orm"/>
<target name="package-phar" depends="build-orm">
<pharpackage basedir="${build.dir}/doctrine-orm/" destfile="${dist.dir}/doctrine-orm-${version}.phar" clistub="${build.dir}/doctrine-orm/bin/doctrine.php" signature="sha512">
<fileset dir="${build.dir}/doctrine-orm">
<include name="**/**" />
</fileset>
<metadata>
<element name="version" value="${version}" />
<element name="authors">
<element name="Guilherme Blanco"><element name="e-mail" value="guilhermeblanco@gmail.com" /></element>
<element name="Benjamin Eberlei"><element name="e-mail" value="kontakt@beberlei.de" /></element>
<element name="Jonathan H. Wage"><element name="e-mail" value="jonwage@gmail.com" /></element>
<element name="Roman Borschel"><element name="e-mail" value="roman@code-factory.org" /></element>
</element>
</metadata>
</pharpackage>
</target>
<!--
Runs the full test suite.
-->
<target name="test" depends="prepare">
<if><equals arg1="${test.phpunit_generate_coverage}" arg2="1" />
<then>
<property name="test.phpunit_coverage_file" value="${build.dir}/logs/clover.xml" />
</then>
<else>
<property name="test.phpunit_coverage_file" value="false" />
</else>
</if>
<nativephpunit
testfile="./tests/Doctrine/Tests/AllTests.php" junitlogfile="${build.dir}/logs/testsuites.xml"
testdirectory="./tests" coverageclover="${test.phpunit_coverage_file}" configuration="${test.phpunit_configuration_file}"
/>
<phpunitreport infile="${build.dir}/logs/testsuites.xml" format="frames" todir="${report.dir}/tests" />
<nativephpunit testfile="./tests/Doctrine/Tests/ORM/Performance/AllTests.php" testdirectory="./tests" haltonfailure="false" haltonerror="false" />
<tstamp/>
<copy file="${build.dir}/logs/testsuites.xml" tofile="${log.archive.dir}/latest/log.xml" overwrite="true"/>
<if><equals arg1="${test.pmd_reports}" arg2="1" />
<then>
<exec command="${test.pdepend_exec} --jdepend-xml=${build.dir}/logs/jdepend.xml ./lib/Doctrine" />
<exec command="${test.phpmd_exec} ./lib/Doctrine xml codesize --reportfile ${build.dir}/logs/phpmd.xml" />
<copy file="${build.dir}/logs/jdepend.xml" tofile="${log.archive.dir}/latest/jdepend.xml" overwrite="true"/>
<copy file="${build.dir}/logs/phpmd.xml" tofile="${log.archive.dir}/latest/phpmd.xml" overwrite="true"/>
</then>
</if>
</target>
<!--
Builds distributable PEAR packages.
-->
<target name="define-pear-package" depends="copy-files">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/${project.name}-${version}">
<target name="build-packages" depends="build-orm">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<name>DoctrineORM</name>
<summary>Doctrine Object Relational Mapper</summary>
<channel>pear.doctrine-project.org</channel>
@@ -86,29 +172,124 @@
<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}" />
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${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}" maximum_version="2.2.99" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" maximum_version="2.2.99" />
<package name="Console" channel="pear.symfony.com" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.com" minimum_version="2.0.0" />
<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="DoctrineSymfonyConsole" channel="pear.doctrine-project.org" minimum_version="2.0.0" />
<package name="DoctrineSymfonyYaml" channel="pear.doctrine-project.org" 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/Yaml/</ignore>
<ignore>Symfony/Component/Console/</ignore>
<release>
<install as="doctrine" name="bin/doctrine" />
<install as="doctrine.php" name="bin/doctrine.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="@php_bin@" to="php_bin" />
<replacement path="bin/doctrine.bat" type="pear-config" from="@bin_dir@" to="bin_dir" />
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineORM-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<tar destfile="dist/DoctrineORM-${version}-full.tar.gz" compression="gzip" basedir="${build.dir}">
<fileset dir="${build.dir}">
<include name="**/**" />
<exclude name="logs/" />
<exclude name="doctrine-orm/package.xml" />
</fileset>
</tar>
</target>
<target name="git-tag">
<exec command="grep '${version}-DEV' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<exec command="sed 's/${version}-DEV/${version}/' ${project.basedir}/lib/Doctrine/ORM/Version.php > ${project.basedir}/lib/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${project.basedir}/lib/Doctrine/ORM/Version2.php ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git add ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git commit -m 'Release ${version}'" />
<exec command="git tag -m 'Tag ${version}' -a ${version}" passthru="true" />
</target>
<target name="pirum-release">
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineORM-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum build ${project.pirum_dir}" passthru="true" />
</target>
<target name="distribute-download">
<copy file="dist/DoctrineORM-${version}-full.tar.gz" todir="${project.download_dir}" />
<copy file="${dist.dir}/doctrine-orm-${version}.phar" todir="${project.download_dir}" />
</target>
<target name="update-dev-version">
<exec command="grep '${version}' ${project.basedir}/lib/Doctrine/ORM/Version.php" checkreturn="true"/>
<propertyprompt propertyName="next_version" defaultValue="${version}" promptText="Enter next version string (without -DEV)" />
<exec command="sed 's/${version}/${next_version}-DEV/' ${project.basedir}/lib/Doctrine/ORM/Version.php > ${project.basedir}/lib/Doctrine/ORM/Version2.php" passthru="true" />
<exec command="mv ${project.basedir}/lib/Doctrine/ORM/Version2.php ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git add ${project.basedir}/lib/Doctrine/ORM/Version.php" passthru="true" />
<exec command="git commit -m 'Bump Dev Version to ${next_version}-DEV'" passthru="true" />
</target>
<target name="release" depends="git-tag,build-packages,package-phar,distribute-download,pirum-release,update-dev-version" />
<!--
Builds distributable PEAR packages for the Symfony Dependencies
-->
<target name="release-symfony-dependencies" depends="build-orm">
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<name>DoctrineSymfonyConsole</name>
<summary>Symfony Console Component</summary>
<channel>pear.doctrine-project.org</channel>
<description>A command line interface tool from the Symfony project. Packaged for shipping with Doctrine projects using ORM version numbers.</description>
<lead user="fabpot" name="Fabien Potencier" email="fabien.potencier@symfony-project.com" />
<license>NewBSD License</license>
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
</dependencies>
<ignore>bin/</ignore>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Doctrine/ORM/</ignore>
<ignore>Symfony/Component/Yaml/</ignore>
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineSymfonyConsole-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<d51pearpkg2 baseinstalldir="/" dir="${build.dir}/doctrine-orm">
<name>DoctrineSymfonyYaml</name>
<summary>Symfony Yaml Component</summary>
<channel>pear.doctrine-project.org</channel>
<description>A YAML Parser from the Symfony project. Packaged for shipping with Doctrine projects using ORM version numbers.</description>
<lead user="fabpot" name="Fabien Potencier" email="fabien.potencier@symfony-project.com" />
<license>NewBSD License</license>
<version release="${version}" api="${version}" />
<stability release="${stability}" api="${stability}" />
<notes>-</notes>
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
</dependencies>
<ignore>bin/</ignore>
<ignore>Doctrine/Common/</ignore>
<ignore>Doctrine/DBAL/</ignore>
<ignore>Doctrine/ORM/</ignore>
<ignore>Symfony/Component/Console/</ignore>
</d51pearpkg2>
<exec command="pear package" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="mv DoctrineSymfonyYaml-${version}.tgz ../../dist" dir="${build.dir}/doctrine-orm" passthru="true" />
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineSymfonyConsole-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum add ${project.pirum_dir} ${project.basedir}/dist/DoctrineSymfonyYaml-${version}.tgz" dir="." passthru="true" />
<exec command="sudo pirum build ${project.pirum_dir}" passthru="true" />
</target>
</project>

View File

@@ -1,23 +0,0 @@
{
"name": "doctrine/orm",
"type": "library","version":"2.2.1",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",
"license": "LGPL",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"}
],
"require": {
"php": ">=5.3.2",
"ext-pdo": "*",
"doctrine/common": ">=2.2.0,<2.2.99",
"doctrine/dbal": ">=2.2.1,<2.2.99"
},
"autoload": {
"psr-0": { "Doctrine\\ORM": "lib/" }
}
}

View File

@@ -150,7 +150,7 @@
<xs:restriction base="xs:token">
<xs:enumeration value="CASCADE"/>
<xs:enumeration value="RESTRICT"/>
<xs:enumeration value="SET NULL"/>
<xs:enumeration value="SET_NULL"/>
</xs:restriction>
</xs:simpleType>
@@ -350,7 +350,6 @@
<xs:attribute name="index-by" type="xs:NMTOKEN" />
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

View File

@@ -20,8 +20,7 @@
namespace Doctrine\ORM;
use Doctrine\DBAL\Types\Type,
Doctrine\ORM\Query\QueryException,
Doctrine\DBAL\Cache\QueryCacheProfile;
Doctrine\ORM\Query\QueryException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -77,7 +76,7 @@ abstract class AbstractQuery
protected $_resultSetMapping;
/**
* @var \Doctrine\ORM\EntityManager The entity manager used by this query object.
* @var Doctrine\ORM\EntityManager The entity manager used by this query object.
*/
protected $_em;
@@ -92,19 +91,38 @@ abstract class AbstractQuery
protected $_hydrationMode = self::HYDRATE_OBJECT;
/**
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
* The locally set cache driver used for caching result sets of this query.
*
* @var CacheDriver
*/
protected $_queryCacheProfile;
protected $_resultCacheDriver;
/**
* Boolean flag for whether or not to cache the results of this query.
*
* @var boolean
*/
protected $_useResultCache;
/**
* @var string The id to store the result cache entry under.
*/
protected $_resultCacheId;
/**
* @var boolean Boolean value that indicates whether or not expire the result cache.
*/
protected $_expireResultCache = false;
/**
* @var int Result Cache lifetime.
*/
protected $_resultCacheTTL;
/**
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
* @param \Doctrine\ORM\EntityManager $entityManager
* @param Doctrine\ORM\EntityManager $entityManager
*/
public function __construct(EntityManager $em)
{
@@ -114,7 +132,7 @@ abstract class AbstractQuery
/**
* Retrieves the associated EntityManager of this Query instance.
*
* @return \Doctrine\ORM\EntityManager
* @return Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
@@ -144,7 +162,7 @@ abstract class AbstractQuery
{
return $this->_params;
}
/**
* Get all defined parameter types.
*
@@ -163,11 +181,7 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
if (isset($this->_params[$key])) {
return $this->_params[$key];
}
return null;
return isset($this->_params[$key]) ? $this->_params[$key] : null;
}
/**
@@ -178,11 +192,7 @@ abstract class AbstractQuery
*/
public function getParameterType($key)
{
if (isset($this->_paramTypes[$key])) {
return $this->_paramTypes[$key];
}
return null;
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
}
/**
@@ -202,83 +212,36 @@ abstract class AbstractQuery
* @param string $type The parameter type. If specified, the given value will be run through
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameter($key, $value, $type = null)
{
$key = trim($key, ':');
$value = $this->processParameterValue($value);
if ($type === null) {
$type = Query\ParameterTypeInferer::inferType($value);
}
$this->_paramTypes[$key] = $type;
$this->_params[$key] = $value;
return $this;
}
/**
* Process an individual parameter value
*
* @param mixed $value
* @return array
*/
private function processParameterValue($value)
{
switch (true) {
case is_array($value):
for ($i = 0, $l = count($value); $i < $l; $i++) {
$paramValue = $this->processParameterValue($value[$i]);
$value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
}
return $value;
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
return $this->convertObjectParameterToScalarValue($value);
default:
return $value;
}
}
protected function convertObjectParameterToScalarValue($value)
{
$class = $this->_em->getClassMetadata(get_class($value));
if ($class->isIdentifierComposite) {
throw new \InvalidArgumentException("Binding an entity with a composite primary key to a query is not supported. You should split the parameter into the explicit fields and bind them seperately.");
}
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
$values = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
} else {
$values = $class->getIdentifierValues($value);
}
$value = $values[$class->getSingleIdentifierFieldName()];
if (!$value) {
throw new \InvalidArgumentException("Binding entities to query parameters only allowed for entities that have an identifier.");
}
return $value;
}
/**
* Sets a collection of query parameters.
*
* @param array $params
* @param array $types
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameters(array $params, array $types = array())
{
foreach ($params as $key => $value) {
$this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
if (isset($types[$key])) {
$this->setParameter($key, $value, $types[$key]);
} else {
$this->setParameter($key, $value);
}
}
return $this;
}
@@ -286,47 +249,44 @@ abstract class AbstractQuery
* Sets the ResultSetMapping that should be used for hydration.
*
* @param ResultSetMapping $rsm
* @return \Doctrine\ORM\AbstractQuery
* @return Doctrine\ORM\AbstractQuery
*/
public function setResultSetMapping(Query\ResultSetMapping $rsm)
{
$this->_resultSetMapping = $rsm;
return $this;
}
/**
* Defines a cache driver to be used for caching result sets and implictly enables caching.
* Defines a cache driver to be used for caching result sets.
*
* @param \Doctrine\Common\Cache\Cache $driver Cache driver
* @return \Doctrine\ORM\AbstractQuery
* @param Doctrine\Common\Cache\Cache $driver Cache driver
* @return Doctrine\ORM\AbstractQuery
*/
public function setResultCacheDriver($resultCacheDriver = null)
{
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
throw ORMException::invalidResultCacheDriver();
}
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
: new QueryCacheProfile(0, null, $resultCacheDriver);
$this->_resultCacheDriver = $resultCacheDriver;
if ($resultCacheDriver) {
$this->_useResultCache = true;
}
return $this;
}
/**
* Returns the cache driver used for caching result sets.
*
* @deprecated
* @return \Doctrine\Common\Cache\Cache Cache driver
* @return Doctrine\Common\Cache\Cache Cache driver
*/
public function getResultCacheDriver()
{
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
return $this->_queryCacheProfile->getResultCacheDriver();
if ($this->_resultCacheDriver) {
return $this->_resultCacheDriver;
} else {
return $this->_em->getConfiguration()->getResultCacheImpl();
}
return $this->_em->getConfiguration()->getResultCacheImpl();
}
/**
@@ -334,62 +294,57 @@ abstract class AbstractQuery
* how long and which ID to use for the cache entry.
*
* @param boolean $bool
* @param integer $lifetime
* @param integer $timeToLive
* @param string $resultCacheId
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
public function useResultCache($bool, $timeToLive = null, $resultCacheId = null)
{
if ($bool) {
$this->setResultCacheLifetime($lifetime);
$this->setResultCacheId($resultCacheId);
return $this;
$this->_useResultCache = $bool;
if ($timeToLive) {
$this->setResultCacheLifetime($timeToLive);
}
if ($resultCacheId) {
$this->_resultCacheId = $resultCacheId;
}
$this->_queryCacheProfile = null;
return $this;
}
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $lifetime How long the cache entry is valid.
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @param integer $timeToLive How long the cache entry is valid.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheLifetime($lifetime)
public function setResultCacheLifetime($timeToLive)
{
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setLifetime($lifetime)
: new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl());
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
$this->_resultCacheTTL = $timeToLive;
return $this;
}
/**
* Retrieves the lifetime of resultset cache.
*
* @deprecated
* @return integer
*/
public function getResultCacheLifetime()
{
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0;
return $this->_resultCacheTTL;
}
/**
* Defines if the result cache is active or not.
*
* @param boolean $expire Whether or not to force resultset cache expiration.
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function expireResultCache($expire = true)
{
$this->_expireResultCache = $expire;
return $this;
}
@@ -403,14 +358,6 @@ abstract class AbstractQuery
return $this->_expireResultCache;
}
/**
* @return QueryCacheProfile
*/
public function getQueryCacheProfile()
{
return $this->_queryCacheProfile;
}
/**
* Change the default fetch mode of an association for this query.
*
@@ -428,7 +375,6 @@ abstract class AbstractQuery
}
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
return $this;
}
@@ -437,12 +383,11 @@ abstract class AbstractQuery
*
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setHydrationMode($hydrationMode)
{
$this->_hydrationMode = $hydrationMode;
return $this;
}
@@ -507,15 +452,14 @@ abstract class AbstractQuery
return null;
}
if ( ! is_array($result)) {
return $result;
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
return $result;
}
/**
@@ -539,15 +483,14 @@ abstract class AbstractQuery
throw new NoResultException;
}
if ( ! is_array($result)) {
return $result;
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
return $result;
}
/**
@@ -568,12 +511,11 @@ abstract class AbstractQuery
*
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
* @return \Doctrine\ORM\AbstractQuery
* @return Doctrine\ORM\AbstractQuery
*/
public function setHint($name, $value)
{
$this->_hints[$name] = $value;
return $this;
}
@@ -590,7 +532,7 @@ abstract class AbstractQuery
/**
* Return the key value map of query hints that are currently set.
*
*
* @return array
*/
public function getHints()
@@ -604,7 +546,7 @@ abstract class AbstractQuery
*
* @param array $params The query parameters.
* @param integer $hydrationMode The hydration mode to use.
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
* @return IterableResult
*/
public function iterate(array $params = array(), $hydrationMode = null)
{
@@ -640,6 +582,28 @@ abstract class AbstractQuery
$this->setParameters($params);
}
// Check result cache
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
list($key, $hash) = $this->getResultCacheId();
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($hash);
if ($cached === false || !isset($cached[$key])) {
// Cache miss.
$stmt = $this->_doExecute();
$result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL);
return $result;
} else {
// Cache hit.
return $cached[$key];
}
}
$stmt = $this->_doExecute();
if (is_numeric($stmt)) {
@@ -647,8 +611,8 @@ abstract class AbstractQuery
}
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$stmt, $this->_resultSetMapping, $this->_hints
);
}
/**
@@ -657,32 +621,53 @@ abstract class AbstractQuery
* generated for you.
*
* @param string $id
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheId($id)
{
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setCacheKey($id)
: new QueryCacheProfile(0, $id, $this->_em->getConfiguration()->getResultCacheImpl());
$this->_resultCacheId = $id;
return $this;
}
/**
* Get the result cache id to use to store the result set cache entry if set.
* Get the result cache id to use to store the result set cache entry.
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @deprecated
* @return string
* @return array ($key, $hash)
*/
public function getResultCacheId()
protected function getResultCacheId()
{
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null;
if ($this->_resultCacheId) {
return array($this->_resultCacheId, $this->_resultCacheId);
} else {
$params = $this->_params;
foreach ($params AS $key => $value) {
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
} else {
$class = $this->_em->getClassMetadata(get_class($value));
$idValues = $class->getIdentifierValues($value);
}
$params[$key] = $idValues;
} else {
$params[$key] = $value;
}
}
$sql = $this->getSql();
ksort($this->_hints);
$key = implode(";", (array)$sql) . var_export($params, true) .
var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode;
return array($key, md5($key));
}
}
/**
* Executes the query and returns a the resulting Statement object.
*
* @return \Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
* @return Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
*/
abstract protected function _doExecute();

View File

@@ -85,7 +85,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the namespace where proxy classes reside.
*
*
* @return string
*/
public function getProxyNamespace()
@@ -96,7 +96,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Sets the namespace where proxy classes reside.
*
*
* @param string $ns
*/
public function setProxyNamespace($ns)
@@ -118,23 +118,22 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Add a new default annotation driver with a correctly configured annotation reader.
*
*
* @param array $paths
* @return Mapping\Driver\AnnotationDriver
*/
public function newDefaultAnnotationDriver($paths = array())
{
if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
// Register the ORM Annotations in the AnnotationRegistry
AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php');
$reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$reader = new AnnotationReader();
$reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
} else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0-DEV', '>=')) {
// Register the ORM Annotations in the AnnotationRegistry
AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php');
$reader = new AnnotationReader();
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$reader->setIgnoreNotImportedAnnotations(true);
@@ -163,7 +162,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Resolves a registered namespace alias to the full namespace.
*
* @param string $entityNamespaceAlias
* @param string $entityNamespaceAlias
* @return string
* @throws MappingException
*/
@@ -186,10 +185,10 @@ class Configuration extends \Doctrine\DBAL\Configuration
{
$this->_attributes['entityNamespaces'] = $entityNamespaces;
}
/**
* Retrieves the list of registered entity namespace aliases.
*
*
* @return array
*/
public function getEntityNamespaces()
@@ -209,6 +208,27 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['metadataDriverImpl'] : null;
}
/**
* Gets the cache driver implementation that is used for query result caching.
*
* @return \Doctrine\Common\Cache\Cache
*/
public function getResultCacheImpl()
{
return isset($this->_attributes['resultCacheImpl']) ?
$this->_attributes['resultCacheImpl'] : null;
}
/**
* Sets the cache driver implementation that is used for query result caching.
*
* @param \Doctrine\Common\Cache\Cache $cacheImpl
*/
public function setResultCacheImpl(Cache $cacheImpl)
{
$this->_attributes['resultCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for the query cache (SQL cache).
*
@@ -340,7 +360,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the implementation class name of a registered custom string DQL function.
*
*
* @param string $name
* @return string
*/
@@ -383,7 +403,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the implementation class name of a registered custom numeric DQL function.
*
*
* @param string $name
* @return string
*/
@@ -426,7 +446,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the implementation class name of a registered custom date/time DQL function.
*
*
* @param string $name
* @return string
*/
@@ -477,7 +497,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Set a class metadata factory.
*
*
* @param string $cmf
*/
public function setClassMetadataFactoryName($cmfName)
@@ -495,57 +515,4 @@ class Configuration extends \Doctrine\DBAL\Configuration
}
return $this->_attributes['classMetadataFactoryName'];
}
/**
* Add a filter to the list of possible filters.
*
* @param string $name The name of the filter.
* @param string $className The class name of the filter.
*/
public function addFilter($name, $className)
{
$this->_attributes['filters'][$name] = $className;
}
/**
* Gets the class name for a given filter name.
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null of it is not
* defined.
*/
public function getFilterClassName($name)
{
return isset($this->_attributes['filters'][$name]) ?
$this->_attributes['filters'][$name] : null;
}
/**
* Set default repository class.
*
* @since 2.2
* @param string $className
* @throws ORMException If not is a \Doctrine\ORM\EntityRepository
*/
public function setDefaultRepositoryClassName($className)
{
if ($className != "Doctrine\ORM\EntityRepository" &&
!is_subclass_of($className, 'Doctrine\ORM\EntityRepository')){
throw ORMException::invalidEntityRepository($className);
}
$this->_attributes['defaultRepositoryClassName'] = $className;
}
/**
* Get default repository class.
*
* @since 2.2
* @return string
*/
public function getDefaultRepositoryClassName()
{
return isset($this->_attributes['defaultRepositoryClassName']) ?
$this->_attributes['defaultRepositoryClassName'] : 'Doctrine\ORM\EntityRepository';
}
}
}

View File

@@ -27,8 +27,7 @@ use Closure, Exception,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Query\ResultSetMapping,
Doctrine\ORM\Proxy\ProxyFactory,
Doctrine\ORM\Query\FilterCollection;
Doctrine\ORM\Proxy\ProxyFactory;
/**
* The EntityManager is the central access point to ORM functionality.
@@ -44,21 +43,21 @@ class EntityManager implements ObjectManager
/**
* The used Configuration.
*
* @var \Doctrine\ORM\Configuration
* @var Doctrine\ORM\Configuration
*/
private $config;
/**
* The database connection used by the EntityManager.
*
* @var \Doctrine\DBAL\Connection
* @var Doctrine\DBAL\Connection
*/
private $conn;
/**
* The metadata factory, used to retrieve the ORM metadata of entity classes.
*
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
* @var Doctrine\ORM\Mapping\ClassMetadataFactory
*/
private $metadataFactory;
@@ -72,14 +71,14 @@ class EntityManager implements ObjectManager
/**
* The UnitOfWork used to coordinate object-level transactions.
*
* @var \Doctrine\ORM\UnitOfWork
* @var Doctrine\ORM\UnitOfWork
*/
private $unitOfWork;
/**
* The event manager that is the central point of the event system.
*
* @var \Doctrine\Common\EventManager
* @var Doctrine\Common\EventManager
*/
private $eventManager;
@@ -93,14 +92,14 @@ class EntityManager implements ObjectManager
/**
* The proxy factory used to create dynamic proxies.
*
* @var \Doctrine\ORM\Proxy\ProxyFactory
* @var Doctrine\ORM\Proxy\ProxyFactory
*/
private $proxyFactory;
/**
* The expression builder instance used to generate query expressions.
*
* @var \Doctrine\ORM\Query\Expr
* @var Doctrine\ORM\Query\Expr
*/
private $expressionBuilder;
@@ -111,20 +110,13 @@ class EntityManager implements ObjectManager
*/
private $closed = false;
/**
* Collection of query filters.
*
* @var Doctrine\ORM\Query\FilterCollection
*/
private $filterCollection;
/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
*
* @param \Doctrine\DBAL\Connection $conn
* @param \Doctrine\ORM\Configuration $config
* @param \Doctrine\Common\EventManager $eventManager
* @param Doctrine\DBAL\Connection $conn
* @param Doctrine\ORM\Configuration $config
* @param Doctrine\Common\EventManager $eventManager
*/
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
{
@@ -136,20 +128,18 @@ class EntityManager implements ObjectManager
$this->metadataFactory = new $metadataFactoryClassName;
$this->metadataFactory->setEntityManager($this);
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
$this->unitOfWork = new UnitOfWork($this);
$this->proxyFactory = new ProxyFactory(
$this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses()
);
$this->proxyFactory = new ProxyFactory($this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses());
}
/**
* Gets the database connection object used by the EntityManager.
*
* @return \Doctrine\DBAL\Connection
* @return Doctrine\DBAL\Connection
*/
public function getConnection()
{
@@ -159,7 +149,7 @@ class EntityManager implements ObjectManager
/**
* Gets the metadata factory used to gather the metadata of classes.
*
* @return \Doctrine\ORM\Mapping\ClassMetadataFactory
* @return Doctrine\ORM\Mapping\ClassMetadataFactory
*/
public function getMetadataFactory()
{
@@ -178,14 +168,13 @@ class EntityManager implements ObjectManager
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
* </code>
*
* @return \Doctrine\ORM\Query\Expr
* @return Doctrine\ORM\Query\Expr
*/
public function getExpressionBuilder()
{
if ($this->expressionBuilder === null) {
$this->expressionBuilder = new Query\Expr;
}
return $this->expressionBuilder;
}
@@ -210,23 +199,22 @@ class EntityManager implements ObjectManager
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
*
* @param Closure $func The function to execute transactionally.
* @return mixed Returns the non-empty value returned from the closure or true instead
*/
public function transactional(Closure $func)
{
$this->conn->beginTransaction();
try {
$return = $func($this);
$this->flush();
$this->conn->commit();
return $return ?: true;
} catch (Exception $e) {
$this->close();
$this->conn->rollback();
throw $e;
}
}
@@ -256,12 +244,12 @@ class EntityManager implements ObjectManager
*
* The class name must be the fully-qualified class name without a leading backslash
* (as it is returned by get_class($obj)) or an aliased class name.
*
*
* Examples:
* MyProject\Domain\User
* sales:PriceRequest
*
* @return \Doctrine\ORM\Mapping\ClassMetadata
* @return Doctrine\ORM\Mapping\ClassMetadata
* @internal Performance-sensitive method.
*/
public function getClassMetadata($className)
@@ -273,16 +261,14 @@ class EntityManager implements ObjectManager
* Creates a new Query object.
*
* @param string The DQL string.
* @return \Doctrine\ORM\Query
* @return Doctrine\ORM\Query
*/
public function createQuery($dql = "")
{
$query = new Query($this);
if ( ! empty($dql)) {
$query->setDql($dql);
}
return $query;
}
@@ -290,7 +276,7 @@ class EntityManager implements ObjectManager
* Creates a Query from a named query.
*
* @param string $name
* @return \Doctrine\ORM\Query
* @return Doctrine\ORM\Query
*/
public function createNamedQuery($name)
{
@@ -309,7 +295,6 @@ class EntityManager implements ObjectManager
$query = new NativeQuery($this);
$query->setSql($sql);
$query->setResultSetMapping($rsm);
return $query;
}
@@ -317,12 +302,11 @@ class EntityManager implements ObjectManager
* Creates a NativeQuery from a named native query.
*
* @param string $name
* @return \Doctrine\ORM\NativeQuery
* @return Doctrine\ORM\NativeQuery
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@@ -341,18 +325,13 @@ class EntityManager implements ObjectManager
* This effectively synchronizes the in-memory state of managed objects with the
* database.
*
* If an entity is explicitly passed to this method only this entity and
* the cascade-persist semantics + scheduled inserts/removals are synchronized.
*
* @param object $entity
* @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that
* @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that
* makes use of optimistic locking fails.
*/
public function flush($entity = null)
public function flush()
{
$this->errorIfClosed();
$this->unitOfWork->commit($entity);
$this->unitOfWork->commit();
}
/**
@@ -376,39 +355,27 @@ class EntityManager implements ObjectManager
* without actually loading it, if the entity is not yet loaded.
*
* @param string $entityName The name of the entity type.
* @param mixed $id The entity identifier.
* @param mixed $identifier The entity identifier.
* @return object The entity reference.
*/
public function getReference($entityName, $id)
public function getReference($entityName, $identifier)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
if ( ! is_array($id)) {
$id = array($class->identifier[0] => $id);
}
$sortedId = array();
foreach ($class->identifier as $identifier) {
if (!isset($id[$identifier])) {
throw ORMException::missingIdentifierField($class->name, $identifier);
}
$sortedId[$identifier] = $id[$identifier];
}
// Check identity map first, if its already in there just return it.
if ($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) {
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ($class->subClasses) {
return $this->find($entityName, $sortedId);
$entity = $this->find($entityName, $identifier);
} else {
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
$this->unitOfWork->registerManaged($entity, $identifier, array());
}
if ( ! is_array($sortedId)) {
$sortedId = array($class->identifier[0] => $sortedId);
}
$entity = $this->proxyFactory->getProxy($class->name, $sortedId);
$this->unitOfWork->registerManaged($entity, $sortedId, array());
return $entity;
}
@@ -439,7 +406,6 @@ class EntityManager implements ObjectManager
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
@@ -447,7 +413,6 @@ class EntityManager implements ObjectManager
$entity = $class->newInstance();
$class->setIdentifierValues($entity, $identifier);
$this->unitOfWork->registerManaged($entity, $identifier, array());
$this->unitOfWork->markReadOnly($entity);
return $entity;
}
@@ -456,11 +421,16 @@ class EntityManager implements ObjectManager
* Clears the EntityManager. All entities that are currently managed
* by this EntityManager become detached.
*
* @param string $entityName if given, only entities of this type will get detached
* @param string $entityName
*/
public function clear($entityName = null)
{
$this->unitOfWork->clear($entityName);
if ($entityName === null) {
$this->unitOfWork->clear();
} else {
//TODO
throw new ORMException("EntityManager#clear(\$entityName) not yet implemented.");
}
}
/**
@@ -479,7 +449,7 @@ class EntityManager implements ObjectManager
*
* The entity will be entered into the database at or before transaction
* commit or as a result of the flush operation.
*
*
* NOTE: The persist operation always considers entities that are not yet known to
* this EntityManager as NEW. Do not pass detached entities to the persist operation.
*
@@ -490,9 +460,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->persist($entity);
}
@@ -509,9 +477,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->remove($entity);
}
@@ -526,9 +492,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->refresh($entity);
}
@@ -546,7 +510,6 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->unitOfWork->detach($entity);
}
@@ -563,9 +526,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
return $this->unitOfWork->merge($entity);
}
@@ -605,20 +566,19 @@ class EntityManager implements ObjectManager
public function getRepository($entityName)
{
$entityName = ltrim($entityName, '\\');
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$repositoryClassName = $metadata->customRepositoryClassName;
$customRepositoryClassName = $metadata->customRepositoryClassName;
if ($repositoryClassName === null) {
$repositoryClassName = $this->config->getDefaultRepositoryClassName();
if ($customRepositoryClassName !== null) {
$repository = new $customRepositoryClassName($this, $metadata);
} else {
$repository = new EntityRepository($this, $metadata);
}
$repository = new $repositoryClassName($this, $metadata);
$this->repositories[$entityName] = $repository;
return $repository;
@@ -632,15 +592,15 @@ class EntityManager implements ObjectManager
*/
public function contains($entity)
{
return $this->unitOfWork->isScheduledForInsert($entity)
|| $this->unitOfWork->isInIdentityMap($entity)
&& ! $this->unitOfWork->isScheduledForDelete($entity);
return $this->unitOfWork->isScheduledForInsert($entity) ||
$this->unitOfWork->isInIdentityMap($entity) &&
! $this->unitOfWork->isScheduledForDelete($entity);
}
/**
* Gets the EventManager used by the EntityManager.
*
* @return \Doctrine\Common\EventManager
* @return Doctrine\Common\EventManager
*/
public function getEventManager()
{
@@ -650,7 +610,7 @@ class EntityManager implements ObjectManager
/**
* Gets the Configuration used by the EntityManager.
*
* @return \Doctrine\ORM\Configuration
* @return Doctrine\ORM\Configuration
*/
public function getConfiguration()
{
@@ -671,7 +631,7 @@ class EntityManager implements ObjectManager
/**
* Check if the Entity manager is open or closed.
*
*
* @return bool
*/
public function isOpen()
@@ -682,7 +642,7 @@ class EntityManager implements ObjectManager
/**
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
*
* @return \Doctrine\ORM\UnitOfWork
* @return Doctrine\ORM\UnitOfWork
*/
public function getUnitOfWork()
{
@@ -696,7 +656,7 @@ class EntityManager implements ObjectManager
* selectively iterate over the result.
*
* @param int $hydrationMode
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @return Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
public function getHydrator($hydrationMode)
{
@@ -711,33 +671,35 @@ class EntityManager implements ObjectManager
* Create a new instance for the given hydration mode.
*
* @param int $hydrationMode
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @return Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
public function newHydrator($hydrationMode)
{
switch ($hydrationMode) {
case Query::HYDRATE_OBJECT:
return new Internal\Hydration\ObjectHydrator($this);
$hydrator = new Internal\Hydration\ObjectHydrator($this);
break;
case Query::HYDRATE_ARRAY:
return new Internal\Hydration\ArrayHydrator($this);
$hydrator = new Internal\Hydration\ArrayHydrator($this);
break;
case Query::HYDRATE_SCALAR:
return new Internal\Hydration\ScalarHydrator($this);
$hydrator = new Internal\Hydration\ScalarHydrator($this);
break;
case Query::HYDRATE_SINGLE_SCALAR:
return new Internal\Hydration\SingleScalarHydrator($this);
$hydrator = new Internal\Hydration\SingleScalarHydrator($this);
break;
case Query::HYDRATE_SIMPLEOBJECT:
return new Internal\Hydration\SimpleObjectHydrator($this);
$hydrator = new Internal\Hydration\SimpleObjectHydrator($this);
break;
default:
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
return new $class($this);
$hydrator = new $class($this);
break;
}
throw ORMException::invalidHydrationMode($hydrationMode);
}
throw ORMException::invalidHydrationMode($hydrationMode);
return $hydrator;
}
/**
@@ -750,18 +712,6 @@ class EntityManager implements ObjectManager
return $this->proxyFactory;
}
/**
* Helper method to initialize a lazy loading proxy or persistent collection.
*
* This method is a no-op for other objects
*
* @param object $obj
*/
public function initializeObject($obj)
{
$this->unitOfWork->initializeObject($obj);
}
/**
* Factory method to create EntityManager instances.
*
@@ -773,62 +723,20 @@ class EntityManager implements ObjectManager
*/
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if ( ! $config->getMetadataDriverImpl()) {
if (!$config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
switch (true) {
case (is_array($conn)):
$conn = \Doctrine\DBAL\DriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection):
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
break;
default:
throw new \InvalidArgumentException("Invalid argument: " . $conn);
if (is_array($conn)) {
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager()));
} else if ($conn instanceof Connection) {
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
} else {
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
return new EntityManager($conn, $config, $conn->getEventManager());
}
/**
* Gets the enabled filters.
*
* @return FilterCollection The active filter collection.
*/
public function getFilters()
{
if (null === $this->filterCollection) {
$this->filterCollection = new FilterCollection($this);
}
return $this->filterCollection;
}
/**
* Checks whether the state of the filter collection is clean.
*
* @return boolean True, if the filter collection is clean.
*/
public function isFiltersStateClean()
{
return null === $this->filterCollection
|| $this->filterCollection->isClean();
}
/**
* Checks whether the Entity Manager has filters.
*
* @return True, if the EM has a filter collection.
*/
public function hasFilters()
{
return null !== $this->filterCollection;
}
}

View File

@@ -48,7 +48,7 @@ class EntityRepository implements ObjectRepository
protected $_em;
/**
* @var \Doctrine\ORM\Mapping\ClassMetadata
* @var Doctrine\ORM\Mapping\ClassMetadata
*/
protected $_class;
@@ -107,51 +107,42 @@ class EntityRepository implements ObjectRepository
*/
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
if ( ! is_array($id)) {
$id = array($this->_class->identifier[0] => $id);
}
$sortedId = array();
foreach ($this->_class->identifier as $identifier) {
if (!isset($id[$identifier])) {
throw ORMException::missingIdentifierField($this->_class->name, $identifier);
}
$sortedId[$identifier] = $id[$identifier];
}
// Check identity map first
if ($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) {
if ( ! ($entity instanceof $this->_class->name)) {
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
if (!($entity instanceof $this->_class->name)) {
return null;
}
if ($lockMode !== LockMode::NONE) {
if ($lockMode != LockMode::NONE) {
$this->_em->lock($entity, $lockMode, $lockVersion);
}
return $entity; // Hit!
}
switch ($lockMode) {
case LockMode::NONE:
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
if ( ! is_array($id) || count($id) <= 1) {
// @todo FIXME: Not correct. Relies on specific order.
$value = is_array($id) ? array_values($id) : array($id);
$id = array_combine($this->_class->identifier, $value);
}
case LockMode::OPTIMISTIC:
if ( ! $this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
if ($lockMode == LockMode::NONE) {
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
} else if ($lockMode == LockMode::OPTIMISTIC) {
if (!$this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
return $entity;
default:
if ( ! $this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId, null, null, array(), $lockMode);
return $entity;
} else {
if (!$this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
}
}
@@ -187,7 +178,7 @@ class EntityRepository implements ObjectRepository
*/
public function findOneBy(array $criteria)
{
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria, null, null, array(), 0, 1);
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria);
}
/**
@@ -200,35 +191,31 @@ class EntityRepository implements ObjectRepository
*/
public function __call($method, $arguments)
{
switch (true) {
case (substr($method, 0, 6) == 'findBy'):
$by = substr($method, 6, strlen($method));
$method = 'findBy';
break;
case (substr($method, 0, 9) == 'findOneBy'):
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
break;
default:
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
if (substr($method, 0, 6) == 'findBy') {
$by = substr($method, 6, strlen($method));
$method = 'findBy';
} else if (substr($method, 0, 9) == 'findOneBy') {
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
} else {
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
}
if (empty($arguments)) {
throw ORMException::findByRequiresParameter($method . $by);
if ( !isset($arguments[0])) {
// we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL.
throw ORMException::findByRequiresParameter($method.$by);
}
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
return $this->$method(array($fieldName => $arguments[0]));
} else {
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/**
@@ -239,14 +226,6 @@ class EntityRepository implements ObjectRepository
return $this->_entityName;
}
/**
* @return string
*/
public function getClassName()
{
return $this->getEntityName();
}
/**
* @return EntityManager
*/
@@ -262,4 +241,4 @@ class EntityRepository implements ObjectRepository
{
return $this->_class;
}
}
}

View File

@@ -19,59 +19,42 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\EntityManager;
/**
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
* of entities.
*
* @link www.doctrine-project.org
* @since 2.0
* @since 2.0
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class LifecycleEventArgs extends EventArgs
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var \Doctrine\ORM\EntityManager
* @var EntityManager
*/
private $em;
private $_em;
/**
* @var object
*/
private $entity;
/**
* Constructor
*
* @param object $entity
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct($entity, EntityManager $em)
private $_entity;
public function __construct($entity, $em)
{
$this->entity = $entity;
$this->em = $em;
$this->_entity = $entity;
$this->_em = $em;
}
/**
* Retireve associated Entity.
*
* @return object
*/
public function getEntity()
{
return $this->entity;
return $this->_entity;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
* @return EntityManager
*/
public function getEntityManager()
{
return $this->em;
return $this->_em;
}
}

View File

@@ -1,25 +1,9 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\EntityManager;
@@ -27,36 +11,32 @@ use Doctrine\ORM\EntityManager;
* Class that holds event arguments for a loadMetadata event.
*
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
* @since 2.0
*/
class LoadClassMetadataEventArgs extends EventArgs
{
/**
* @var \Doctrine\ORM\Mapping\ClassMetadata
* @var ClassMetadata
*/
private $classMetadata;
/**
* @var \Doctrine\ORM\EntityManager
* @var EntityManager
*/
private $em;
/**
* Constructor.
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
* @param \Doctrine\ORM\EntityManager $em
* @param ClassMetadataInfo $classMetadata
* @param EntityManager $em
*/
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
{
$this->classMetadata = $classMetadata;
$this->em = $em;
$this->em = $em;
}
/**
* Retrieve associated ClassMetadata.
*
* @return \Doctrine\ORM\Mapping\ClassMetadataInfo
* @return ClassMetadataInfo
*/
public function getClassMetadata()
{
@@ -64,9 +44,7 @@ class LoadClassMetadataEventArgs extends EventArgs
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
* @return EntityManager
*/
public function getEntityManager()
{

View File

@@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
*/
namespace Doctrine\ORM\Event;
@@ -23,8 +23,9 @@ namespace Doctrine\ORM\Event;
* Provides event arguments for the onClear event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
@@ -36,49 +37,18 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
private $em;
/**
* @var string
*/
private $entityClass;
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
* @param string $entityClass Optional entity class
*/
public function __construct($em, $entityClass = null)
public function __construct($em)
{
$this->em = $em;
$this->entityClass = $entityClass;
$this->em = $em;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->em;
}
/**
* Name of the entity class that is cleared, or empty if all are cleared.
*
* @return string
*/
public function getEntityClass()
{
return $this->entityClass;
}
/**
* Check if event clears all entities.
*
* @return bool
*/
public function clearsAllEntities()
{
return ($this->entityClass === null);
}
}

View File

@@ -21,63 +21,55 @@
namespace Doctrine\ORM\Event;
use Doctrine\ORM\EntityManager;
/**
* Provides event arguments for the preFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class OnFlushEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var Doctirne\ORM\EntityManager
* @var EntityManager
*/
private $em;
//private $entitiesToPersist = array();
//private $entitiesToRemove = array();
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
private $_em;
//private $_entitiesToPersist = array();
//private $_entitiesToRemove = array();
public function __construct($em)
{
$this->em = $em;
$this->_em = $em;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
* @return EntityManager
*/
public function getEntityManager()
{
return $this->em;
return $this->_em;
}
/*
public function addEntityToPersist($entity)
{
}
public function addEntityToRemove($entity)
{
}
public function addEntityToUpdate($entity)
{
}
public function getEntitiesToPersist()
{
return $this->_entitiesToPersist;

View File

@@ -1,61 +0,0 @@
<?php
/*
* $Id$
*
* 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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\EventArgs;
/**
* Provides event arguments for the postFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Daniel Freudenberger <df@rebuy.de>
*/
class PostFlushEventArgs extends EventArgs
{
/**
* @var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->em;
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* $Id$
*
* 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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
/**
* Provides event arguments for the preFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class PreFlushEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var EntityManager
*/
private $_em;
public function __construct($em)
{
$this->_em = $em;
}
/**
* @return EntityManager
*/
public function getEntityManager()
{
return $this->_em;
}
}

View File

@@ -1,23 +1,4 @@
<?php
/*
* $Id$
*
* 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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
@@ -27,63 +8,55 @@ use Doctrine\Common\EventArgs,
/**
* Class that holds event arguments for a preInsert/preUpdate event.
*
* @author Guilherme Blanco <guilehrmeblanco@hotmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
* @since 2.0
*/
class PreUpdateEventArgs extends LifecycleEventArgs
{
/**
* @var array
*/
private $entityChangeSet;
private $_entityChangeSet;
/**
* Constructor.
*
* @param object $entity
* @param \Doctrine\ORM\EntityManager $em
* @param EntityManager $em
* @param array $changeSet
*/
public function __construct($entity, EntityManager $em, array &$changeSet)
public function __construct($entity, $em, array &$changeSet)
{
parent::__construct($entity, $em);
$this->entityChangeSet = &$changeSet;
$this->_entityChangeSet = &$changeSet;
}
/**
* Retrieve entity changeset.
*
* @return array
*/
public function getEntityChangeSet()
{
return $this->entityChangeSet;
return $this->_entityChangeSet;
}
/**
* Check if field has a changeset.
* Field has a changeset?
*
* @return boolean
* @return bool
*/
public function hasChangedField($field)
{
return isset($this->entityChangeSet[$field]);
return isset($this->_entityChangeSet[$field]);
}
/**
* Get the old value of the changeset of the changed field.
*
*
* @param string $field
* @return mixed
*/
public function getOldValue($field)
{
$this->assertValidField($field);
$this->_assertValidField($field);
return $this->entityChangeSet[$field][0];
return $this->_entityChangeSet[$field][0];
}
/**
@@ -94,37 +67,31 @@ class PreUpdateEventArgs extends LifecycleEventArgs
*/
public function getNewValue($field)
{
$this->assertValidField($field);
$this->_assertValidField($field);
return $this->entityChangeSet[$field][1];
return $this->_entityChangeSet[$field][1];
}
/**
* Set the new value of this field.
*
*
* @param string $field
* @param mixed $value
*/
public function setNewValue($field, $value)
{
$this->assertValidField($field);
$this->_assertValidField($field);
$this->entityChangeSet[$field][1] = $value;
$this->_entityChangeSet[$field][1] = $value;
}
/**
* Assert the field exists in changeset.
*
* @param string $field
*/
private function assertValidField($field)
private function _assertValidField($field)
{
if ( ! isset($this->entityChangeSet[$field])) {
throw new \InvalidArgumentException(sprintf(
'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.',
$field,
get_class($this->getEntity())
));
if (!isset($this->_entityChangeSet[$field])) {
throw new \InvalidArgumentException(
"Field '".$field."' is not a valid field of the entity ".
"'".get_class($this->getEntity())."' in PreInsertUpdateEventArgs."
);
}
}
}

View File

@@ -35,55 +35,55 @@ final class Events
/**
* The preRemove event occurs for a given entity before the respective
* EntityManager remove operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preRemove = 'preRemove';
/**
* The postRemove event occurs for an entity after the entity has
* The postRemove event occurs for an entity after the entity has
* been deleted. It will be invoked after the database delete operations.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postRemove = 'postRemove';
/**
* The prePersist event occurs for a given entity before the respective
* EntityManager persist operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const prePersist = 'prePersist';
/**
* The postPersist event occurs for an entity after the entity has
* The postPersist event occurs for an entity after the entity has
* been made persistent. It will be invoked after the database insert operations.
* Generated primary key values are available in the postPersist event.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postPersist = 'postPersist';
/**
* The preUpdate event occurs before the database update operations to
* entity data.
*
* The preUpdate event occurs before the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preUpdate = 'preUpdate';
/**
* The postUpdate event occurs after the database update operations to
* entity data.
*
* The postUpdate event occurs after the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postUpdate = 'postUpdate';
@@ -91,53 +91,35 @@ final class Events
* The postLoad event occurs for an entity after the entity has been loaded
* into the current EntityManager from the database or after the refresh operation
* has been applied to it.
*
*
* Note that the postLoad event occurs for an entity before any associations have been
* initialized. Therefore it is not safe to access associations in a postLoad callback
* or event handler.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postLoad = 'postLoad';
/**
* The loadClassMetadata event occurs after the mapping metadata for a class
* has been loaded from a mapping source (annotations/xml/yaml).
*
*
* @var string
*/
const loadClassMetadata = 'loadClassMetadata';
/**
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
* but before any changes to managed entites have been calculated. This event is
* always raised right after EntityManager#flush() call.
*/
const preFlush = 'preFlush';
/**
* The onFlush event occurs when the EntityManager#flush() operation is invoked,
* after any changes to managed entities have been determined but before any
* actual database operations are executed. The event is only raised if there is
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
* the onFlush event is not raised.
*
*
* @var string
*/
const onFlush = 'onFlush';
/**
* The postFlush event occurs when the EntityManager#flush() operation is invoked and
* after all actual database operations are executed successfully. The event is only raised if there is
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
* the postFlush event is not raised. The event won't be raised if an error occurs during the
* flush operation.
*
* @var string
*/
const postFlush = 'postFlush';
/**
* The onClear event occurs when the EntityManager#clear() operation is invoked,
* after all references to entities have been removed from the unit of work.

View File

@@ -26,7 +26,7 @@ abstract class AbstractIdGenerator
/**
* Generates an identifier for an entity.
*
* @param \Doctrine\ORM\Entity $entity
* @param Doctrine\ORM\Entity $entity
* @return mixed
*/
abstract public function generate(EntityManager $em, $entity);
@@ -35,7 +35,7 @@ abstract class AbstractIdGenerator
* Gets whether this generator is a post-insert generator which means that
* {@link generate()} must be called after the entity has been inserted
* into the database.
*
*
* By default, this method returns FALSE. Generators that have this requirement
* must override this method and return TRUE.
*

View File

@@ -20,7 +20,6 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException;
/**
@@ -43,29 +42,46 @@ class AssignedGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
$class = $em->getClassMetadata(get_class($entity));
$idFields = $class->getIdentifierFieldNames();
$class = $em->getClassMetadata(get_class($entity));
$identifier = array();
foreach ($idFields as $idField) {
$value = $class->reflFields[$idField]->getValue($entity);
if ( ! isset($value)) {
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
}
if (isset($class->associationMappings[$idField])) {
if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
if ($class->isIdentifierComposite) {
$idFields = $class->getIdentifierFieldNames();
foreach ($idFields as $idField) {
$value = $class->reflFields[$idField]->getValue($entity);
if (isset($value)) {
if (isset($class->associationMappings[$idField])) {
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
} else {
$identifier[$idField] = $value;
}
} else {
throw ORMException::entityMissingAssignedId($entity);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$value = current($em->getUnitOfWork()->getEntityIdentifier($value));
}
$identifier[$idField] = $value;
} else {
$idField = $class->identifier[0];
$value = $class->reflFields[$idField]->getValue($entity);
if (isset($value)) {
if (isset($class->associationMappings[$idField])) {
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
} else {
$identifier[$idField] = $value;
}
} else {
throw ORMException::entityMissingAssignedId($entity);
}
}
return $identifier;
}
}
}

View File

@@ -46,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
return (int)$em->getConnection()->lastInsertId($this->_seqName);
return $em->getConnection()->lastInsertId($this->_seqName);
}
/**

View File

@@ -37,7 +37,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
/**
* Initializes a new sequence generator.
*
* @param \Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param string $sequenceName The name of the sequence.
* @param integer $allocationSize The allocation size of the sequence.
*/
@@ -46,7 +46,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
$this->_sequenceName = $sequenceName;
$this->_allocationSize = $allocationSize;
}
/**
* Generates an ID for the given entity.
*
@@ -59,12 +59,10 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values
$conn = $em->getConnection();
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = (int)$conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = $conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
}
return $this->_nextValue++;
}
@@ -92,14 +90,13 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
{
return serialize(array(
'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName
'sequenceName' => $this->_sequenceName
));
}
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->_sequenceName = $array['sequenceName'];
$this->_allocationSize = $array['allocationSize'];
}

View File

@@ -50,12 +50,11 @@ class TableGenerator extends AbstractIdGenerator
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values
$conn = $em->getConnection();
if ($conn->getTransactionNestingLevel() == 0) {
if ($conn->getTransactionNestingLevel() === 0) {
// use select for update
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
$currentLevel = $conn->fetchColumn($sql);
if ($currentLevel != null) {
$this->_nextValue = $currentLevel;
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
@@ -63,7 +62,7 @@ class TableGenerator extends AbstractIdGenerator
$updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
$this->_tableName, $this->_sequenceName, $this->_allocationSize
);
if ($conn->executeUpdate($updateSql, array(1 => $currentLevel, 2 => $currentLevel+1)) !== 1) {
// no affected rows, concurrency issue, throw exception
}
@@ -75,7 +74,6 @@ class TableGenerator extends AbstractIdGenerator
// or do we want to work with table locks exclusively?
}
}
return $this->_nextValue++;
}
}

View File

@@ -23,21 +23,20 @@ namespace Doctrine\ORM\Internal;
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
* correct order in which changes to entities need to be persisted.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class CommitOrderCalculator
{
const NOT_VISITED = 1;
const IN_PROGRESS = 2;
const VISITED = 3;
private $_nodeStates = array();
private $_classes = array(); // The nodes to sort
private $_relatedClasses = array();
private $_sorted = array();
/**
* Clears the current graph.
*
@@ -48,10 +47,10 @@ class CommitOrderCalculator
$this->_classes =
$this->_relatedClasses = array();
}
/**
* Gets a valid commit order for all current nodes.
*
*
* Uses a depth-first search (DFS) to traverse the graph.
* The desired topological sorting is the reverse postorder of these searches.
*
@@ -61,16 +60,17 @@ class CommitOrderCalculator
{
// Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount = count($this->_classes);
if ($nodeCount <= 1) {
return ($nodeCount == 1) ? array_values($this->_classes) : array();
if ($nodeCount == 0) {
return array();
} else if ($nodeCount == 1) {
return array_values($this->_classes);
}
// Init
foreach ($this->_classes as $node) {
$this->_nodeStates[$node->name] = self::NOT_VISITED;
}
// Go
foreach ($this->_classes as $node) {
if ($this->_nodeStates[$node->name] == self::NOT_VISITED) {
@@ -100,17 +100,17 @@ class CommitOrderCalculator
$this->_nodeStates[$node->name] = self::VISITED;
$this->_sorted[] = $node;
}
public function addDependency($fromClass, $toClass)
{
$this->_relatedClasses[$fromClass->name][] = $toClass;
}
public function hasClass($className)
{
return isset($this->_classes[$className]);
}
public function addClass($class)
{
$this->_classes[$class->name] = $class;

View File

@@ -22,17 +22,15 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\Mapping\ClassMetadata;
Doctrine\ORM\EntityManager;
/**
* Base class for all hydrators. A hydrator is a class that provides some form
* of transformation of an SQL result set into another structure.
*
* @since 2.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
* @since 2.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractHydrator
{
@@ -60,13 +58,13 @@ abstract class AbstractHydrator
/**
* Initializes a new instance of a class derived from <tt>AbstractHydrator</tt>.
*
* @param \Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
*/
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->_em = $em;
$this->_platform = $em->getConnection()->getDatabasePlatform();
$this->_uow = $em->getUnitOfWork();
$this->_uow = $em->getUnitOfWork();
}
/**
@@ -74,17 +72,14 @@ abstract class AbstractHydrator
*
* @param object $stmt
* @param object $resultSetMapping
*
* @return IterableResult
*/
public function iterate($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->prepare();
$this->_prepare();
return new IterableResult($this);
}
@@ -97,16 +92,12 @@ abstract class AbstractHydrator
*/
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->prepare();
$result = $this->hydrateAllData();
$this->cleanup();
$this->_prepare();
$result = $this->_hydrateAll();
$this->_cleanup();
return $result;
}
@@ -119,17 +110,12 @@ abstract class AbstractHydrator
public function hydrateRow()
{
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
if ( ! $row) {
$this->cleanup();
$this->_cleanup();
return false;
}
$result = array();
$this->hydrateRowData($row, $this->_cache, $result);
$this->_hydrateRow($row, $this->_cache, $result);
return $result;
}
@@ -137,17 +123,16 @@ abstract class AbstractHydrator
* Excutes one-time preparation tasks, once each time hydration is started
* through {@link hydrateAll} or {@link iterate()}.
*/
protected function prepare()
protected function _prepare()
{}
/**
* Excutes one-time cleanup tasks at the end of a hydration that was initiated
* through {@link hydrateAll} or {@link iterate()}.
*/
protected function cleanup()
protected function _cleanup()
{
$this->_rsm = null;
$this->_stmt->closeCursor();
$this->_stmt = null;
}
@@ -161,81 +146,61 @@ abstract class AbstractHydrator
* @param array $cache The cache to use.
* @param mixed $result The result to fill.
*/
protected function hydrateRowData(array $data, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
throw new HydrationException("_hydrateRow() not implemented by this hydrator.");
}
/**
* Hydrates all rows from the current statement instance at once.
*/
abstract protected function hydrateAllData();
abstract protected function _hydrateAll();
/**
* Processes a row of the result set.
*
* Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY).
* Puts the elements of a result row into a new array, grouped by the dql alias
* Puts the elements of a result row into a new array, grouped by the class
* they belong to. The column names in the result set are mapped to their
* field names during this procedure as well as any necessary conversions on
* the values applied. Scalar values are kept in a specfic key 'scalars'.
*
* @param array $data SQL Result Row
* @param array &$cache Cache for column to field result information
* @param array &$id Dql-Alias => ID-Hash
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
* the values applied.
*
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias.
*/
protected function gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
protected function _gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
{
$rowData = array();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
switch (true) {
// NOTE: Most of the times it's a field mapping, so keep it first!!!
case (isset($this->_rsm->fieldMappings[$key])):
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
case (isset($this->_rsm->scalarMappings[$key])):
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['type'] = Type::getType($this->_rsm->typeMappings[$key]);
$cache[$key]['isScalar'] = true;
break;
case (isset($this->_rsm->metaMappings[$key])):
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$fieldName = $this->_rsm->metaMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$this->_rsm->columnOwnerMap[$key]]);
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
break;
default:
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue 2;
if (isset($this->_rsm->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
} else if (isset($this->_rsm->fieldMappings[$key])) {
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else if (!isset($this->_rsm->metaMappings[$key])) {
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue;
} else {
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$fieldName = $this->_rsm->metaMappings[$key];
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$cache[$key]['dqlAlias']]);
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
}
}
if (isset($cache[$key]['isScalar'])) {
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
continue;
}
@@ -246,17 +211,13 @@ abstract class AbstractHydrator
}
if (isset($cache[$key]['isMetaColumn'])) {
if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value !== null) {
if (!isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) {
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
if ($cache[$key]['isIdentifier']) {
$nonemptyComponents[$dqlAlias] = true;
}
}
continue;
}
// in an inheritance hierarchy the same field could be defined several times.
// in an inheritance hierachy the same field could be defined several times.
// We overwrite this value so long we dont have a non-null value, that value we keep.
// Per definition it cannot be that a field is defined several times and has several values.
if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) {
@@ -275,7 +236,6 @@ abstract class AbstractHydrator
/**
* Processes a row of the result set.
*
* Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that
* simply converts column names to field names and properly converts the
* values according to their types. The resulting row has the same number
@@ -283,77 +243,52 @@ abstract class AbstractHydrator
*
* @param array $data
* @param array $cache
*
* @return array The processed row.
*/
protected function gatherScalarRowData(&$data, &$cache)
protected function _gatherScalarRowData(&$data, &$cache)
{
$rowData = array();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
switch (true) {
// NOTE: During scalar hydration, most of the times it's a scalar mapping, keep it first!!!
case (isset($this->_rsm->scalarMappings[$key])):
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
break;
case (isset($this->_rsm->fieldMappings[$key])):
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
case (isset($this->_rsm->metaMappings[$key])):
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key];
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
default:
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue 2;
if (isset($this->_rsm->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
} else if (isset($this->_rsm->fieldMappings[$key])) {
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else if (!isset($this->_rsm->metaMappings[$key])) {
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue;
} else {
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key];
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
}
}
$fieldName = $cache[$key]['fieldName'];
switch (true) {
case (isset($cache[$key]['isScalar'])):
$rowData[$fieldName] = $value;
break;
case (isset($cache[$key]['isMetaColumn'])):
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
break;
default:
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
if (isset($cache[$key]['isScalar'])) {
$rowData[$fieldName] = $value;
} else if (isset($cache[$key]['isMetaColumn'])) {
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
} else {
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $cache[$key]['type']
->convertToPHPValue($value, $this->_platform);
}
}
return $rowData;
}
/**
* Register entity as managed in UnitOfWork.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
* @param object $entity
* @param array $data
*
* @todo The "$id" generation is the same of UnitOfWork#createEntity. Remove this duplication somehow
*/
protected function registerManaged(ClassMetadata $class, $entity, array $data)
protected function registerManaged($class, $entity, $data)
{
if ($class->isIdentifierComposite) {
$id = array();
@@ -371,7 +306,6 @@ abstract class AbstractHydrator
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
}
}
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
}

View File

@@ -25,9 +25,8 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
* The ArrayHydrator produces a nested array "graph" that is often (not always)
* interchangeable with the corresponding object graph for read-only access.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
* @since 1.0
*/
class ArrayHydrator extends AbstractHydrator
{
@@ -39,55 +38,45 @@ class ArrayHydrator extends AbstractHydrator
private $_idTemplate = array();
private $_resultCounter = 0;
/**
* {@inheritdoc}
*/
protected function prepare()
/** @override */
protected function _prepare()
{
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
$this->_identifierMap = array();
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
$this->_identifierMap = array();
$this->_resultPointers = array();
$this->_idTemplate = array();
$this->_resultCounter = 0;
$this->_idTemplate = array();
$this->_resultCounter = 0;
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
$this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$this->_idTemplate[$dqlAlias] = '';
}
}
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
/** @override */
protected function _hydrateAll()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->hydrateRowData($data, $cache, $result);
$this->_hydrateRow($data, $cache, $result);
}
return $result;
}
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $row, array &$cache, array &$result)
/** @override */
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
// 1) Initialize
$id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array();
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
// Extract scalar values. They're appended at the end.
if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars'];
unset($rowData['scalars']);
if (empty($rowData)) {
++$this->_resultCounter;
}
@@ -101,12 +90,7 @@ class ArrayHydrator extends AbstractHydrator
// It's a joined result
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
$path = $parent . '.' . $dqlAlias;
// missing parent data, skipping as RIGHT JOIN hydration is not supported.
if ( ! isset($nonemptyComponents[$parent]) ) {
continue;
}
$path = $parent . '.' . $dqlAlias;
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
@@ -120,41 +104,39 @@ class ArrayHydrator extends AbstractHydrator
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
continue;
}
$relationAlias = $this->_rsm->relationMap[$dqlAlias];
$relation = $this->getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
$relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
// Check the type of the relation (many or single-valued)
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array();
}
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
if ( ! $indexExists || ! $indexIsValid) {
$element = $data;
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $element;
$field = $this->_rsm->indexByMap[$dqlAlias];
$baseElement[$relationAlias][$element[$field]] = $element;
} else {
$baseElement[$relationAlias][] = $element;
}
end($baseElement[$relationAlias]);
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] =
key($baseElement[$relationAlias]);
}
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array();
}
} else {
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) {
@@ -170,42 +152,32 @@ class ArrayHydrator extends AbstractHydrator
} else {
// It's a root result element
$this->_rootAliases[$dqlAlias] = true; // Mark as root
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
// 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;
}
$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);
}
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
$result[$resultKey] = $element;
$field = $this->_rsm->indexByMap[$dqlAlias];
if ($this->_rsm->isMixed) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
$resultKey = $this->_resultCounter;
$result[] = $element;
++$this->_resultCounter;
if ($this->_rsm->isMixed) {
$result[] = array($element);
++$this->_resultCounter;
} else {
$result[] = $element;
}
}
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
end($result);
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
} else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] =& $result[$index];
++$this->_resultCounter;
@@ -217,17 +189,8 @@ class ArrayHydrator extends AbstractHydrator
// Append scalar values to mixed result sets
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;
}
}
foreach ($scalars as $name => $value) {
$result[$resultKey][$name] = $value;
$result[$this->_resultCounter - 1][$name] = $value;
}
}
}
@@ -245,45 +208,28 @@ class ArrayHydrator extends AbstractHydrator
{
if ($coll === null) {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
return;
}
if ($index !== false) {
$this->_resultPointers[$dqlAlias] =& $coll[$index];
return;
} else {
if ($coll) {
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
} else {
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
}
}
}
if ( ! $coll) {
return;
}
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
return;
}
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
return;
}
/**
* Retrieve ClassMetadata associated to entity class name.
*
* @param string $className
*
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
private function getClassMetadata($className)
private function _getClassMetadata($className)
{
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
}
}

View File

@@ -8,19 +8,10 @@ class HydrationException extends \Doctrine\ORM\ORMException
{
return new self("The result returned by the query was not unique.");
}
public static function parentObjectOfRelationNotFound($alias, $parentAlias)
{
return new self("The parent object of entity result with alias '$alias' was not found."
. " The parent alias is '$parentAlias'.");
}
public static function emptyDiscriminatorValue($dqlAlias)
{
return new self("The DQL alias '" . $dqlAlias . "' contains an entity ".
"of an inheritance hierachy with an empty discriminator value. This means " .
"that the database contains inconsistent data with an empty " .
"discriminator value in a table row."
);
}
}

View File

@@ -29,7 +29,7 @@ namespace Doctrine\ORM\Internal\Hydration;
class IterableResult implements \Iterator
{
/**
* @var \Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @var Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
private $_hydrator;
@@ -49,7 +49,7 @@ class IterableResult implements \Iterator
private $_current = null;
/**
* @param \Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
* @param Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
*/
public function __construct($hydrator)
{

View File

@@ -23,19 +23,14 @@ use PDO,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Query,
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Events,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\Common\Collections\Collection,
Doctrine\ORM\Proxy\Proxy;
Doctrine\Common\Collections\Collection;
/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @since 2.0
* @internal Highly performance-sensitive code.
*/
class ObjectHydrator extends AbstractHydrator
@@ -58,63 +53,59 @@ class ObjectHydrator extends AbstractHydrator
/** @override */
protected function prepare()
protected function _prepare()
{
$this->_identifierMap =
$this->_resultPointers =
$this->_idTemplate = array();
$this->_resultCounter = 0;
if ( ! isset($this->_hints['deferEagerLoad'])) {
if (!isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true;
}
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$this->_idTemplate[$dqlAlias] = '';
$class = $this->_em->getClassMetadata($className);
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
$this->_ce[$className] = $class;
}
// Remember which associations are "fetch joined", so that we know where to inject
// collection stubs or proxies and where not.
if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
continue;
}
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) {
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]);
}
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$sourceClass = $this->_getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$this->_rsm->parentAliasMap[$dqlAlias]][$assoc['fieldName']] = true;
if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
continue;
}
// Mark any non-collection opposite sides as fetched, too.
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true;
continue;
}
// handle fetch-joined owning side bi-directional one-to-one associations
if ($assoc['inversedBy']) {
$class = $this->_ce[$className];
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
continue;
if (isset($this->_rsm->relationMap[$dqlAlias])) {
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) {
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]);
}
$this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$sourceClass = $this->_getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$sourceClassName][$assoc['fieldName']] = true;
if ($sourceClass->subClasses) {
foreach ($sourceClass->subClasses as $sourceSubclassName) {
$this->_hints['fetched'][$sourceSubclassName][$assoc['fieldName']] = true;
}
}
if ($assoc['type'] != ClassMetadata::MANY_TO_MANY) {
// Mark any non-collection opposite sides as fetched, too.
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$className][$assoc['mappedBy']] = true;
} else {
if ($assoc['inversedBy']) {
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
$this->_hints['fetched'][$className][$inverseAssoc['fieldName']] = true;
if ($class->subClasses) {
foreach ($class->subClasses as $targetSubclassName) {
$this->_hints['fetched'][$targetSubclassName][$inverseAssoc['fieldName']] = true;
}
}
}
}
}
}
}
}
}
@@ -122,17 +113,16 @@ class ObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function cleanup()
protected function _cleanup()
{
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
parent::cleanup();
parent::_cleanup();
$this->_identifierMap =
$this->_initializedCollections =
$this->_existingCollections =
$this->_resultPointers = array();
if ($eagerLoad) {
$this->_em->getUnitOfWork()->triggerEagerLoads();
}
@@ -141,13 +131,13 @@ class ObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
protected function _hydrateAll()
{
$result = array();
$cache = array();
$cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->hydrateRowData($row, $cache, $result);
$this->_hydrateRow($row, $cache, $result);
}
// Take snapshots from all newly initialized collections
@@ -162,40 +152,35 @@ class ObjectHydrator extends AbstractHydrator
* Initializes a related collection.
*
* @param object $entity The entity to which the collection belongs.
* @param ClassMetadata $class
* @param string $name The name of the field on the entity that holds the collection.
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
*/
private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
private function _initRelatedCollection($entity, $class, $fieldName)
{
$oid = spl_object_hash($entity);
$oid = spl_object_hash($entity);
$relation = $class->associationMappings[$fieldName];
$value = $class->reflFields[$fieldName]->getValue($entity);
$value = $class->reflFields[$fieldName]->getValue($entity);
if ($value === null) {
$value = new ArrayCollection;
}
if ( ! $value instanceof PersistentCollection) {
$value = new PersistentCollection(
$this->_em, $this->_ce[$relation['targetEntity']], $value
$this->_em,
$this->_ce[$relation['targetEntity']],
$value
);
$value->setOwner($entity, $relation);
$class->reflFields[$fieldName]->setValue($entity, $value);
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
$this->_initializedCollections[$oid . $fieldName] = $value;
} else if (
isset($this->_hints[Query::HINT_REFRESH]) ||
isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
! $value->isInitialized()
) {
} else if (isset($this->_hints[Query::HINT_REFRESH]) ||
isset($this->_hints['fetched'][$class->name][$fieldName]) &&
! $value->isInitialized()) {
// Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
$value->setDirty(false);
$value->setInitialized(true);
$value->unwrap()->clear();
$this->_initializedCollections[$oid . $fieldName] = $value;
} else {
// Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
@@ -207,7 +192,7 @@ class ObjectHydrator extends AbstractHydrator
/**
* Gets an entity instance.
*
*
* @param $data The instance data.
* @param $dqlAlias The DQL alias of the entity's class.
* @return object The entity.
@@ -215,25 +200,17 @@ class ObjectHydrator extends AbstractHydrator
private function _getEntity(array $data, $dqlAlias)
{
$className = $this->_rsm->aliasMap[$dqlAlias];
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
$discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]];
if ($data[$discrColumn] === "") {
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
}
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
unset($data[$discrColumn]);
}
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
$this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
$class = $this->_ce[$className];
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
$this->_hints['fetchAlias'] = $dqlAlias;
return $this->_uow->createEntity($className, $data, $this->_hints);
}
@@ -241,7 +218,6 @@ class ObjectHydrator extends AbstractHydrator
{
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
$class = $this->_ce[$className];
/* @var $class ClassMetadata */
if ($class->isIdentifierComposite) {
$idHash = '';
@@ -264,7 +240,7 @@ class ObjectHydrator extends AbstractHydrator
* Gets a ClassMetadata instance from the local cache.
* If the instance is not yet in the local cache, it is loaded into the
* local cache.
*
*
* @param string $className The name of the class.
* @return ClassMetadata
*/
@@ -273,45 +249,42 @@ class ObjectHydrator extends AbstractHydrator
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
/**
* Hydrates a single row in an SQL result set.
*
*
* @internal
* First, the data of the row is split into chunks where each chunk contains data
* that belongs to a particular component/class. Afterwards, all these chunks
* are processed, one after the other. For each chunk of class data only one of the
* following code paths is executed:
*
*
* Path A: The data chunk belongs to a joined/associated object and the association
* is collection-valued.
* Path B: The data chunk belongs to a joined/associated object and the association
* is single-valued.
* Path C: The data chunk belongs to a root result element/object that appears in the topmost
* level of the hydrated result. A typical example are the objects of the type
* specified by the FROM clause in a DQL query.
*
* specified by the FROM clause in a DQL query.
*
* @param array $data The data of the row to process.
* @param array $cache The cache to use.
* @param array $result The result array to fill.
*/
protected function hydrateRowData(array $row, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
// Initialize
$id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array();
// Split the row data into chunks of class data.
$rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
// Extract scalar values. They're appended at the end.
if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars'];
unset($rowData['scalars']);
if (empty($rowData)) {
++$this->_resultCounter;
}
@@ -329,16 +302,10 @@ class ObjectHydrator extends AbstractHydrator
// seen for this parent-child relationship
$path = $parentAlias . '.' . $dqlAlias;
// We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
if (!isset($nonemptyComponents[$parentAlias])) {
// TODO: Add special case code where we hydrate the right join objects into identity map at least
continue;
}
// Get a reference to the parent object to which the joined element belongs.
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) {
$first = reset($this->_resultPointers);
$parentObject = $first[key($first)];
$parentObject = $this->_resultPointers[$parentAlias][key($first)];
} else if (isset($this->_resultPointers[$parentAlias])) {
$parentObject = $this->_resultPointers[$parentAlias];
} else {
@@ -354,14 +321,13 @@ class ObjectHydrator extends AbstractHydrator
// Check the type of the relation (many or single-valued)
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
$reflFieldValue = $reflField->getValue($parentObject);
// PATH A: Collection-valued association
if (isset($nonemptyComponents[$dqlAlias])) {
$collKey = $oid . $relationField;
if (isset($this->_initializedCollections[$collKey])) {
$reflFieldValue = $this->_initializedCollections[$collKey];
} else if ( ! isset($this->_existingCollections[$collKey])) {
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
}
$indexExists = isset($this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
@@ -380,7 +346,8 @@ class ObjectHydrator extends AbstractHydrator
$element = $this->_getEntity($data, $dqlAlias);
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
$field = $this->_rsm->indexByMap[$dqlAlias];
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
$reflFieldValue->hydrateSet($indexValue, $element);
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
} else {
@@ -395,24 +362,21 @@ class ObjectHydrator extends AbstractHydrator
// Update result pointer
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
}
} else if ( ! $reflFieldValue) {
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
$reflFieldValue->setInitialized(true);
} else if ( ! $reflField->getValue($parentObject)) {
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
$coll->setOwner($parentObject, $relation);
$reflField->setValue($parentObject, $coll);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
}
} else {
// PATH B: Single-valued association
$reflFieldValue = $reflField->getValue($parentObject);
if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
// we only need to take action if this value is null,
// we refresh the entity or its an unitialized proxy.
if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH])) {
if (isset($nonemptyComponents[$dqlAlias])) {
$element = $this->_getEntity($data, $dqlAlias);
$reflField->setValue($parentObject, $element);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
$targetClass = $this->_ce[$relation['targetEntity']];
if ($relation['isOwningSide']) {
//TODO: Just check hints['fetched'] here?
// If there is an inverse mapping on the target class its bidirectional
@@ -433,8 +397,6 @@ class ObjectHydrator extends AbstractHydrator
}
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;
} else {
$this->_uow->setOriginalEntityProperty($oid, $relationField, null);
}
// else leave $reflFieldValue null for single-valued associations
} else {
@@ -445,48 +407,38 @@ class ObjectHydrator extends AbstractHydrator
} else {
// PATH C: Its a root result element
$this->_rootAliases[$dqlAlias] = true; // Mark as root alias
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
// 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;
}
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
continue;
}
// check for existing result from the iterations before
if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateSet($resultKey, $element);
$field = $this->_rsm->indexByMap[$dqlAlias];
$key = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
if ($this->_rsm->isMixed) {
$element = array($key => $element);
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter;
} else {
$result[$key] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key;
}
$result[$resultKey] = $element;
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateSet($key, $element);
}
} else {
$resultKey = $this->_resultCounter;
if ($this->_rsm->isMixed) {
$element = array(0 => $element);
}
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter;
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateAdd($element);
}
$result[] = $element;
}
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;
@@ -494,7 +446,6 @@ class ObjectHydrator extends AbstractHydrator
// Update result pointer
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$this->_resultPointers[$dqlAlias] = $result[$index];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] = $result[$index];
++$this->_resultCounter;
@@ -505,16 +456,8 @@ class ObjectHydrator extends AbstractHydrator
// Append scalar values to mixed result sets
if (isset($scalars)) {
if ( ! isset($resultKey) ) {
if (isset($this->_rsm->indexByMap['scalars'])) {
$resultKey = $row[$this->_rsm->indexByMap['scalars']];
} else {
$resultKey = $this->_resultCounter - 1;
}
}
foreach ($scalars as $name => $value) {
$result[$resultKey][$name] = $value;
$result[$this->_resultCounter - 1][$name] = $value;
}
}
}

View File

@@ -26,32 +26,25 @@ use Doctrine\DBAL\Connection;
* The created result is almost the same as a regular SQL result set, except
* that column names are mapped to field names and data type conversions take place.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @since 2.0
*/
class ScalarHydrator extends AbstractHydrator
{
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
/** @override */
protected function _hydrateAll()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$this->hydrateRowData($data, $cache, $result);
$result[] = $this->_gatherScalarRowData($data, $cache);
}
return $result;
}
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$cache, array &$result)
/** @override */
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
$result[] = $this->gatherScalarRowData($data, $cache);
$result[] = $this->_gatherScalarRowData($data, $cache);
}
}

View File

@@ -17,14 +17,13 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Internal\Hydration;
use \PDO,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Events,
Doctrine\ORM\Query;
use \PDO;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query;
class SimpleObjectHydrator extends AbstractHydrator
{
@@ -33,21 +32,15 @@ class SimpleObjectHydrator extends AbstractHydrator
*/
private $class;
/**
* @var array
*/
private $declaringClasses = array();
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
protected function _hydrateAll()
{
$result = array();
$cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->hydrateRowData($row, $cache, $result);
$this->_hydrateRow($row, $cache, $result);
}
$this->_em->getUnitOfWork()->triggerEagerLoads();
@@ -55,129 +48,84 @@ class SimpleObjectHydrator extends AbstractHydrator
return $result;
}
/**
* {@inheritdoc}
*/
protected function prepare()
protected function _prepare()
{
if (count($this->_rsm->aliasMap) !== 1) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
if (count($this->_rsm->aliasMap) == 1) {
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
foreach ($this->_rsm->declaringClasses AS $column => $class) {
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
}
}
} else {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping not containing exactly one object result.");
}
if ($this->_rsm->scalarMappings) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
}
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
// We only need to add declaring classes if we have inheritance.
if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) {
return;
}
foreach ($this->_rsm->declaringClasses AS $column => $class) {
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
}
}
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$cache, array &$result)
protected function _hydrateRow(array $sqlResult, array &$cache, array &$result)
{
$entityName = $this->class->name;
$data = array();
$data = array();
if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) {
foreach ($sqlResult as $column => $value) {
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
if ($sqlResult[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
}
foreach ($sqlResult as $column => $value) {
// Hydrate column information if not yet present
if ( ! isset($cache[$column])) {
if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
continue;
if (!isset($cache[$column])) {
if (isset($this->_rsm->fieldMappings[$column])) {
$cache[$column]['name'] = $this->_rsm->fieldMappings[$column];
$cache[$column]['field'] = true;
} else {
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
}
}
$cache[$column] = $info;
}
// 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);
}
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) {
if (isset($cache[$column]['field'])) {
$value = Type::getType($this->class->fieldMappings[$cache[$column]['name']]['type'])
->convertToPHPValue($value, $this->_platform);
}
$data[$cache[$column]['name']] = $value;
}
$entityName = $this->class->name;
} else {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
foreach ($sqlResult as $column => $value) {
if (!isset($cache[$column])) {
if (isset($this->_rsm->fieldMappings[$column])) {
$field = $this->_rsm->fieldMappings[$column];
$class = $this->declaringClasses[$column];
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
$cache[$column]['name'] = $field;
$cache[$column]['class'] = $class;
}
} else if (isset($this->_rsm->relationMap[$column])) {
if ($this->_rsm->relationMap[$column] == $entityName || is_subclass_of($entityName, $this->_rsm->relationMap[$column])) {
$cache[$column]['name'] = $field;
}
} else {
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
}
}
if (isset($cache[$column]['class'])) {
$value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type'])
->convertToPHPValue($value, $this->_platform);
}
// the second and part is to prevent overwrites in case of multiple
// inheritance classes using the same property name (See AbstractHydrator)
if (isset($cache[$column]) && (!isset($data[$cache[$column]['name']]) || $value !== null)) {
$data[$cache[$column]['name']] = $value;
}
}
}
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY])) {
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
$uow = $this->_em->getUnitOfWork();
$entity = $uow->createEntity($entityName, $data, $this->_hints);
$result[] = $entity;
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
}
/**
* Retrieve column information form ResultSetMapping.
*
* @param string $entityName
* @param string $column
*
* @return array
*/
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;
}
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);
default:
return array(
'name' => $this->_rsm->metaMappings[$column]
);
}
}
}
}

View File

@@ -19,38 +19,31 @@
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection,
Doctrine\ORM\NoResultException,
Doctrine\ORM\NonUniqueResultException;
use Doctrine\DBAL\Connection;
/**
* Hydrator that hydrates a single scalar value from the result set.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @since 2.0
*/
class SingleScalarHydrator extends AbstractHydrator
{
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
/** @override */
protected function _hydrateAll()
{
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$numRows = count($data);
$cache = array();
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$num = count($result);
if ($numRows === 0) {
throw new NoResultException();
if ($num == 0) {
throw new \Doctrine\ORM\NoResultException;
} else if ($num > 1 || count($result[key($result)]) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
}
if ($numRows > 1 || count($data[key($data)]) > 1) {
throw new NonUniqueResultException();
}
$cache = array();
$result = $this->gatherScalarRowData($data[key($data)], $cache);
$result = $this->_gatherScalarRowData($result[key($result)], $cache);
return array_shift($result);
}
}

View File

@@ -1,24 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
interface Annotation
{
}

View File

@@ -1,167 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
use Doctrine\ORM\Mapping\ClassMetadata;
class AssociationBuilder
{
/**
* @var ClassMetadataBuilder
*/
protected $builder;
/**
* @var array
*/
protected $mapping;
/**
* @var array
*/
protected $joinColumns;
/**
*
* @var int
*/
protected $type;
/**
* @param ClassMetadataBuilder $builder
* @param array $mapping
*/
public function __construct(ClassMetadataBuilder $builder, array $mapping, $type)
{
$this->builder = $builder;
$this->mapping = $mapping;
$this->type = $type;
}
public function mappedBy($fieldName)
{
$this->mapping['mappedBy'] = $fieldName;
return $this;
}
public function inversedBy($fieldName)
{
$this->mapping['inversedBy'] = $fieldName;
return $this;
}
public function cascadeAll()
{
$this->mapping['cascade'] = array("ALL");
return $this;
}
public function cascadePersist()
{
$this->mapping['cascade'][] = "persist";
return $this;
}
public function cascadeRemove()
{
$this->mapping['cascade'][] = "remove";
return $this;
}
public function cascadeMerge()
{
$this->mapping['cascade'][] = "merge";
return $this;
}
public function cascadeDetach()
{
$this->mapping['cascade'][] = "detach";
return $this;
}
public function cascadeRefresh()
{
$this->mapping['cascade'][] = "refresh";
return $this;
}
public function fetchExtraLazy()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY;
return $this;
}
public function fetchEager()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_EAGER;
return $this;
}
public function fetchLazy()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_LAZY;
return $this;
}
/**
* Add Join Columns
*
* @param string $columnName
* @param string $referencedColumnName
* @param bool $nullable
* @param bool $unique
* @param string $onDelete
* @param string $columnDef
*/
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
$this->joinColumns[] = array(
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'nullable' => $nullable,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
);
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
if ($this->joinColumns) {
$mapping['joinColumns'] = $this->joinColumns;
}
$cm = $this->builder->getClassMetadata();
if ($this->type == ClassMetadata::MANY_TO_ONE) {
$cm->mapManyToOne($mapping);
} else if ($this->type == ClassMetadata::ONE_TO_ONE) {
$cm->mapOneToOne($mapping);
} else {
throw new \InvalidArgumentException("Type should be a ToOne Assocation here");
}
return $this->builder;
}
}

View File

@@ -1,470 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* Builder Object for ClassMetadata
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class ClassMetadataBuilder
{
/**
* @var \Doctrine\ORM\Mapping\ClassMetadataInfo
*/
private $cm;
/**
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm
*/
public function __construct(ClassMetadataInfo $cm)
{
$this->cm = $cm;
}
/**
* @return ClassMetadata
*/
public function getClassMetadata()
{
return $this->cm;
}
/**
* Mark the class as mapped superclass.
*
* @return ClassMetadataBuilder
*/
public function setMappedSuperClass()
{
$this->cm->isMappedSuperclass = true;
return $this;
}
/**
* Set custom Repository class name
*
* @param string $repositoryClassName
* @return ClassMetadataBuilder
*/
public function setCustomRepositoryClass($repositoryClassName)
{
$this->cm->setCustomRepositoryClass($repositoryClassName);
return $this;
}
/**
* Mark class read only
*
* @return ClassMetadataBuilder
*/
public function setReadOnly()
{
$this->cm->markReadOnly();
return $this;
}
/**
* Set the table name
*
* @param string $name
* @return ClassMetadataBuilder
*/
public function setTable($name)
{
$this->cm->setPrimaryTable(array('name' => $name));
return $this;
}
/**
* Add Index
*
* @param array $columns
* @param string $name
* @return ClassMetadataBuilder
*/
public function addIndex(array $columns, $name)
{
if (!isset($this->cm->table['indexes'])) {
$this->cm->table['indexes'] = array();
}
$this->cm->table['indexes'][$name] = array('columns' => $columns);
return $this;
}
/**
* Add Unique Constraint
*
* @param array $columns
* @param string $name
* @return ClassMetadataBuilder
*/
public function addUniqueConstraint(array $columns, $name)
{
if ( ! isset($this->cm->table['uniqueConstraints'])) {
$this->cm->table['uniqueConstraints'] = array();
}
$this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns);
return $this;
}
/**
* Add named query
*
* @param string $name
* @param string $dqlQuery
* @return ClassMetadataBuilder
*/
public function addNamedQuery($name, $dqlQuery)
{
$this->cm->addNamedQuery(array(
'name' => $name,
'query' => $dqlQuery,
));
return $this;
}
/**
* Set class as root of a joined table inheritance hierachy.
*
* @return ClassMetadataBuilder
*/
public function setJoinedTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED);
return $this;
}
/**
* Set class as root of a single table inheritance hierachy.
*
* @return ClassMetadataBuilder
*/
public function setSingleTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
return $this;
}
/**
* Set the discriminator column details.
*
* @param string $name
* @param string $type
*/
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
{
$this->cm->setDiscriminatorColumn(array(
'name' => $name,
'type' => $type,
'length' => $length,
));
return $this;
}
/**
* Add a subclass to this inheritance hierachy.
*
* @param string $name
* @param string $class
* @return ClassMetadataBuilder
*/
public function addDiscriminatorMapClass($name, $class)
{
$this->cm->addDiscriminatorMapClass($name, $class);
return $this;
}
/**
* Set deferred explicit change tracking policy.
*
* @return ClassMetadataBuilder
*/
public function setChangeTrackingPolicyDeferredExplicit()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT);
return $this;
}
/**
* Set notify change tracking policy.
*
* @return ClassMetadataBuilder
*/
public function setChangeTrackingPolicyNotify()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY);
return $this;
}
/**
* Add lifecycle event
*
* @param string $methodName
* @param string $event
* @return ClassMetadataBuilder
*/
public function addLifecycleEvent($methodName, $event)
{
$this->cm->addLifecycleCallback($methodName, $event);
return $this;
}
/**
* Add Field
*
* @param string $name
* @param string $type
* @param array $mapping
*/
public function addField($name, $type, array $mapping = array())
{
$mapping['fieldName'] = $name;
$mapping['type'] = $type;
$this->cm->mapField($mapping);
return $this;
}
/**
* Create a field builder.
*
* @param string $name
* @param string $type
* @return FieldBuilder
*/
public function createField($name, $type)
{
return new FieldBuilder(
$this,
array(
'fieldName' => $name,
'type' => $type
)
);
}
/**
* Add a simple many to one association, optionally with the inversed by field.
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
* @return ClassMetadataBuilder
*/
public function addManyToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToOne($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Create a ManyToOne Assocation Builder.
*
* Note: This method does not add the association, you have to call build() on the AssociationBuilder.
*
* @param string $name
* @param string $targetEntity
* @return AssociationBuilder
*/
public function createManyToOne($name, $targetEntity)
{
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_ONE
);
}
/**
* Create OneToOne Assocation Builder
*
* @param string $name
* @param string $targetEntity
* @return AssociationBuilder
*/
public function createOneToOne($name, $targetEntity)
{
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_ONE
);
}
/**
* Add simple inverse one-to-one assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addInverseOneToOne($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToOne($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
/**
* Add simple owning one-to-one assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $inversedBy
* @return ClassMetadataBuilder
*/
public function addOwningOneToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createOneToOne($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Create ManyToMany Assocation Builder
*
* @param string $name
* @param string $targetEntity
* @return ManyToManyAssociationBuilder
*/
public function createManyToMany($name, $targetEntity)
{
return new ManyToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_MANY
);
}
/**
* Add a simple owning many to many assocation.
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
* @return ClassMetadataBuilder
*/
public function addOwningManyToMany($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToMany($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Add a simple inverse many to many assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addInverseManyToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createManyToMany($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
/**
* Create a one to many assocation builder
*
* @param string $name
* @param string $targetEntity
* @return OneToManyAssociationBuilder
*/
public function createOneToMany($name, $targetEntity)
{
return new OneToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_MANY
);
}
/**
* Add simple OneToMany assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addOneToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToMany($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
}

View File

@@ -1,223 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* Field Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class FieldBuilder
{
/**
* @var ClassMetadataBuilder
*/
private $builder;
/**
* @var array
*/
private $mapping;
/**
* @var bool
*/
private $version;
/**
* @var string
*/
private $generatedValue;
/**
* @var array
*/
private $sequenceDef;
/**
*
* @param ClassMetadataBuilder $builder
* @param array $mapping
*/
public function __construct(ClassMetadataBuilder $builder, array $mapping)
{
$this->builder = $builder;
$this->mapping = $mapping;
}
/**
* Set length.
*
* @param int $length
* @return FieldBuilder
*/
public function length($length)
{
$this->mapping['length'] = $length;
return $this;
}
/**
* Set nullable
*
* @param bool
* @return FieldBuilder
*/
public function nullable($flag = true)
{
$this->mapping['nullable'] = (bool)$flag;
return $this;
}
/**
* Set Unique
*
* @param bool
* @return FieldBuilder
*/
public function unique($flag = true)
{
$this->mapping['unique'] = (bool)$flag;
return $this;
}
/**
* Set column name
*
* @param string $name
* @return FieldBuilder
*/
public function columnName($name)
{
$this->mapping['columnName'] = $name;
return $this;
}
/**
* Set Precision
*
* @param int $p
* @return FieldBuilder
*/
public function precision($p)
{
$this->mapping['precision'] = $p;
return $this;
}
/**
* Set scale.
*
* @param int $s
* @return FieldBuilder
*/
public function scale($s)
{
$this->mapping['scale'] = $s;
return $this;
}
/**
* Set field as primary key.
*
* @return FieldBuilder
*/
public function isPrimaryKey()
{
$this->mapping['id'] = true;
return $this;
}
/**
* @param int $strategy
* @return FieldBuilder
*/
public function generatedValue($strategy = 'AUTO')
{
$this->generatedValue = $strategy;
return $this;
}
/**
* Set field versioned
*
* @return FieldBuilder
*/
public function isVersionField()
{
$this->version = true;
return $this;
}
/**
* Set Sequence Generator
*
* @param string $sequenceName
* @param int $allocationSize
* @param int $initialValue
* @return FieldBuilder
*/
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
{
$this->sequenceDef = array(
'sequenceName' => $sequenceName,
'allocationSize' => $allocationSize,
'initialValue' => $initialValue,
);
return $this;
}
/**
* Set column definition.
*
* @param string $def
* @return FieldBuilder
*/
public function columnDefinition($def)
{
$this->mapping['columnDefinition'] = $def;
return $this;
}
/**
* Finalize this field and attach it to the ClassMetadata.
*
* Without this call a FieldBuilder has no effect on the ClassMetadata.
*
* @return ClassMetadataBuilder
*/
public function build()
{
$cm = $this->builder->getClassMetadata();
if ($this->generatedValue) {
$cm->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $this->generatedValue));
}
if ($this->version) {
$cm->setVersionMapping($this->mapping);
}
$cm->mapField($this->mapping);
if ($this->sequenceDef) {
$cm->setSequenceGeneratorDefinition($this->sequenceDef);
}
return $this->builder;
}
}

View File

@@ -1,86 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* ManyToMany Association Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
{
private $joinTableName;
private $inverseJoinColumns = array();
public function setJoinTable($name)
{
$this->joinTableName = $name;
return $this;
}
/**
* Add Inverse Join Columns
*
* @param string $columnName
* @param string $referencedColumnName
* @param bool $nullable
* @param bool $unique
* @param string $onDelete
* @param string $columnDef
*/
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
$this->inverseJoinColumns[] = array(
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'nullable' => $nullable,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
);
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
$mapping['joinTable'] = array();
if ($this->joinColumns) {
$mapping['joinTable']['joinColumns'] = $this->joinColumns;
}
if ($this->inverseJoinColumns) {
$mapping['joinTable']['inverseJoinColumns'] = $this->inverseJoinColumns;
}
if ($this->joinTableName) {
$mapping['joinTable']['name'] = $this->joinTableName;
}
$cm = $this->builder->getClassMetadata();
$cm->mapManyToMany($mapping);
return $this->builder;
}
}

View File

@@ -1,62 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* OneToMany Association Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class OneToManyAssociationBuilder extends AssociationBuilder
{
/**
* @param array $fieldNames
* @return OneToManyAssociationBuilder
*/
public function setOrderBy(array $fieldNames)
{
$this->mapping['orderBy'] = $fieldNames;
return $this;
}
public function setIndexBy($fieldName)
{
$this->mapping['indexBy'] = $fieldName;
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
if ($this->joinColumns) {
$mapping['joinColumns'] = $this->joinColumns;
}
$cm = $this->builder->getClassMetadata();
$cm->mapOneToMany($mapping);
return $this->builder;
}
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class ChangeTrackingPolicy implements Annotation
{
/** @var string */
public $value;
}

View File

@@ -24,7 +24,7 @@ use ReflectionClass, ReflectionProperty;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
* of an entity and it's associations.
*
*
* Once populated, ClassMetadata instances are usually cached in a serialized form.
*
* <b>IMPORTANT NOTE:</b>
@@ -41,4 +41,306 @@ use ReflectionClass, ReflectionProperty;
*/
class ClassMetadata extends ClassMetadataInfo
{
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param string $entityName The name of the entity class the new instance is used for.
*/
public function __construct($entityName)
{
$this->reflClass = new ReflectionClass($entityName);
$this->namespace = $this->reflClass->getNamespaceName();
$this->table['name'] = $this->reflClass->getShortName();
parent::__construct($this->reflClass->getName()); // do not use $entityName, possible case-problems
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validated & complete.
* @return array The validated and completed field mapping.
*
* @throws MappingException
*/
protected function _validateAndCompleteFieldMapping(array &$mapping)
{
parent::_validateAndCompleteFieldMapping($mapping);
// Store ReflectionProperty of mapped field
$refProp = $this->reflClass->getProperty($mapping['fieldName']);
$refProp->setAccessible(true);
$this->reflFields[$mapping['fieldName']] = $refProp;
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
} else {
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Stores the association mapping.
*
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
parent::_storeAssociationMapping($assocMapping);
// Store ReflectionProperty of mapped field
$sourceFieldName = $assocMapping['fieldName'];
$refProp = $this->reflClass->getProperty($sourceFieldName);
$refProp->setAccessible(true);
$this->reflFields[$sourceFieldName] = $refProp;
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @return void
*/
public function __wakeup()
{
// Restore ReflectionClass and properties
$this->reflClass = new ReflectionClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
foreach ($this->associationMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
}

View File

@@ -24,8 +24,6 @@ use ReflectionException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events,
Doctrine\Common\Persistence\Mapping\RuntimeReflectionService,
Doctrine\Common\Persistence\Mapping\ReflectionService,
Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface;
/**
@@ -45,14 +43,14 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* @var EntityManager
*/
private $em;
/**
* @var AbstractPlatform
*/
private $targetPlatform;
/**
* @var \Doctrine\ORM\Mapping\Driver\Driver
* @var Driver\Driver
*/
private $driver;
@@ -75,12 +73,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* @var bool
*/
private $initialized = false;
/**
* @var ReflectionService
*/
private $reflectionService;
/**
* @param EntityManager $$em
*/
@@ -92,7 +85,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Sets the cache driver used by the factory to cache ClassMetadata instances.
*
* @param \Doctrine\Common\Cache\Cache $cacheDriver
* @param Doctrine\Common\Cache\Cache $cacheDriver
*/
public function setCacheDriver($cacheDriver)
{
@@ -102,22 +95,22 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Gets the cache driver used by the factory to cache ClassMetadata instances.
*
* @return \Doctrine\Common\Cache\Cache
* @return Doctrine\Common\Cache\Cache
*/
public function getCacheDriver()
{
return $this->cacheDriver;
}
public function getLoadedMetadata()
{
return $this->loadedMetadata;
}
/**
* Forces the factory to load the metadata of all classes known to the underlying
* mapping driver.
*
*
* @return array The ClassMetadata instances of all mapped classes.
*/
public function getAllMetadata()
@@ -150,7 +143,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* Gets the class metadata descriptor for a class.
*
* @param string $className The name of the class.
* @return \Doctrine\ORM\Mapping\ClassMetadata
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
public function getMetadataFor($className)
{
@@ -172,7 +165,6 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->wakeupReflection($cached, $this->getReflectionService());
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
@@ -196,7 +188,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Checks whether the factory has the metadata for a class loaded already.
*
*
* @param string $className
* @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise.
*/
@@ -207,7 +199,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Sets the metadata descriptor for a specific class.
*
*
* NOTE: This is only useful in very special cases, like when generating proxy classes.
*
* @param string $className
@@ -228,7 +220,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
foreach (array_reverse(class_parents($name)) as $parentClass) {
if ( ! $this->driver->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
@@ -269,7 +261,6 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
$class = $this->newClassMetadataInstance($className);
$this->initializeReflection($class, $this->getReflectionService());
if ($parent) {
$class->setInheritanceType($parent->inheritanceType);
@@ -283,9 +274,6 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class->setDiscriminatorMap($parent->discriminatorMap);
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
if ($parent->isMappedSuperclass) {
$class->setCustomRepositoryClass($parent->customRepositoryClassName);
}
}
// Invoke driver
@@ -318,24 +306,15 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class->setPrimaryTable($parent->table);
}
if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent && !empty ($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
$class->setParentClasses($visited);
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
}
$this->wakeupReflection($class, $this->getReflectionService());
$this->validateRuntimeMetadata($class, $parent);
$this->loadedMetadata[$className] = $class;
$parent = $class;
@@ -359,15 +338,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
protected function validateRuntimeMetadata($class, $parent)
{
if ( ! $class->reflClass ) {
// only validate if there is a reflection class instance
return;
// Verify & complete identifier mapping
if ( ! $class->identifier && ! $class->isMappedSuperclass) {
throw MappingException::identifierRequired($class->name);
}
$class->validateIdentifier();
$class->validateAssocations();
$class->validateLifecycleCallbacks($this->getReflectionService());
// verify inheritance
if (!$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
if (!$parent) {
@@ -391,7 +366,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
* Creates a new ClassMetadata instance for the given class name.
*
* @param string $className
* @return \Doctrine\ORM\Mapping\ClassMetadata
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
protected function newClassMetadataInstance($className)
{
@@ -401,8 +376,8 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Adds inherited fields to the subclass mapping.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@@ -423,8 +398,8 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
/**
* Adds inherited association mappings to the subclass mapping.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@@ -447,30 +422,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
}
/**
* Adds inherited named queries to the subclass mapping.
*
* @since 2.2
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->namedQueries as $name => $query) {
if (!isset ($subClass->namedQueries[$name])) {
$subClass->addNamedQuery(array(
'name' => $query['name'],
'query' => $query['query']
));
}
}
}
/**
* Completes the ID generator mapping. If "auto" is specified we choose the generator
* most appropriate for the targeted database platform.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
* @param Doctrine\ORM\Mapping\ClassMetadata $class
*/
private function completeIdGeneratorMapping(ClassMetadataInfo $class)
{
@@ -492,7 +448,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
// <table>_<column>_seq in PostgreSQL for SERIAL columns.
// Not pretty but necessary and the simplest solution that currently works.
$seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ?
$class->getTableName() . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
$class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
null;
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName));
break;
@@ -522,72 +478,4 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
throw new ORMException("Unknown generator type: " . $class->generatorType);
}
}
/**
* Check if this class is mapped by this EntityManager + ClassMetadata configuration
*
* @param $class
* @return bool
*/
public function isTransient($class)
{
if ( ! $this->initialized) {
$this->initialize();
}
// Check for namespace alias
if (strpos($class, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $class);
$class = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
return $this->driver->isTransient($class);
}
/**
* Get reflectionService.
*
* @return \Doctrine\Common\Persistence\Mapping\ReflectionService
*/
public function getReflectionService()
{
if ($this->reflectionService === null) {
$this->reflectionService = new RuntimeReflectionService();
}
return $this->reflectionService;
}
/**
* Set reflectionService.
*
* @param reflectionService the value to set.
*/
public function setReflectionService(ReflectionService $reflectionService)
{
$this->reflectionService = $reflectionService;
}
/**
* Wakeup reflection after ClassMetadata gets unserialized from cache.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function wakeupReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->wakeupReflection($reflService);
}
/**
* Initialize Reflection after ClassMetadata was constructed.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function initializeReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->initializeReflection($reflService);
}
}

View File

@@ -19,9 +19,8 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\DBAL\Types\Type;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use ReflectionClass;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@@ -120,7 +119,7 @@ class ClassMetadataInfo implements ClassMetadata
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
* association is fetched.
*/
const FETCH_EAGER = 3;
/**
@@ -137,6 +136,10 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-one association.
*/
const MANY_TO_ONE = 2;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Identifies a one-to-many association.
*/
@@ -145,10 +148,6 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-many association.
*/
const MANY_TO_MANY = 8;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Combined bitmask for to-many (collection-valued) associations.
*/
@@ -207,7 +206,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* READ-ONLY: The named queries allowed to be called directly from Repository.
*
*
* @var array
*/
public $namedQueries = array();
@@ -319,7 +318,7 @@ class ClassMetadataInfo implements ClassMetadata
public $discriminatorMap = array();
/**
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
* READ-ONLY: The definition of the descriminator column used in JOINED and SINGLE_TABLE
* inheritance mappings.
*
* @var array
@@ -362,7 +361,7 @@ class ClassMetadataInfo implements ClassMetadata
* - <b>mappedBy</b> (string, required for bidirectional associations)
* The name of the field that completes the bidirectional association on the owning side.
* This key must be specified on the inverse side of a bidirectional association.
*
*
* - <b>inversedBy</b> (string, required for bidirectional associations)
* The name of the field that completes the bidirectional association on the inverse side.
* This key must be specified on the owning side of a bidirectional association.
@@ -389,7 +388,7 @@ class ClassMetadataInfo implements ClassMetadata
* Specification of a field on target-entity that is used to index the collection by.
* This field HAS to be either the primary key or a unique column. Otherwise the collection
* does not contain all the entities that are actually related.
*
*
* A join table definition has the following structure:
* <pre>
* array(
@@ -431,7 +430,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* READ-ONLY: The definition of the sequence generator of this class. Only used for the
* SEQUENCE generation strategy.
*
*
* The definition has the following structure:
* <code>
* array(
@@ -495,20 +494,6 @@ class ClassMetadataInfo implements ClassMetadata
*/
public $isReadOnly = false;
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
@@ -521,308 +506,6 @@ class ClassMetadataInfo implements ClassMetadata
$this->rootEntityName = $entityName;
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
}
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @param ReflectionService $reflService
* @return void
*/
public function wakeupReflection($reflService)
{
// Restore ReflectionClass and properties
$this->reflClass = $reflService->getClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
foreach ($this->associationMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
}
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param string $entityName The name of the entity class the new instance is used for.
*/
public function initializeReflection($reflService)
{
$this->reflClass = $reflService->getClass($this->name);
$this->namespace = $reflService->getClassNamespace($this->name);
$this->table['name'] = $reflService->getClassShortName($this->name);
if ($this->reflClass) {
$this->name = $this->rootEntityName = $this->reflClass->getName();
}
}
/**
* Validate Identifier
*
* @return void
*/
public function validateIdentifier()
{
// Verify & complete identifier mapping
if ( ! $this->identifier && ! $this->isMappedSuperclass) {
throw MappingException::identifierRequired($this->name);
}
if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
}
}
/**
* Validate association targets actually exist.
*
* @return void
*/
public function validateAssocations()
{
foreach ($this->associationMappings as $field => $mapping) {
if ( ! \Doctrine\Common\ClassLoader::classExists($mapping['targetEntity']) ) {
throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
}
}
}
/**
* Validate lifecycle callbacks
*
* @param ReflectionService $reflService
* @return void
*/
public function validateLifecycleCallbacks($reflService)
{
foreach ($this->lifecycleCallbacks as $event => $callbacks) {
foreach ($callbacks as $callbackFuncName) {
if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
}
}
}
}
/**
* Gets the ReflectionClass instance of the mapped class.
*
@@ -830,6 +513,9 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getReflectionClass()
{
if ( ! $this->reflClass) {
$this->reflClass = new ReflectionClass($this->name);
}
return $this->reflClass;
}
@@ -999,7 +685,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($this->namedQueries[$queryName])) {
throw MappingException::queryNotFound($this->name, $queryName);
}
return $this->namedQueries[$queryName]['dql'];
return $this->namedQueries[$queryName];
}
/**
@@ -1060,14 +746,6 @@ class ClassMetadataInfo implements ClassMetadata
$this->isIdentifierComposite = true;
}
}
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
if (isset($mapping['id']) && $mapping['id'] === true) {
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
}
$mapping['requireSQLConversion'] = true;
}
}
/**
@@ -1096,22 +774,15 @@ class ClassMetadataInfo implements ClassMetadata
// If targetEntity is unqualified, assume it is in the same namespace as
// the sourceEntity.
$mapping['sourceEntity'] = $this->name;
if (isset($mapping['targetEntity'])) {
if (strlen($this->namespace) > 0 && strpos($mapping['targetEntity'], '\\') === false) {
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
}
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
}
if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 &&
isset($mapping['orphanRemoval']) &&
$mapping['orphanRemoval'] == true) {
throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
}
// Complete id mapping
if (isset($mapping['id']) && $mapping['id'] === true) {
if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
@@ -1142,7 +813,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($mapping['targetEntity'])) {
throw MappingException::missingTargetEntity($mapping['fieldName']);
}
// Mandatory and optional attributes for either side
if ( ! $mapping['mappedBy']) {
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
@@ -1158,7 +829,7 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) {
throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
}
// Fetch mode. Default fetch mode to LAZY, if not set.
if ( ! isset($mapping['fetch'])) {
$mapping['fetch'] = self::FETCH_LAZY;
@@ -1166,18 +837,22 @@ class ClassMetadataInfo implements ClassMetadata
// Cascades
$cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
if (in_array('all', $cascades)) {
$cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
$cascades = array(
'remove',
'persist',
'refresh',
'merge',
'detach'
);
}
$mapping['cascade'] = $cascades;
$mapping['isCascadeRemove'] = in_array('remove', $cascades);
$mapping['isCascadePersist'] = in_array('persist', $cascades);
$mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
$mapping['isCascadeMerge'] = in_array('merge', $cascades);
$mapping['isCascadeDetach'] = in_array('detach', $cascades);
return $mapping;
}
@@ -1191,11 +866,11 @@ class ClassMetadataInfo implements ClassMetadata
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
$mapping['isOwningSide'] = true;
}
if ($mapping['isOwningSide']) {
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
@@ -1207,7 +882,7 @@ class ClassMetadataInfo implements ClassMetadata
$uniqueContraintColumns = array();
foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
if ($mapping['type'] === self::ONE_TO_ONE) {
if (count($mapping['joinColumns']) == 1) {
$joinColumn['unique'] = true;
} else {
@@ -1262,7 +937,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($mapping['mappedBy'])) {
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
}
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
@@ -1271,7 +946,7 @@ class ClassMetadataInfo implements ClassMetadata
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping;
}
@@ -1289,7 +964,7 @@ class ClassMetadataInfo implements ClassMetadata
} else {
$targetShortName = strtolower($mapping['targetEntity']);
}
// owning side MUST have a join table
if ( ! isset($mapping['joinTable']['name'])) {
$mapping['joinTable']['name'] = $sourceShortName .'_' . $targetShortName;
@@ -1336,8 +1011,6 @@ class ClassMetadataInfo implements ClassMetadata
}
}
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
@@ -1442,23 +1115,23 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getIdentifierColumnNames()
{
$columnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
continue;
if ($this->isIdentifierComposite) {
$columnNames = array();
foreach ($this->identifier as $idField) {
if (isset($this->associationMappings[$idField])) {
// no composite pk as fk entity assumption:
$columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
} else {
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
}
}
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
$columnNames = array_merge($columnNames, $assocColumnNames);
return $columnNames;
} else if(isset($this->fieldMappings[$this->identifier[0]])) {
return array($this->fieldMappings[$this->identifier[0]]['columnName']);
} else {
// no composite pk as fk entity assumption:
return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
}
return $columnNames;
}
/**
@@ -1565,7 +1238,7 @@ class ClassMetadataInfo implements ClassMetadata
* Gets the type of a field.
*
* @param string $fieldName
* @return \Doctrine\DBAL\Types\Type
* @return Doctrine\DBAL\Types\Type
*/
public function getTypeOfField($fieldName)
{
@@ -1576,7 +1249,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the type of a column.
*
* @return \Doctrine\DBAL\Types\Type
* @return Doctrine\DBAL\Types\Type
*/
public function getTypeOfColumn($columnName)
{
@@ -1601,7 +1274,7 @@ class ClassMetadataInfo implements ClassMetadata
public function getTemporaryIdTableName()
{
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
return str_replace('.', '_', $this->getTableName() . '_id_tmp');
return str_replace('.', '_', $this->table['name'] . '_id_tmp');
}
/**
@@ -1694,17 +1367,15 @@ class ClassMetadataInfo implements ClassMetadata
{
if (isset($table['name'])) {
if ($table['name'][0] == '`') {
$this->table['name'] = str_replace("`", "", $table['name']);
$this->table['name'] = trim($table['name'], '`');
$this->table['quoted'] = true;
} else {
$this->table['name'] = $table['name'];
}
}
if (isset($table['indexes'])) {
$this->table['indexes'] = $table['indexes'];
}
if (isset($table['uniqueConstraints'])) {
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
}
@@ -1779,15 +1450,8 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($this->namedQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
}
$name = $queryMapping['name'];
$query = $queryMapping['query'];
$dql = str_replace('__CLASS__', $this->name, $query);
$this->namedQueries[$name] = array(
'name' => $name,
'query' => $query,
'dql' => $dql
);
$query = str_replace('__CLASS__', $this->name, $queryMapping['query']);
$this->namedQueries[$queryMapping['name']] = $query;
}
/**
@@ -1842,16 +1506,14 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Stores the association mapping.
*
* @param array $assocMapping
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping['fieldName'];
if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
}
$this->associationMappings[$sourceFieldName] = $assocMapping;
}
@@ -1862,10 +1524,6 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function setCustomRepositoryClass($repositoryClassName)
{
if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
&& strlen($this->namespace) > 0) {
$repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
}
$this->customRepositoryClassName = $repositoryClassName;
}
@@ -1908,6 +1566,9 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Adds a lifecycle callback for entities of this class.
*
* Note: If the same callback is registered more than once, the old one
* will be overridden.
*
* @param string $callback
* @param string $event
*/
@@ -1966,33 +1627,22 @@ class ClassMetadataInfo implements ClassMetadata
public function setDiscriminatorMap(array $map)
{
foreach ($map as $value => $className) {
$this->addDiscriminatorMapClass($value, $className);
}
}
/**
* Add one entry of the discriminator map with a new class and corresponding name.
*
* @param string $name
* @param string $className
*/
public function addDiscriminatorMapClass($name, $className)
{
if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
$className = $this->namespace . '\\' . $className;
}
$className = ltrim($className, '\\');
$this->discriminatorMap[$name] = $className;
if ($this->name == $className) {
$this->discriminatorValue = $name;
} else {
if ( ! class_exists($className)) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
$className = $this->namespace . '\\' . $className;
}
if (is_subclass_of($className, $this->name)) {
$this->subClasses[] = $className;
$className = ltrim($className, '\\');
$this->discriminatorMap[$value] = $className;
if ($this->name == $className) {
$this->discriminatorValue = $value;
} else {
if ( ! class_exists($className)) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
}
if (is_subclass_of($className, $this->name)) {
$this->subClasses[] = $className;
}
}
}
}
@@ -2062,7 +1712,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Return the single association join column (if any).
*
*
* @param string $fieldName
* @return string
*/
@@ -2104,7 +1754,7 @@ class ClassMetadataInfo implements ClassMetadata
foreach ($this->associationMappings AS $assocName => $mapping) {
if ($this->isAssociationWithSingleJoinColumn($assocName) &&
$this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
return $assocName;
}
}
@@ -2154,7 +1804,7 @@ class ClassMetadataInfo implements ClassMetadata
$this->versionField = $mapping['fieldName'];
if ( ! isset($mapping['default'])) {
if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) {
if ($mapping['type'] == 'integer') {
$mapping['default'] = 1;
} else if ($mapping['type'] == 'datetime') {
$mapping['default'] = 'CURRENT_TIMESTAMP';
@@ -2194,49 +1844,48 @@ class ClassMetadataInfo implements ClassMetadata
{
$this->isReadOnly = true;
}
/**
* A numerically indexed list of field names of this persistent class.
*
*
* This array includes identifier fields if present on this class.
*
*
* @return array
*/
public function getFieldNames()
{
return array_keys($this->fieldMappings);
}
/**
* A numerically indexed list of association names of this persistent class.
*
*
* This array includes identifier associations if present on this class.
*
*
* @return array
*/
public function getAssociationNames()
{
return array_keys($this->associationMappings);
}
/**
* Returns the target class name of the given association.
*
*
* @param string $assocName
* @return string
*/
public function getAssociationTargetClass($assocName)
{
if ( ! isset($this->associationMappings[$assocName])) {
if (!isset($this->associationMappings[$assocName])) {
throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
}
return $this->associationMappings[$assocName]['targetEntity'];
}
/**
* Get fully-qualified class name of this persistent class.
*
*
* @return string
*/
public function getName()
@@ -2244,67 +1893,33 @@ class ClassMetadataInfo implements ClassMetadata
return $this->name;
}
/**
* Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
*
* @param AbstractPlatform $platform
* @return array
*/
public function getQuotedIdentifierColumnNames($platform)
{
$quotedColumnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName'])
: $this->fieldMappings[$idProperty]['columnName'];
continue;
}
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocQuotedColumnNames = array_map(
function ($joinColumn) {
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
},
$joinColumns
);
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
}
return $quotedColumnNames;
}
/**
* Gets the (possibly quoted) column name of a mapped field for safe use
* in an SQL statement.
*
*
* @param string $field
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedColumnName($field, $platform)
{
return isset($this->fieldMappings[$field]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
: $this->fieldMappings[$field]['columnName'];
return isset($this->fieldMappings[$field]['quoted']) ?
$platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) :
$this->fieldMappings[$field]['columnName'];
}
/**
* Gets the (possibly quoted) primary table name of this class for safe use
* in an SQL statement.
*
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedTableName($platform)
{
return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
return isset($this->table['quoted']) ?
$platform->quoteIdentifier($this->table['name']) :
$this->table['name'];
}
/**
@@ -2315,24 +1930,8 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getQuotedJoinTableName(array $assoc, $platform)
{
return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
}
/**
* @param string $fieldName
* @return bool
*/
public function isAssociationInverseSide($fieldName)
{
return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide'];
}
/**
* @param string $fieldName
* @return string
*/
public function getAssociationMappedByTargetField($fieldName)
{
return $this->associationMappings[$fieldName]['mappedBy'];
return isset($assoc['joinTable']['quoted'])
? $platform->quoteIdentifier($assoc['joinTable']['name'])
: $assoc['joinTable']['name'];
}
}

View File

@@ -1,46 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Column implements Annotation
{
/** @var string */
public $name;
/** @var mixed */
public $type = 'string';
/** @var integer */
public $length;
/** @var integer */
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
/** @var integer */
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
/** @var boolean */
public $unique = false;
/** @var boolean */
public $nullable = false;
/** @var array */
public $options = array();
/** @var string */
public $columnDefinition;
}

View File

@@ -1,36 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorColumn implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $type;
/** @var integer */
public $length;
/** @var mixed */
public $fieldName; // field name used in non-object hydration (array/scalar)
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorMap implements Annotation
{
/** @var array<string> */
public $value;
}

View File

@@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping\MappingException;
/**
* Base driver for file-based metadata drivers.
*
*
* A file driver operates in a mode where it loads the mapping files of individual
* classes on demand. This requires the user to adhere to the convention of 1 mapping
* file per class and the file names of the mapping files must correspond to the full
@@ -56,16 +56,16 @@ abstract class AbstractFileDriver implements Driver
*/
protected $_fileExtension;
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
$this->addPaths((array) $paths);
}
}
/**
* Append lookup paths to metadata driver.
@@ -117,10 +117,7 @@ abstract class AbstractFileDriver implements Driver
public function getElement($className)
{
$result = $this->_loadMappingFile($this->_findMappingFile($className));
if(!isset($result[$className])){
throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->_fileExtension);
}
return $result[$className];
}
@@ -148,7 +145,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
public function getAllClassNames()
@@ -160,23 +157,23 @@ abstract class AbstractFileDriver implements Driver
if ( ! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
continue;
}
// NOTE: All files found here means classes are not transient!
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
return $classes;
}
@@ -191,7 +188,7 @@ abstract class AbstractFileDriver implements Driver
protected function _findMappingFile($className)
{
$fileName = str_replace('\\', '.', $className) . $this->_fileExtension;
// Check whether file exists
foreach ((array) $this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) {
@@ -205,7 +202,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding elements.
*
*
* @param string $file The mapping file to load.
* @return array
*/

View File

@@ -97,16 +97,6 @@ class AnnotationDriver implements Driver
return $this->_paths;
}
/**
* Retrieve the current annotation reader
*
* @return AnnotationReader
*/
public function getReader()
{
return $this->_reader;
}
/**
* Get the file extension used to look for mapping files under
*
@@ -134,15 +124,11 @@ class AnnotationDriver implements Driver
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$class = $metadata->getReflectionClass();
if (!$class) {
// this happens when running annotation driver in combination with
// static reflection services. This is not the nicest fix
$class = new \ReflectionClass($metadata->name);
}
$classAnnotations = $this->_reader->getClassAnnotations($class);
if ($classAnnotations && is_numeric(key($classAnnotations))) {
// Compatibility with Doctrine Common 3.x
if ($classAnnotations && is_int(key($classAnnotations))) {
foreach ($classAnnotations as $annot) {
$classAnnotations[get_class($annot)] = $annot;
}
@@ -151,15 +137,12 @@ class AnnotationDriver implements Driver
// Evaluate Entity annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
$entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
if ($entityAnnot->repositoryClass !== null) {
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
}
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
if ($entityAnnot->readOnly) {
$metadata->markReadOnly();
}
} else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) {
$mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'];
$metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
$metadata->isMappedSuperclass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
@@ -175,25 +158,17 @@ class AnnotationDriver implements Driver
if ($tableAnnot->indexes !== null) {
foreach ($tableAnnot->indexes as $indexAnnot) {
$index = array('columns' => $indexAnnot->columns);
if ( ! empty($indexAnnot->name)) {
$primaryTable['indexes'][$indexAnnot->name] = $index;
} else {
$primaryTable['indexes'][] = $index;
}
$primaryTable['indexes'][$indexAnnot->name] = array(
'columns' => $indexAnnot->columns
);
}
}
if ($tableAnnot->uniqueConstraints !== null) {
foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
$uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns);
if ( ! empty($uniqueConstraintAnnot->name)) {
$primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
} else {
$primaryTable['uniqueConstraints'][] = $uniqueConstraint;
}
foreach ($tableAnnot->uniqueConstraints as $uniqueConstraint) {
$primaryTable['uniqueConstraints'][$uniqueConstraint->name] = array(
'columns' => $uniqueConstraint->columns
);
}
}
@@ -204,14 +179,7 @@ class AnnotationDriver implements Driver
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
$namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
if (!is_array($namedQueriesAnnot->value)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
foreach ($namedQueriesAnnot->value as $namedQuery) {
if (!($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
$metadata->addNamedQuery(array(
'name' => $namedQuery->name,
'query' => $namedQuery->query
@@ -275,6 +243,7 @@ class AnnotationDriver implements Driver
'unique' => $joinColumnAnnot->unique,
'nullable' => $joinColumnAnnot->nullable,
'onDelete' => $joinColumnAnnot->onDelete,
'onUpdate' => $joinColumnAnnot->onUpdate,
'columnDefinition' => $joinColumnAnnot->columnDefinition,
);
} else if ($joinColumnsAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
@@ -285,6 +254,7 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -350,7 +320,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
@@ -358,7 +328,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
@@ -374,7 +344,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
@@ -392,6 +362,7 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -403,6 +374,7 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -414,8 +386,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
@@ -432,7 +403,8 @@ class AnnotationDriver implements Driver
if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) {
$annotations = $this->_reader->getMethodAnnotations($method);
if ($annotations && is_numeric(key($annotations))) {
// Compatibility with Doctrine Common 3.x
if ($annotations && is_int(key($annotations))) {
foreach ($annotations as $annot) {
$annotations[get_class($annot)] = $annot;
}
@@ -465,10 +437,6 @@ class AnnotationDriver implements Driver
if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad);
}
if (isset($annotations['Doctrine\ORM\Mapping\PreFlush'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preFlush);
}
}
}
}
@@ -487,7 +455,8 @@ class AnnotationDriver implements Driver
{
$classAnnotations = $this->_reader->getClassAnnotations(new \ReflectionClass($className));
if ($classAnnotations && is_numeric(key($classAnnotations))) {
// Compatibility with Doctrine Common 3.x
if ($classAnnotations && is_int(key($classAnnotations))) {
foreach ($classAnnotations as $annot) {
if ($annot instanceof \Doctrine\ORM\Mapping\Entity) {
return false;
@@ -530,15 +499,15 @@ class AnnotationDriver implements Driver
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i',
'/^.+\\' . $this->_fileExtension . '$/i',
\RecursiveRegexIterator::GET_MATCH
);
foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}
@@ -558,22 +527,6 @@ class AnnotationDriver implements Driver
return $classes;
}
/**
* Attempts to resolve the fetch mode.
*
* @param string $className The class name
* @param string $fetchMode The fetch mode
* @return integer The fetch mode as defined in ClassMetadata
* @throws MappingException If the fetch mode is not valid
*/
private function getFetchMode($className, $fetchMode)
{
if(!defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
throw MappingException::invalidFetchMode($className, $fetchMode);
}
return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
}
/**
* Factory method for the Annotation Driver
*

View File

@@ -76,7 +76,7 @@ class DatabaseDriver implements Driver
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
*
* @param AnnotationReader $reader The AnnotationReader to use.
*/
public function __construct(AbstractSchemaManager $schemaManager)
@@ -111,7 +111,7 @@ class DatabaseDriver implements Driver
}
$tables = array();
foreach ($this->_sm->listTableNames() as $tableName) {
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
}
@@ -129,7 +129,7 @@ class DatabaseDriver implements Driver
foreach ($foreignKeys AS $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
@@ -145,7 +145,7 @@ class DatabaseDriver implements Driver
}
}
}
/**
* {@inheritdoc}
*/
@@ -169,7 +169,7 @@ class DatabaseDriver implements Driver
} catch(SchemaException $e) {
$primaryKeyColumns = array();
}
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
} else {

View File

@@ -17,38 +17,190 @@
* <http://www.doctrine-project.org>.
*/
require_once __DIR__.'/../Annotation.php';
require_once __DIR__.'/../Entity.php';
require_once __DIR__.'/../MappedSuperclass.php';
require_once __DIR__.'/../InheritanceType.php';
require_once __DIR__.'/../DiscriminatorColumn.php';
require_once __DIR__.'/../DiscriminatorMap.php';
require_once __DIR__.'/../Id.php';
require_once __DIR__.'/../GeneratedValue.php';
require_once __DIR__.'/../Version.php';
require_once __DIR__.'/../JoinColumn.php';
require_once __DIR__.'/../JoinColumns.php';
require_once __DIR__.'/../Column.php';
require_once __DIR__.'/../OneToOne.php';
require_once __DIR__.'/../OneToMany.php';
require_once __DIR__.'/../ManyToOne.php';
require_once __DIR__.'/../ManyToMany.php';
require_once __DIR__.'/../ElementCollection.php';
require_once __DIR__.'/../Table.php';
require_once __DIR__.'/../UniqueConstraint.php';
require_once __DIR__.'/../Index.php';
require_once __DIR__.'/../JoinTable.php';
require_once __DIR__.'/../SequenceGenerator.php';
require_once __DIR__.'/../ChangeTrackingPolicy.php';
require_once __DIR__.'/../OrderBy.php';
require_once __DIR__.'/../NamedQueries.php';
require_once __DIR__.'/../NamedQuery.php';
require_once __DIR__.'/../HasLifecycleCallbacks.php';
require_once __DIR__.'/../PrePersist.php';
require_once __DIR__.'/../PostPersist.php';
require_once __DIR__.'/../PreUpdate.php';
require_once __DIR__.'/../PostUpdate.php';
require_once __DIR__.'/../PreRemove.php';
require_once __DIR__.'/../PostRemove.php';
require_once __DIR__.'/../PostLoad.php';
require_once __DIR__.'/../PreFlush.php';
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Annotations\Annotation;
/* Annotations */
/** @Annotation */
final class Entity extends Annotation {
public $repositoryClass;
public $readOnly = false;
}
/** @Annotation */
final class MappedSuperclass extends Annotation {}
/** @Annotation */
final class InheritanceType extends Annotation {}
/** @Annotation */
final class DiscriminatorColumn extends Annotation {
public $name;
public $fieldName; // field name used in non-object hydration (array/scalar)
public $type;
public $length;
}
/** @Annotation */
final class DiscriminatorMap extends Annotation {}
/** @Annotation */
final class Id extends Annotation {}
/** @Annotation */
final class GeneratedValue extends Annotation {
public $strategy = 'AUTO';
}
/** @Annotation */
final class Version extends Annotation {}
/** @Annotation */
final class JoinColumn extends Annotation {
public $name;
public $fieldName; // field name used in non-object hydration (array/scalar)
public $referencedColumnName = 'id';
public $unique = false;
public $nullable = true;
public $onDelete;
public $onUpdate;
public $columnDefinition;
}
/** @Annotation */
final class JoinColumns extends Annotation {}
/** @Annotation */
final class Column extends Annotation {
public $type = 'string';
public $length;
// The precision for a decimal (exact numeric) column (Applies only for decimal column)
public $precision = 0;
// The scale for a decimal (exact numeric) column (Applies only for decimal column)
public $scale = 0;
public $unique = false;
public $nullable = false;
public $name;
public $options = array();
public $columnDefinition;
}
/** @Annotation */
final class OneToOne extends Annotation {
public $targetEntity;
public $mappedBy;
public $inversedBy;
public $cascade;
public $fetch = 'LAZY';
public $orphanRemoval = false;
}
/** @Annotation */
final class OneToMany extends Annotation {
public $mappedBy;
public $targetEntity;
public $cascade;
public $fetch = 'LAZY';
public $orphanRemoval = false;
public $indexBy;
}
/** @Annotation */
final class ManyToOne extends Annotation {
public $targetEntity;
public $cascade;
public $fetch = 'LAZY';
public $inversedBy;
}
/** @Annotation */
final class ManyToMany extends Annotation {
public $targetEntity;
public $mappedBy;
public $inversedBy;
public $cascade;
public $fetch = 'LAZY';
public $indexBy;
}
/** @Annotation */
final class ElementCollection extends Annotation {
public $tableName;
}
/** @Annotation */
final class Table extends Annotation {
public $name;
public $schema;
public $indexes;
public $uniqueConstraints;
}
/** @Annotation */
final class UniqueConstraint extends Annotation {
public $name;
public $columns;
}
/** @Annotation */
final class Index extends Annotation {
public $name;
public $columns;
}
/** @Annotation */
final class JoinTable extends Annotation {
public $name;
public $schema;
public $joinColumns = array();
public $inverseJoinColumns = array();
}
/** @Annotation */
final class SequenceGenerator extends Annotation {
public $sequenceName;
public $allocationSize = 1;
public $initialValue = 1;
}
/** @Annotation */
final class ChangeTrackingPolicy extends Annotation {}
/** @Annotation */
final class OrderBy extends Annotation {}
/** @Annotation */
final class NamedQueries extends Annotation {}
/** @Annotation */
final class NamedQuery extends Annotation {
public $name;
public $query;
}
/* Annotations for lifecycle callbacks */
/** @Annotation */
final class HasLifecycleCallbacks extends Annotation {}
/** @Annotation */
final class PrePersist extends Annotation {}
/** @Annotation */
final class PostPersist extends Annotation {}
/** @Annotation */
final class PreUpdate extends Annotation {}
/** @Annotation */
final class PostUpdate extends Annotation {}
/** @Annotation */
final class PreRemove extends Annotation {}
/** @Annotation */
final class PostRemove extends Annotation {}
/** @Annotation */
final class PostLoad extends Annotation {}

View File

@@ -34,18 +34,18 @@ interface Driver
{
/**
* Loads the metadata for the specified class into the provided container.
*
*
* @param string $className
* @param ClassMetadataInfo $metadata
*/
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
function getAllClassNames();
function getAllClassNames();
/**
* Whether the class with the specified name should have its metadata loaded.

View File

@@ -94,7 +94,7 @@ class DriverChain implements Driver
if (!isset($driverClasses[$oid])) {
$driverClasses[$oid] = $driver->getAllClassNames();
}
foreach ($driverClasses[$oid] AS $className) {
if (strpos($className, $namespace) === 0) {
$classNames[$className] = true;

View File

@@ -1,176 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\MappingException;
/**
* XmlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @license MIT
*/
class SimplifiedXmlDriver extends XmlDriver
{
protected $_prefixes = array();
protected $_globalBasename;
protected $_classCache;
protected $_fileExtension = '.orm.xml';
public function __construct($prefixes)
{
$this->addNamespacePrefixes($prefixes);
}
public function setGlobalBasename($file)
{
$this->_globalBasename = $file;
}
public function getGlobalBasename()
{
return $this->_globalBasename;
}
public function addNamespacePrefixes($prefixes)
{
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
$this->addPaths(array_flip($prefixes));
}
public function getNamespacePrefixes()
{
return $this->_prefixes;
}
public function isTransient($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
// The mapping is defined in the global mapping file
if (isset($this->_classCache[$className])) {
return false;
}
try {
$this->_findMappingFile($className);
return false;
} catch (MappingException $e) {
return true;
}
}
public function getAllClassNames()
{
if (null === $this->_classCache) {
$this->initialize();
}
$classes = array();
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if (!is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$fileName = $file->getBasename($this->_fileExtension);
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
continue;
}
// NOTE: All files found here means classes are not transient!
if (isset($this->_prefixes[$path])) {
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
} else {
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
}
return array_merge($classes, array_keys($this->_classCache));
}
public function getElement($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
if (!isset($this->_classCache[$className])) {
$this->_classCache[$className] = parent::getElement($className);
}
return $this->_classCache[$className];
}
protected function initialize()
{
$this->_classCache = array();
if (null !== $this->_globalBasename) {
foreach ($this->_paths as $path) {
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
}
}
}
}
protected function _findMappingFile($className)
{
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
foreach ($this->_paths as $path) {
if (!isset($this->_prefixes[$path])) {
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
}
continue;
}
$prefix = $this->_prefixes[$path];
if (0 !== strpos($className, $prefix.'\\')) {
continue;
}
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
if (is_file($filename)) {
return $filename;
}
throw MappingException::mappingFileNotFound($className, $filename);
}
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
}
}

View File

@@ -1,181 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\MappingException;
/**
* YamlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @license MIT
*/
class SimplifiedYamlDriver extends YamlDriver
{
protected $_prefixes = array();
protected $_globalBasename;
protected $_classCache;
protected $_fileExtension = '.orm.yml';
public function __construct($prefixes)
{
$this->addNamespacePrefixes($prefixes);
}
public function setGlobalBasename($file)
{
$this->_globalBasename = $file;
}
public function getGlobalBasename()
{
return $this->_globalBasename;
}
public function addNamespacePrefixes($prefixes)
{
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
$this->addPaths(array_flip($prefixes));
}
public function addNamespacePrefix($prefix, $path)
{
$this->_prefixes[$path] = $prefix;
}
public function getNamespacePrefixes()
{
return $this->_prefixes;
}
public function isTransient($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
// The mapping is defined in the global mapping file
if (isset($this->_classCache[$className])) {
return false;
}
try {
$this->_findMappingFile($className);
return false;
} catch (MappingException $e) {
return true;
}
}
public function getAllClassNames()
{
if (null === $this->_classCache) {
$this->initialize();
}
$classes = array();
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if (!is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$fileName = $file->getBasename($this->_fileExtension);
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
continue;
}
// NOTE: All files found here means classes are not transient!
if (isset($this->_prefixes[$path])) {
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
} else {
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
}
return array_merge($classes, array_keys($this->_classCache));
}
public function getElement($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
if (!isset($this->_classCache[$className])) {
$this->_classCache[$className] = parent::getElement($className);
}
return $this->_classCache[$className];
}
protected function initialize()
{
$this->_classCache = array();
if (null !== $this->_globalBasename) {
foreach ($this->_paths as $path) {
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
}
}
}
}
protected function _findMappingFile($className)
{
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
foreach ($this->_paths as $path) {
if (!isset($this->_prefixes[$path])) {
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
}
continue;
}
$prefix = $this->_prefixes[$path];
if (0 !== strpos($className, $prefix.'\\')) {
continue;
}
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
if (is_file($filename)) {
return $filename;
}
throw MappingException::mappingFileNotFound($className, $filename);
}
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
}
}

View File

@@ -38,21 +38,21 @@ class StaticPHPDriver implements Driver
{
/**
* Paths of entity directories.
*
*
* @var array
*/
private $_paths = array();
/**
* Map of all class names.
*
*
* @var array
*/
private $_classNames;
/**
* The file extension of mapping documents.
*
*
* @var string
*/
private $_fileExtension = '.php';

View File

@@ -52,16 +52,13 @@ class XmlDriver extends AbstractFileDriver
$xmlRoot = $this->getElement($className);
if ($xmlRoot->getName() == 'entity') {
if (isset($xmlRoot['repository-class'])) {
$metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']);
}
$metadata->setCustomRepositoryClass(
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
);
if (isset($xmlRoot['read-only']) && $xmlRoot['read-only'] == "true") {
$metadata->markReadOnly();
}
} else if ($xmlRoot->getName() == 'mapped-superclass') {
$metadata->setCustomRepositoryClass(
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
);
$metadata->isMappedSuperclass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
@@ -89,7 +86,7 @@ class XmlDriver extends AbstractFileDriver
if (isset($xmlRoot['schema'])) {
$metadata->table['schema'] = (string)$xmlRoot['schema'];
}*/
if (isset($xmlRoot['inheritance-type'])) {
$inheritanceType = (string)$xmlRoot['inheritance-type'];
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
@@ -166,12 +163,9 @@ class XmlDriver extends AbstractFileDriver
foreach ($xmlRoot->field as $fieldMapping) {
$mapping = array(
'fieldName' => (string)$fieldMapping['name'],
'type' => (string)$fieldMapping['type']
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$fieldMapping['type'];
}
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string)$fieldMapping['column'];
}
@@ -216,27 +210,20 @@ class XmlDriver extends AbstractFileDriver
$associationIds = array();
foreach ($xmlRoot->id as $idElement) {
if ((bool)$idElement['association-key'] == true) {
$associationIds[(string)$idElement['name']] = true;
$associationIds[(string)$idElement['fieldName']] = true;
continue;
}
$mapping = array(
'id' => true,
'fieldName' => (string)$idElement['name']
'fieldName' => (string)$idElement['name'],
'type' => (string)$idElement['type']
);
if (isset($idElement['type'])) {
$mapping['type'] = (string)$idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = (string)$idElement['column'];
}
if (isset($idElement['column-definition'])) {
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
}
$metadata->mapField($mapping);
if (isset($idElement->generator)) {
@@ -335,10 +322,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['orderBy'] = $orderBy;
}
if (isset($oneToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$oneToManyElement['index-by'];
} else if (isset($oneToManyElement->{'index-by'})) {
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
if (isset($oneToManyElement->{'index-by'})) {
$mapping['indexBy'] = (string)$oneToManyElement->{'index-by'};
}
$metadata->mapOneToMany($mapping);
@@ -381,6 +366,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
}
if (isset($manyToOneElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement->{'orphan-removal'};
}
$metadata->mapManyToOne($mapping);
}
}
@@ -397,10 +386,6 @@ class XmlDriver extends AbstractFileDriver
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
}
if (isset($manyToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphan-removal'];
}
if (isset($manyToManyElement['mapped-by'])) {
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
} else if (isset($manyToManyElement->{'join-table'})) {
@@ -432,6 +417,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade);
}
if (isset($manyToManyElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement->{'orphan-removal'};
}
if (isset($manyToManyElement->{'order-by'})) {
$orderBy = array();
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) {
@@ -440,10 +429,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['orderBy'] = $orderBy;
}
if (isset($manyToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$manyToManyElement['index-by'];
} else if (isset($manyToManyElement->{'index-by'})) {
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
if (isset($manyToManyElement->{'index-by'})) {
$mapping['indexBy'] = (string)$manyToManyElement->{'index-by'};
}
$metadata->mapManyToMany($mapping);
@@ -484,6 +471,10 @@ class XmlDriver extends AbstractFileDriver
$joinColumn['onDelete'] = (string)$joinColumnElement['on-delete'];
}
if (isset($joinColumnElement['on-update'])) {
$joinColumn['onUpdate'] = (string)$joinColumnElement['on-update'];
}
if (isset($joinColumnElement['column-definition'])) {
$joinColumn['columnDefinition'] = (string)$joinColumnElement['column-definition'];
}

View File

@@ -46,16 +46,13 @@ class YamlDriver extends AbstractFileDriver
$element = $this->getElement($className);
if ($element['type'] == 'entity') {
if (isset($element['repositoryClass'])) {
$metadata->setCustomRepositoryClass($element['repositoryClass']);
}
$metadata->setCustomRepositoryClass(
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
);
if (isset($element['readOnly']) && $element['readOnly'] == true) {
$metadata->markReadOnly();
}
} else if ($element['type'] == 'mappedSuperclass') {
$metadata->setCustomRepositoryClass(
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
);
$metadata->isMappedSuperclass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
@@ -165,15 +162,16 @@ class YamlDriver extends AbstractFileDriver
continue;
}
if (!isset($idElement['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$mapping = array(
'id' => true,
'fieldName' => $name
'fieldName' => $name,
'type' => $idElement['type']
);
if (isset($idElement['type'])) {
$mapping['type'] = $idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = $idElement['column'];
}
@@ -182,10 +180,6 @@ class YamlDriver extends AbstractFileDriver
$mapping['length'] = $idElement['length'];
}
if (isset($idElement['columnDefinition'])) {
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {
@@ -204,21 +198,19 @@ class YamlDriver extends AbstractFileDriver
// Evaluate fields
if (isset($element['fields'])) {
foreach ($element['fields'] as $name => $fieldMapping) {
$mapping = array(
'fieldName' => $name
);
if (isset($fieldMapping['type'])) {
$e = explode('(', $fieldMapping['type']);
$fieldMapping['type'] = $e[0];
$mapping['type'] = $fieldMapping['type'];
if (isset($e[1])) {
$fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1);
}
if (!isset($fieldMapping['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$e = explode('(', $fieldMapping['type']);
$fieldMapping['type'] = $e[0];
if (isset($e[1])) {
$fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1);
}
$mapping = array(
'fieldName' => $name,
'type' => $fieldMapping['type']
);
if (isset($fieldMapping['id'])) {
$mapping['id'] = true;
if (isset($fieldMapping['generator']['strategy'])) {
@@ -383,6 +375,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $manyToOneElement['cascade'];
}
if (isset($manyToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement['orphanRemoval'];
}
$metadata->mapManyToOne($mapping);
}
}
@@ -438,6 +434,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $manyToManyElement['cascade'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
if (isset($manyToManyElement['orderBy'])) {
$mapping['orderBy'] = $manyToManyElement['orderBy'];
}
@@ -446,10 +446,6 @@ class YamlDriver extends AbstractFileDriver
$mapping['indexBy'] = $manyToManyElement['indexBy'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
$metadata->mapManyToMany($mapping);
}
}
@@ -494,6 +490,10 @@ class YamlDriver extends AbstractFileDriver
$joinColumn['onDelete'] = $joinColumnElement['onDelete'];
}
if (isset($joinColumnElement['onUpdate'])) {
$joinColumn['onUpdate'] = $joinColumnElement['onUpdate'];
}
if (isset($joinColumnElement['columnDefinition'])) {
$joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
}

View File

@@ -1,31 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ALL")
* @todo check available targets
*/
final class ElementCollection implements Annotation
{
/** @var string */
public $tableName;
}

View File

@@ -1,32 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Entity implements Annotation
{
/** @var string */
public $repositoryClass;
/** @var boolean */
public $readOnly = false;
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class GeneratedValue implements Annotation
{
/** @var string */
public $strategy = 'AUTO';
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class HasLifecycleCallbacks implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Id implements Annotation
{
}

View File

@@ -1,32 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class Index implements Annotation
{
/** @var string */
public $name;
/** @var array<string> */
public $columns;
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class InheritanceType implements Annotation
{
/** @var string */
public $value;
}

View File

@@ -1,42 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinColumn implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $referencedColumnName = 'id';
/** @var boolean */
public $unique = false;
/** @var boolean */
public $nullable = true;
/** @var mixed */
public $onDelete;
/** @var string */
public $columnDefinition;
/** @var string */
public $fieldName; // field name used in non-object hydration (array/scalar)
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class JoinColumns implements Annotation
{
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $value;
}

View File

@@ -1,36 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class JoinTable implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $schema;
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $joinColumns = array();
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $inverseJoinColumns = array();
}

View File

@@ -1,42 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToMany implements Annotation
{
/** @var string */
public $targetEntity;
/** @var string */
public $mappedBy;
/** @var string */
public $inversedBy;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var boolean */
public $orphanRemoval = false;
/** @var string */
public $indexBy;
}

View File

@@ -1,36 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToOne implements Annotation
{
/** @var string */
public $targetEntity;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var string */
public $inversedBy;
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class MappedSuperclass implements Annotation
{
/** @var string */
public $repositoryClass;
}

View File

@@ -68,11 +68,6 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No mapping file found named '$fileName' for class '$entityName'.");
}
public static function invalidMappingFile($entityName, $fileName)
{
return new self("Invalid mapping file '$fileName' for class '$entityName'.");
}
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' on class '$className'.");
@@ -189,7 +184,7 @@ class MappingException extends \Doctrine\ORM\ORMException
if ( ! empty($path)) {
$path = '[' . $path . ']';
}
return new self(
'File mapping drivers must have a valid directory path, ' .
'however the given path ' . $path . ' seems to be incorrect!'
@@ -231,11 +226,6 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported.");
}
public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type)
{
return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers.");
}
/**
* @param string $className
* @param string $columnName
@@ -280,12 +270,6 @@ class MappingException extends \Doctrine\ORM\ORMException
"part of the identifier in '$className#$field'.");
}
public static function illegalOrphanRemoval($className, $field)
{
return new self("Orphan removal is only allowed on one-to-one and one-to-many ".
"associations, but " . $className."#" .$field . " is not.");
}
public static function illegalInverseIdentifierAssocation($className, $field)
{
return new self("An inverse association is not allowed to be identifier in '$className#$field'.");
@@ -295,38 +279,18 @@ class MappingException extends \Doctrine\ORM\ORMException
{
return new self("Many-to-many or one-to-many associations are not allowed to be identifier in '$className#$field'.");
}
public static function noInheritanceOnMappedSuperClass($className)
{
return new self("Its not supported to define inheritance information on a mapped superclass '" . $className . "'.");
}
public static function mappedClassNotPartOfDiscriminatorMap($className, $rootClassName)
{
return new self(
"Entity '" . $className . "' has to be part of the discriminator map of '" . $rootClassName . "' " .
"Entity '" . $className . "' has to be part of the descriminator map of '" . $rootClassName . "' " .
"to be properly mapped in the inheritance hierachy. Alternatively you can make '".$className."' an abstract class " .
"to avoid this exception from occuring."
);
}
public static function lifecycleCallbackMethodNotFound($className, $methodName)
{
return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback.");
}
public static function invalidFetchMode($className, $annotation)
{
return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'");
}
public static function compositeKeyAssignedIdGeneratorRequired($className)
{
return new self("Entity '". $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.");
}
public static function invalidTargetEntityClass($targetEntity, $sourceEntity, $associationName)
{
return new self("The target-entity " . $targetEntity . " cannot be found in '" . $sourceEntity."#".$associationName."'.");
}
}
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class NamedQueries implements Annotation
{
/** @var array<\Doctrine\ORM\Mapping\NamedQuery> */
public $value;
}

View File

@@ -1,32 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class NamedQuery implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $query;
}

View File

@@ -1,40 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToMany implements Annotation
{
/** @var string */
public $mappedBy;
/** @var string */
public $targetEntity;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var boolean */
public $orphanRemoval = false;
/** @var string */
public $indexBy;
}

View File

@@ -1,40 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToOne implements Annotation
{
/** @var string */
public $targetEntity;
/** @var string */
public $mappedBy;
/** @var string */
public $inversedBy;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var boolean */
public $orphanRemoval = false;
}

View File

@@ -1,30 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OrderBy implements Annotation
{
/** @var array<string> */
public $value;
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostLoad implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostPersist implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostRemove implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostUpdate implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreFlush implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PrePersist implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreRemove implements Annotation
{
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreUpdate implements Annotation
{
}

View File

@@ -1,34 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class SequenceGenerator implements Annotation
{
/** @var string */
public $sequenceName;
/** @var integer */
public $allocationSize = 1;
/** @var integer */
public $initialValue = 1;
}

View File

@@ -1,36 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Table implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $schema;
/** @var array<\Doctrine\ORM\Mapping\Index> */
public $indexes;
/** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */
public $uniqueConstraints;
}

View File

@@ -1,32 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class UniqueConstraint implements Annotation
{
/** @var string */
public $name;
/** @var array<string> */
public $columns;
}

View File

@@ -1,28 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Version implements Annotation
{
}

View File

@@ -1,4 +1,4 @@
<?php
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -38,7 +38,6 @@ final class NativeQuery extends AbstractQuery
public function setSQL($sql)
{
$this->_sql = $sql;
return $this;
}
@@ -58,19 +57,17 @@ final class NativeQuery extends AbstractQuery
*/
protected function _doExecute()
{
$stmt = $this->_em->getConnection()->prepare($this->_sql);
$params = $this->_params;
$types = $this->_paramTypes;
if ($params && is_int(key($params))) {
ksort($params);
ksort($types);
$params = array_values($params);
$types = array_values($types);
foreach ($params as $key => $value) {
if (isset($this->_paramTypes[$key])) {
$stmt->bindValue($key, $value, $this->_paramTypes[$key]);
} else {
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
return $this->_em->getConnection()->executeQuery(
$this->_sql, $params, $types, $this->_queryCacheProfile
);
return $stmt;
}
}

View File

@@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly does not return any results.
*
*
* @author robo
* @since 2.0
*/

View File

@@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly returns more than one result.
*
*
* @author robo
* @since 2.0
*/

View File

@@ -34,40 +34,32 @@ class ORMException extends Exception
return new self("It's a requirement to specify a Metadata Driver and pass it ".
"to Doctrine\ORM\Configuration::setMetadataDriverImpl().");
}
public static function entityMissingForeignAssignedId($entity, $relatedEntity)
{
return new self(
"Entity of type " . get_class($entity) . " has identity through a foreign entity " . get_class($relatedEntity) . ", " .
"however this entity has no identity itself. You have to call EntityManager#persist() on the related entity " .
"and make sure that an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " .
"however this entity has no ientity itself. You have to call EntityManager#persist() on the related entity " .
"and make sure it an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " .
"of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call " .
"EntityManager#flush() between both persist operations."
);
}
public static function entityMissingAssignedIdForField($entity, $field)
public static function entityMissingAssignedId($entity)
{
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID for field '" . $field . "'. " .
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID. " .
"The identifier generation strategy for this entity requires the ID field to be populated before ".
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
"you need to adjust the metadata mapping accordingly."
);
}
public static function unrecognizedField($field)
{
return new self("Unrecognized field: $field");
}
/**
* @param string $className
* @param string $field
*/
public static function invalidOrientation($className, $field)
{
return new self("Invalid order by orientation specified for " . $className . "#" . $field);
}
public static function invalidFlushMode($mode)
{
return new self("'$mode' is an invalid flush mode.");
@@ -138,15 +130,4 @@ class ORMException extends Exception
"Unknown Entity namespace alias '$entityNamespaceAlias'."
);
}
public static function invalidEntityRepository($className)
{
return new self("Invalid repository class '".$className."'. ".
"it must be a Doctrine\ORM\EntityRepository.");
}
public static function missingIdentifierField($className, $fieldName)
{
return new self("The identifier $fieldName is missing for a query of " . $className);
}
}

View File

@@ -1,107 +0,0 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
/**
* Contains exception messages for all invalid lifecycle state exceptions inside UnitOfWork
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ORMInvalidArgumentException extends \InvalidArgumentException
{
static public function scheduleInsertForManagedEntity($entity)
{
return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertForRemovedEntity($entity)
{
return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertTwice($entity)
{
return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice.");
}
static public function entityWithoutIdentity($className, $entity)
{
throw new self(
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"id values set. It cannot be added to the identity map."
);
}
static public function readOnlyRequiresManagedEntity($entity)
{
return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not");
}
static public function newEntityFoundThroughRelationship(array $assoc, $entry)
{
return new self("A new entity was found through the relationship '"
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
. " To solve this issue: Either explicitly call EntityManager#persist()"
. " on this unknown entity or configure cascade persist "
. " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). "
. " If you cannot find out which entity causes the problem"
. " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.");
}
static public function detachedEntityFoundThroughRelationship(array $assoc, $entry)
{
throw new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") "
. " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' "
. "during cascading a persist operation.");
}
static public function entityNotManaged($entity)
{
throw new self("Entity " . self::objToStr($entity) . " is not managed. An entity is managed if its fetched " .
"from the database or registered as new through EntityManager#persist");
}
static public function entityHasNoIdentity($entity, $operation)
{
throw new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function entityIsRemoved($entity, $operation)
{
throw new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function detachedEntityCannot($entity, $operation)
{
throw new self("A detached entity was found during " . $operation . " " . self::objToStr($entity));
}
/**
* Helper method to show an object as string.
*
* @param object $obj
* @return string
*/
private static function objToStr($obj)
{
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
}
}

View File

@@ -21,7 +21,6 @@ namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\Common\Collections\Collection,
Doctrine\Common\Collections\ArrayCollection,
Closure;
/**
@@ -67,7 +66,7 @@ final class PersistentCollection implements Collection
/**
* The EntityManager that manages the persistence of the collection.
*
* @var \Doctrine\ORM\EntityManager
* @var Doctrine\ORM\EntityManager
*/
private $em;
@@ -94,29 +93,29 @@ final class PersistentCollection implements Collection
/**
* Whether the collection has already been initialized.
*
*
* @var boolean
*/
private $initialized = true;
/**
* The wrapped Collection instance.
*
*
* @var Collection
*/
private $coll;
/**
* Creates a new persistent collection.
*
*
* @param EntityManager $em The EntityManager the collection will be associated with.
* @param ClassMetadata $class The class descriptor of the entity type of this collection.
* @param array The collection elements.
*/
public function __construct(EntityManager $em, $class, $coll)
{
$this->coll = $coll;
$this->em = $em;
$this->coll = $coll;
$this->em = $em;
$this->typeClass = $class;
}
@@ -130,8 +129,8 @@ final class PersistentCollection implements Collection
*/
public function setOwner($entity, array $assoc)
{
$this->owner = $entity;
$this->association = $assoc;
$this->owner = $entity;
$this->association = $assoc;
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
}
@@ -145,7 +144,7 @@ final class PersistentCollection implements Collection
{
return $this->owner;
}
public function getTypeClass()
{
return $this->typeClass;
@@ -155,27 +154,25 @@ final class PersistentCollection implements Collection
* INTERNAL:
* Adds an element to a collection during hydration. This will automatically
* complete bidirectional associations in the case of a one-to-many association.
*
*
* @param mixed $element The element to add.
*/
public function hydrateAdd($element)
{
$this->coll->add($element);
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
$this->em->getUnitOfWork()->setOriginalEntityProperty(
spl_object_hash($element), $this->backRefFieldName, $this->owner
);
spl_object_hash($element),
$this->backRefFieldName,
$this->owner);
}
}
/**
* INTERNAL:
* Sets a keyed element in the collection during hydration.
@@ -186,14 +183,12 @@ final class PersistentCollection implements Collection
public function hydrateSet($key, $element)
{
$this->coll->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
}
}
@@ -203,31 +198,23 @@ final class PersistentCollection implements Collection
*/
public function initialize()
{
if ($this->initialized || ! $this->association) {
return;
}
// Has NEW objects added through add(). Remember them.
$newObjects = array();
if ($this->isDirty) {
$newObjects = $this->coll->toArray();
}
$this->coll->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if ($newObjects) {
foreach ($newObjects as $obj) {
$this->coll->add($obj);
if ( ! $this->initialized && $this->association) {
if ($this->isDirty) {
// Has NEW objects added through add(). Remember them.
$newObjects = $this->coll->toArray();
}
$this->isDirty = true;
$this->coll->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if (isset($newObjects)) {
foreach ($newObjects as $obj) {
$this->coll->add($obj);
}
$this->isDirty = true;
}
$this->initialized = true;
}
$this->initialized = true;
}
/**
@@ -237,7 +224,7 @@ final class PersistentCollection implements Collection
public function takeSnapshot()
{
$this->snapshot = $this->coll->toArray();
$this->isDirty = false;
$this->isDirty = false;
}
/**
@@ -259,11 +246,8 @@ final class PersistentCollection implements Collection
*/
public function getDeleteDiff()
{
return array_udiff_assoc(
$this->snapshot,
$this->coll->toArray(),
function($a, $b) { return $a === $b ? 0 : 1; }
);
return array_udiff_assoc($this->snapshot, $this->coll->toArray(),
function($a, $b) {return $a === $b ? 0 : 1;});
}
/**
@@ -274,40 +258,31 @@ final class PersistentCollection implements Collection
*/
public function getInsertDiff()
{
return array_udiff_assoc(
$this->coll->toArray(),
$this->snapshot,
function($a, $b) { return $a === $b ? 0 : 1; }
);
return array_udiff_assoc($this->coll->toArray(), $this->snapshot,
function($a, $b) {return $a === $b ? 0 : 1;});
}
/**
* INTERNAL: Gets the association mapping of the collection.
*
* @return \Doctrine\ORM\Mapping\AssociationMapping
* @return Doctrine\ORM\Mapping\AssociationMapping
*/
public function getMapping()
{
return $this->association;
}
/**
* Marks this collection as changed/dirty.
*/
private function changed()
{
if ($this->isDirty) {
return;
}
$this->isDirty = true;
if ($this->association !== null &&
$this->association['isOwningSide'] &&
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->owner &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
if ( ! $this->isDirty) {
$this->isDirty = true;
if ($this->association !== null && $this->association['isOwningSide'] && $this->association['type'] == ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
}
}
@@ -331,17 +306,17 @@ final class PersistentCollection implements Collection
{
$this->isDirty = $dirty;
}
/**
* Sets the initialized flag of the collection, forcing it into that state.
*
*
* @param boolean $bool
*/
public function setInitialized($bool)
{
$this->initialized = $bool;
}
/**
* Checks whether this collection has been initialized.
*
@@ -356,7 +331,6 @@ final class PersistentCollection implements Collection
public function first()
{
$this->initialize();
return $this->coll->first();
}
@@ -364,7 +338,6 @@ final class PersistentCollection implements Collection
public function last()
{
$this->initialize();
return $this->coll->last();
}
@@ -378,19 +351,13 @@ final class PersistentCollection implements Collection
// not used we can issue a straight SQL delete/update on the
// association (table). Without initializing the collection.
$this->initialize();
$removed = $this->coll->remove($key);
if ( ! $removed) {
return $removed;
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] & ClassMetadata::TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
}
return $removed;
@@ -401,36 +368,25 @@ final class PersistentCollection implements Collection
*/
public function removeElement($element)
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ($this->coll->contains($element)) {
return $this->coll->removeElement($element);
}
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
if ($persister->removeElement($this, $element)) {
return $element;
}
return null;
}
// TODO: Assuming the identity of entities in a collection is always based
// on their primary key (there is no equals/hashCode in PHP),
// if the collection is not initialized, we could issue a straight
// SQL DELETE/UPDATE on the association (table) without initializing
// the collection.
/*if ( ! $this->initialized) {
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
->deleteRows($this, $element);
}*/
$this->initialize();
$removed = $this->coll->removeElement($element);
if ( ! $removed) {
return $removed;
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] & ClassMetadata::TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
return $removed;
}
@@ -440,7 +396,6 @@ final class PersistentCollection implements Collection
public function containsKey($key)
{
$this->initialize();
return $this->coll->containsKey($key);
}
@@ -449,14 +404,14 @@ final class PersistentCollection implements Collection
*/
public function contains($element)
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->coll->contains($element) || $persister->contains($this, $element);
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->coll->contains($element) ||
$this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->contains($this, $element);
}
$this->initialize();
return $this->coll->contains($element);
}
@@ -466,7 +421,6 @@ final class PersistentCollection implements Collection
public function exists(Closure $p)
{
$this->initialize();
return $this->coll->exists($p);
}
@@ -476,7 +430,6 @@ final class PersistentCollection implements Collection
public function indexOf($element)
{
$this->initialize();
return $this->coll->indexOf($element);
}
@@ -486,7 +439,6 @@ final class PersistentCollection implements Collection
public function get($key)
{
$this->initialize();
return $this->coll->get($key);
}
@@ -496,7 +448,6 @@ final class PersistentCollection implements Collection
public function getKeys()
{
$this->initialize();
return $this->coll->getKeys();
}
@@ -506,7 +457,6 @@ final class PersistentCollection implements Collection
public function getValues()
{
$this->initialize();
return $this->coll->getValues();
}
@@ -515,14 +465,13 @@ final class PersistentCollection implements Collection
*/
public function count()
{
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->count($this) + $this->coll->count();
}
$this->initialize();
return $this->coll->count();
}
@@ -532,9 +481,7 @@ final class PersistentCollection implements Collection
public function set($key, $value)
{
$this->initialize();
$this->coll->set($key, $value);
$this->changed();
}
@@ -544,9 +491,7 @@ final class PersistentCollection implements Collection
public function add($value)
{
$this->coll->add($value);
$this->changed();
return true;
}
@@ -556,17 +501,15 @@ final class PersistentCollection implements Collection
public function isEmpty()
{
$this->initialize();
return $this->coll->isEmpty();
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
$this->initialize();
return $this->coll->getIterator();
}
@@ -576,7 +519,6 @@ final class PersistentCollection implements Collection
public function map(Closure $func)
{
$this->initialize();
return $this->coll->map($func);
}
@@ -586,17 +528,15 @@ final class PersistentCollection implements Collection
public function filter(Closure $p)
{
$this->initialize();
return $this->coll->filter($p);
}
/**
* {@inheritdoc}
*/
public function forAll(Closure $p)
{
$this->initialize();
return $this->coll->forAll($p);
}
@@ -606,17 +546,15 @@ final class PersistentCollection implements Collection
public function partition(Closure $p)
{
$this->initialize();
return $this->coll->partition($p);
}
/**
* {@inheritdoc}
*/
public function toArray()
{
$this->initialize();
return $this->coll->toArray();
}
@@ -628,32 +566,20 @@ final class PersistentCollection implements Collection
if ($this->initialized && $this->isEmpty()) {
return;
}
$uow = $this->em->getUnitOfWork();
if ($this->association['type'] & ClassMetadata::TO_MANY && $this->association['orphanRemoval']) {
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
// hence for event listeners we need the objects in memory.
$this->initialize();
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
foreach ($this->coll as $element) {
$uow->scheduleOrphanRemoval($element);
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
}
$this->coll->clear();
$this->initialized = true; // direct call, {@link initialize()} is too expensive
if ($this->association['isOwningSide']) {
$this->changed();
$uow->scheduleCollectionDeletion($this);
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);
$this->takeSnapshot();
}
}
/**
* Called by PHP when this collection is serialized. Ensures that only the
* elements are properly serialized.
@@ -665,7 +591,7 @@ final class PersistentCollection implements Collection
{
return array('coll', 'initialized');
}
/* ArrayAccess implementation */
/**
@@ -693,7 +619,6 @@ final class PersistentCollection implements Collection
if ( ! isset($offset)) {
return $this->add($value);
}
return $this->set($offset, $value);
}
@@ -704,12 +629,12 @@ final class PersistentCollection implements Collection
{
return $this->remove($offset);
}
public function key()
{
return $this->coll->key();
}
/**
* Gets the element of the collection at the current iterator position.
*/
@@ -717,7 +642,7 @@ final class PersistentCollection implements Collection
{
return $this->coll->current();
}
/**
* Moves the internal iterator position to the next element.
*/
@@ -725,11 +650,9 @@ final class PersistentCollection implements Collection
{
return $this->coll->next();
}
/**
* Retrieves the wrapped Collection instance.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function unwrap()
{
@@ -745,42 +668,17 @@ final class PersistentCollection implements Collection
*
* @param int $offset
* @param int $length
*
* @return array
*/
public function slice($offset, $length = null)
{
if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->slice($this, $offset, $length);
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->slice($this, $offset, $length);
}
$this->initialize();
return $this->coll->slice($offset, $length);
}
/**
* Cleanup internal state of cloned persistent collection.
*
* The following problems have to be prevented:
* 1. Added entities are added to old PC
* 2. New collection is not dirty, if reused on other entity nothing
* changes.
* 3. Snapshot leads to invalid diffs being generated.
* 4. Lazy loading grabs entities from old owner object.
* 5. New collection is connected to old owner and leads to duplicate keys.
*/
public function __clone()
{
$this->initialize();
$this->owner = null;
if (is_object($this->coll)) {
$this->coll = clone $this->coll;
}
$this->snapshot = array();
$this->changed();
}
}

View File

@@ -36,19 +36,19 @@ abstract class AbstractCollectionPersister
protected $_em;
/**
* @var \Doctrine\DBAL\Connection
* @var Doctrine\DBAL\Connection
*/
protected $_conn;
/**
* @var \Doctrine\ORM\UnitOfWork
* @var Doctrine\ORM\UnitOfWork
*/
protected $_uow;
/**
* Initializes a new instance of a class derived from AbstractCollectionPersister.
*
* @param \Doctrine\ORM\EntityManager $em
* @param Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
@@ -65,11 +65,9 @@ abstract class AbstractCollectionPersister
public function delete(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSQL($coll);
$this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll));
}
@@ -98,34 +96,30 @@ abstract class AbstractCollectionPersister
public function update(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$this->deleteRows($coll);
//$this->updateRows($coll);
$this->insertRows($coll);
}
public function deleteRows(PersistentCollection $coll)
{
{
$deleteDiff = $coll->getDeleteDiff();
$sql = $this->_getDeleteRowSQL($coll);
foreach ($deleteDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
}
}
//public function updateRows(PersistentCollection $coll)
//{}
public function insertRows(PersistentCollection $coll)
{
$insertDiff = $coll->getInsertDiff();
$sql = $this->_getInsertRowSQL($coll);
foreach ($insertDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element));
}
@@ -151,16 +145,6 @@ abstract class AbstractCollectionPersister
throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister.");
}
public function removeElement(PersistentCollection $coll, $element)
{
throw new \BadMethodCallException("Removing an element is not supported by this CollectionPersister.");
}
public function removeKey(PersistentCollection $coll, $key)
{
throw new \BadMethodCallException("Removing a key is not supported by this CollectionPersister.");
}
public function get(PersistentCollection $coll, $index)
{
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
@@ -168,7 +152,7 @@ abstract class AbstractCollectionPersister
/**
* Gets the SQL statement used for deleting a row from the collection.
*
*
* @param PersistentCollection $coll
*/
abstract protected function _getDeleteRowSQL(PersistentCollection $coll);
@@ -204,4 +188,4 @@ abstract class AbstractCollectionPersister
* @param mixed $element
*/
abstract protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element);
}
}

View File

@@ -26,7 +26,7 @@ use Doctrine\ORM\Mapping\ClassMetadata,
* Base class for entity persisters that implement a certain inheritance mapping strategy.
* All these persisters are assumed to use a discriminator column to discriminate entity
* types in the hierarchy.
*
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
@@ -39,18 +39,16 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
protected function _prepareInsertData($entity)
{
$data = parent::_prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->_class->discriminatorColumn;
$this->_columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue;
return $data;
}
/**
* Gets the name of the table that contains the discriminator column.
*
*
* @return string The table name.
*/
abstract protected function _getDiscriminatorColumnTableName();
@@ -62,22 +60,18 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($columnName);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
return "$sql AS $columnAlias";
}
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
{
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
$this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++;
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
return $tableAlias . ".$joinColumnName AS $columnAlias";
}
}
}

Some files were not shown because too many files have changed in this diff Show More