Compare commits

..

81 Commits
2.3.3 ... 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
668 changed files with 11661 additions and 42172 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 = git://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

517
LICENSE
View File

@@ -1,19 +1,504 @@
Copyright (c) 2006-2012 Doctrine Project
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,19 +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.2: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.2)](http://travis-ci.org/doctrine/doctrine2)
2.1: [![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://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
* [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

@@ -1,475 +0,0 @@
# Upgrade to 2.3
## EntityManager#find() not calls EntityRepository#find() anymore
Previous to 2.3, calling ``EntityManager#find()`` would be delegated to
``EntityRepository#find()``. This has lead to some unexpected behavior in the
core of Doctrine when people have overwritten the find method in their
repositories. That is why this behavior has been reversed in 2.3, and
``EntityRepository#find()`` calls ``EntityManager#find()`` instead.
## EntityGenerator add*() method generation
When generating an add*() method for a collection the EntityGenerator will now not
use the Type-Hint to get the singular for the collection name, but use the field-name
and strip a trailing "s" character if there is one.
## Merge copies non persisted properties too
When merging an entity in UoW not only mapped properties are copied, but also others.
## Query, QueryBuilder and NativeQuery parameters *BC break*
From now on, parameters in queries is an ArrayCollection instead of a simple array.
This affects heavily the usage of setParameters(), because it will not append anymore
parameters to query, but will actually override the already defined ones.
Whenever you are retrieving a parameter (ie. $query->getParameter(1)), you will
receive an instance of Query\Parameter, which contains the methods "getName",
"getValue" and "getType". Parameters are also only converted to when necessary, and
not when they are set.
Also, related functions were affected:
* execute($parameters, $hydrationMode) the argument $parameters can be either an key=>value array or an ArrayCollection instance
* iterate($parameters, $hydrationMode) the argument $parameters can be either an key=>value array or an ArrayCollection instance
* setParameters($parameters) the argument $parameters can be either an key=>value array or an ArrayCollection instance
* getParameters() now returns ArrayCollection instead of array
* getParameter($key) now returns Parameter instance instead of parameter value
## Query TreeWalker method renamed
Internal changes were made to DQL and SQL generation. If you have implemented your own TreeWalker,
you probably need to update it. The method walkJoinVariableDeclaration is now named walkJoin.
## Metadata Drivers
Metadata drivers have been rewritten to reuse code from Doctrine\Common. Anyone who is using the
`Doctrine\ORM\Mapping\Driver\Driver` interface should instead refer to
`Doctrine\Common\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\ORM\Mapping\Driver\AbstractFileDriver`: you should now refer to
`Doctrine\Common\Persistence\Mapping\Driver\FileDriver`.
Also, following mapping drivers have been deprecated, please use their replacements in Doctrine\Common as listed:
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver`
# Upgrade to 2.2
## 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.
## EntityManager#find(null)
Previously EntityManager#find(null) returned null. It now throws an exception.
# Upgrade to 2.1
## Interface for EntityRepository
The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
## AnnotationReader changes
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();
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
// new code necessary starting here
$reader->setIgnoreNotImportedAnnotations(true);
$reader->setEnableParsePhpImports(false);
$reader = new \Doctrine\Common\Annotations\CachedReader(
new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache()
);
This is already done inside the ``$config->newDefaultAnnotationDriver``, so everything should automatically work if you are using this method. You can verify if everything still works by executing a console command such as schema-validate that loads all metadata into memory.
# Update from 2.0-BETA3 to 2.0-BETA4
## XML Driver <change-tracking-policy /> element demoted to attribute
We changed how the XML Driver allows to define the change-tracking-policy. The working case is now:
<entity change-tracking-policy="DEFERRED_IMPLICT" />
# Update from 2.0-BETA2 to 2.0-BETA3
## Serialization of Uninitialized Proxies
As of Beta3 you can now serialize uninitialized proxies, an exception will only be thrown when
trying to access methods on the unserialized proxy as long as it has not been re-attached to the
EntityManager using `EntityManager#merge()`. See this example:
$proxy = $em->getReference('User', 1);
$serializedProxy = serialize($proxy);
$detachedProxy = unserialized($serializedProxy);
echo $em->contains($detachedProxy); // FALSE
try {
$detachedProxy->getId(); // uninitialized detached proxy
} catch(Exception $e) {
}
$attachedProxy = $em->merge($detachedProxy);
echo $attackedProxy->getId(); // works!
## Changed SQL implementation of Postgres and Oracle DateTime types
The DBAL Type "datetime" included the Timezone Offset in both Postgres and Oracle. As of this version they are now
generated without Timezone (TIMESTAMP WITHOUT TIME ZONE instead of TIMESTAMP WITH TIME ZONE).
See [this comment to Ticket DBAL-22](http://www.doctrine-project.org/jira/browse/DBAL-22?focusedCommentId=13396&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_13396)
for more details as well as migration issues for PostgreSQL and Oracle.
Both Postgres and Oracle will throw Exceptions during hydration of Objects with "DateTime" fields unless migration steps are taken!
## Removed multi-dot/deep-path expressions in DQL
The support for implicit joins in DQL through the multi-dot/Deep Path Expressions
was dropped. For example:
SELECT u FROM User u WHERE u.group.name = ?1
See the "u.group.id" here is using multi dots (deep expression) to walk
through the graph of objects and properties. Internally the DQL parser
would rewrite these queries to:
SELECT u FROM User u JOIN u.group g WHERE g.name = ?1
This explicit notation will be the only supported notation as of now. The internal
handling of multi-dots in the DQL Parser was very complex, error prone in edge cases
and required special treatment for several features we added. Additionally
it had edge cases that could not be solved without making the DQL Parser
even much more complex. For this reason we will drop the support for the
deep path expressions to increase maintainability and overall performance
of the DQL parsing process. This will benefit any DQL query being parsed,
even those not using deep path expressions.
Note that the generated SQL of both notations is exactly the same! You
don't loose anything through this.
## Default Allocation Size for Sequences
The default allocation size for sequences has been changed from 10 to 1. This step was made
to not cause confusion with users and also because it is partly some kind of premature optimization.
# Update from 2.0-BETA1 to 2.0-BETA2
There are no backwards incompatible changes in this release.
# Upgrade from 2.0-ALPHA4 to 2.0-BETA1
## EntityRepository deprecates access to protected variables
Instead of accessing protected variables for the EntityManager in
a custom EntityRepository it is now required to use the getter methods
for all the three instance variables:
* `$this->_em` now accessible through `$this->getEntityManager()`
* `$this->_class` now accessible through `$this->getClassMetadata()`
* `$this->_entityName` now accessible through `$this->getEntityName()`
Important: For Beta 2 the protected visibility of these three properties will be
changed to private!
## Console migrated to Symfony Console
The Doctrine CLI has been replaced by Symfony Console Configuration
Instead of having to specify:
[php]
$cliConfig = new CliConfiguration();
$cliConfig->setAttribute('em', $entityManager);
You now have to configure the script like:
[php]
$helperSet = new \Symfony\Components\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));
## Console: No need for Mapping Paths anymore
In previous versions you had to specify the --from and --from-path options
to show where your mapping paths are from the console. However this information
is already known from the Mapping Driver configuration, so the requirement
for this options were dropped.
Instead for each console command all the entities are loaded and to
restrict the operation to one or more sub-groups you can use the --filter flag.
## AnnotationDriver is not a default mapping driver anymore
In conjunction with the recent changes to Console we realized that the
annotations driver being a default metadata driver lead to lots of glue
code in the console components to detect where entities lie and how to load
them for batch updates like SchemaTool and other commands. However the
annotations driver being a default driver does not really help that much
anyways.
Therefore we decided to break backwards compability in this issue and drop
the support for Annotations as Default Driver and require our users to
specify the driver explicitly (which allows us to ask for the path to all
entities).
If you are using the annotations metadata driver as default driver, you
have to add the following lines to your bootstrap code:
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));
$config->setMetadataDriverImpl($driverImpl);
You have to specify the path to your entities as either string of a single
path or array of multiple paths
to your entities. This information will be used by all console commands to
access all entities.
Xml and Yaml Drivers work as before!
## New inversedBy attribute
It is now *mandatory* that the owning side of a bidirectional association specifies the
'inversedBy' attribute that points to the name of the field on the inverse side that completes
the association. Example:
[php]
// BEFORE (ALPHA4 AND EARLIER)
class User
{
//...
/** @OneToOne(targetEntity="Address", mappedBy="user") */
private $address;
//...
}
class Address
{
//...
/** @OneToOne(targetEntity="User") */
private $user;
//...
}
// SINCE BETA1
// User class DOES NOT CHANGE
class Address
{
//...
/** @OneToOne(targetEntity="User", inversedBy="address") */
private $user;
//...
}
Thus, the inversedBy attribute is the counterpart to the mappedBy attribute. This change
was necessary to enable some simplifications and further performance improvements. We
apologize for the inconvenience.
## Default Property for Field Mappings
The "default" option for database column defaults has been removed. If desired, database column defaults can
be implemented by using the columnDefinition attribute of the @Column annotation (or the approriate XML and YAML equivalents).
Prefer PHP default values, if possible.
## Selecting Partial Objects
Querying for partial objects now has a new syntax. The old syntax to query for partial objects
now has a different meaning. This is best illustrated by an example. If you previously
had a DQL query like this:
[sql]
SELECT u.id, u.name FROM User u
Since BETA1, simple state field path expressions in the select clause are used to select
object fields as plain scalar values (something that was not possible before).
To achieve the same result as previously (that is, a partial object with only id and name populated)
you need to use the following, explicit syntax:
[sql]
SELECT PARTIAL u.{id,name} FROM User u
## XML Mapping Driver
The 'inheritance-type' attribute changed to take last bit of ClassMetadata constant names, i.e.
NONE, SINGLE_TABLE, INHERITANCE_TYPE_JOINED
## YAML Mapping Driver
The way to specify lifecycle callbacks in YAML Mapping driver was changed to allow for multiple callbacks
per event. The Old syntax ways:
[yaml]
lifecycleCallbacks:
doStuffOnPrePersist: prePersist
doStuffOnPostPersist: postPersist
The new syntax is:
[yaml]
lifecycleCallbacks:
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
postPersist: [ doStuffOnPostPersist ]
## PreUpdate Event Listeners
Event Listeners listening to the 'preUpdate' event can only affect the primitive values of entity changesets
by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate listener method. Any changes
to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic
performance benefits for the preUpdate event.
## Collection API
The Collection interface in the Common package has been updated with some missing methods
that were present only on the default implementation, ArrayCollection. Custom collection
implementations need to be updated to adhere to the updated interface.
# Upgrade from 2.0-ALPHA3 to 2.0-ALPHA4
## CLI Controller changes
CLI main object changed its name and namespace. Renamed from Doctrine\ORM\Tools\Cli to Doctrine\Common\Cli\CliController.
Doctrine\Common\Cli\CliController now only deals with namespaces. Ready to go, Core, Dbal and Orm are available and you can subscribe new tasks by retrieving the namespace and including new task. Example:
[php]
$cli->getNamespace('Core')->addTask('my-example', '\MyProject\Tools\Cli\Tasks\MyExampleTask');
## CLI Tasks documentation
Tasks have implemented a new way to build documentation. Although it is still possible to define the help manually by extending the basicHelp and extendedHelp, they are now optional.
With new required method AbstractTask::buildDocumentation, its implementation defines the TaskDocumentation instance (accessible through AbstractTask::getDocumentation()), basicHelp and extendedHelp are now not necessary to be implemented.
## Changes in Method Signatures
* A bunch of Methods on both Doctrine\DBAL\Platforms\AbstractPlatform and Doctrine\DBAL\Schema\AbstractSchemaManager
have changed quite significantly by adopting the new Schema instance objects.
## Renamed Methods
* Doctrine\ORM\AbstractQuery::setExpireResultCache() -> expireResultCache()
* Doctrine\ORM\Query::setExpireQueryCache() -> expireQueryCache()
## SchemaTool Changes
* "doctrine schema-tool --drop" now always drops the complete database instead of
only those tables defined by the current database model. The previous method had
problems when foreign keys of orphaned tables pointed to tables that were schedulded
for deletion.
* Use "doctrine schema-tool --update" to get a save incremental update for your
database schema without deleting any unused tables, sequences or foreign keys.
* Use "doctrine schema-tool --complete-update" to do a full incremental update of
your schema.
# Upgrade from 2.0-ALPHA2 to 2.0-ALPHA3
This section details the changes made to Doctrine 2.0-ALPHA3 to make it easier for you
to upgrade your projects to use this version.
## CLI Changes
The $args variable used in the cli-config.php for configuring the Doctrine CLI has been renamed to $globalArguments.
## Proxy class changes
You are now required to make supply some minimalist configuration with regards to proxy objects. That involves 2 new configuration options. First, the directory where generated proxy classes should be placed needs to be specified. Secondly, you need to configure the namespace used for proxy classes. The following snippet shows an example:
[php]
// step 1: configure directory for proxy classes
// $config instanceof Doctrine\ORM\Configuration
$config->setProxyDir('/path/to/myproject/lib/MyProject/Generated/Proxies');
$config->setProxyNamespace('MyProject\Generated\Proxies');
Note that proxy classes behave exactly like any other classes when it comes to class loading. Therefore you need to make sure the proxy classes can be loaded by some class loader. If you place the generated proxy classes in a namespace and directory under your projects class files, like in the example above, it would be sufficient to register the MyProject namespace on a class loader. Since the proxy classes are contained in that namespace and adhere to the standards for class loading, no additional work is required.
Generating the proxy classes into a namespace within your class library is the recommended setup.
Entities with initialized proxy objects can now be serialized and unserialized properly from within the same application.
For more details refer to the Configuration section of the manual.
## Removed allowPartialObjects configuration option
The allowPartialObjects configuration option together with the `Configuration#getAllowPartialObjects` and `Configuration#setAllowPartialObjects` methods have been removed.
The new behavior is as if the option were set to FALSE all the time, basically disallowing partial objects globally. However, you can still use the `Query::HINT_FORCE_PARTIAL_LOAD` query hint to force a query to return partial objects for optimization purposes.
## Renamed Methods
* Doctrine\ORM\Configuration#getCacheDir() to getProxyDir()
* Doctrine\ORM\Configuration#setCacheDir($dir) to setProxyDir($dir)

240
UPGRADE_TO_2_0 Normal file
View File

@@ -0,0 +1,240 @@
# Update from 2.0-BETA3 to 2.0-BETA4
## XML Driver <change-tracking-policy /> element demoted to attribute
We changed how the XML Driver allows to define the change-tracking-policy. The working case is now:
<entity change-tracking-policy="DEFERRED_IMPLICT" />
# Update from 2.0-BETA2 to 2.0-BETA3
## Serialization of Uninitialized Proxies
As of Beta3 you can now serialize uninitialized proxies, an exception will only be thrown when
trying to access methods on the unserialized proxy as long as it has not been re-attached to the
EntityManager using `EntityManager#merge()`. See this example:
$proxy = $em->getReference('User', 1);
$serializedProxy = serialize($proxy);
$detachedProxy = unserialized($serializedProxy);
echo $em->contains($detachedProxy); // FALSE
try {
$detachedProxy->getId(); // uninitialized detached proxy
} catch(Exception $e) {
}
$attachedProxy = $em->merge($detachedProxy);
echo $attackedProxy->getId(); // works!
## Changed SQL implementation of Postgres and Oracle DateTime types
The DBAL Type "datetime" included the Timezone Offset in both Postgres and Oracle. As of this version they are now
generated without Timezone (TIMESTAMP WITHOUT TIME ZONE instead of TIMESTAMP WITH TIME ZONE).
See [this comment to Ticket DBAL-22](http://www.doctrine-project.org/jira/browse/DBAL-22?focusedCommentId=13396&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_13396)
for more details as well as migration issues for PostgreSQL and Oracle.
Both Postgres and Oracle will throw Exceptions during hydration of Objects with "DateTime" fields unless migration steps are taken!
## Removed multi-dot/deep-path expressions in DQL
The support for implicit joins in DQL through the multi-dot/Deep Path Expressions
was dropped. For example:
SELECT u FROM User u WHERE u.group.name = ?1
See the "u.group.id" here is using multi dots (deep expression) to walk
through the graph of objects and properties. Internally the DQL parser
would rewrite these queries to:
SELECT u FROM User u JOIN u.group g WHERE g.name = ?1
This explicit notation will be the only supported notation as of now. The internal
handling of multi-dots in the DQL Parser was very complex, error prone in edge cases
and required special treatment for several features we added. Additionally
it had edge cases that could not be solved without making the DQL Parser
even much more complex. For this reason we will drop the support for the
deep path expressions to increase maintainability and overall performance
of the DQL parsing process. This will benefit any DQL query being parsed,
even those not using deep path expressions.
Note that the generated SQL of both notations is exactly the same! You
don't loose anything through this.
## Default Allocation Size for Sequences
The default allocation size for sequences has been changed from 10 to 1. This step was made
to not cause confusion with users and also because it is partly some kind of premature optimization.
# Update from 2.0-BETA1 to 2.0-BETA2
There are no backwards incompatible changes in this release.
# Upgrade from 2.0-ALPHA4 to 2.0-BETA1
## EntityRepository deprecates access to protected variables
Instead of accessing protected variables for the EntityManager in
a custom EntityRepository it is now required to use the getter methods
for all the three instance variables:
* `$this->_em` now accessible through `$this->getEntityManager()`
* `$this->_class` now accessible through `$this->getClassMetadata()`
* `$this->_entityName` now accessible through `$this->getEntityName()`
Important: For Beta 2 the protected visibility of these three properties will be
changed to private!
## Console migrated to Symfony Console
The Doctrine CLI has been replaced by Symfony Console Configuration
Instead of having to specify:
[php]
$cliConfig = new CliConfiguration();
$cliConfig->setAttribute('em', $entityManager);
You now have to configure the script like:
[php]
$helperSet = new \Symfony\Components\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));
## Console: No need for Mapping Paths anymore
In previous versions you had to specify the --from and --from-path options
to show where your mapping paths are from the console. However this information
is already known from the Mapping Driver configuration, so the requirement
for this options were dropped.
Instead for each console command all the entities are loaded and to
restrict the operation to one or more sub-groups you can use the --filter flag.
## AnnotationDriver is not a default mapping driver anymore
In conjunction with the recent changes to Console we realized that the
annotations driver being a default metadata driver lead to lots of glue
code in the console components to detect where entities lie and how to load
them for batch updates like SchemaTool and other commands. However the
annotations driver being a default driver does not really help that much
anyways.
Therefore we decided to break backwards compability in this issue and drop
the support for Annotations as Default Driver and require our users to
specify the driver explicitly (which allows us to ask for the path to all
entities).
If you are using the annotations metadata driver as default driver, you
have to add the following lines to your bootstrap code:
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));
$config->setMetadataDriverImpl($driverImpl);
You have to specify the path to your entities as either string of a single
path or array of multiple paths
to your entities. This information will be used by all console commands to
access all entities.
Xml and Yaml Drivers work as before!
## New inversedBy attribute
It is now *mandatory* that the owning side of a bidirectional association specifies the
'inversedBy' attribute that points to the name of the field on the inverse side that completes
the association. Example:
[php]
// BEFORE (ALPHA4 AND EARLIER)
class User
{
//...
/** @OneToOne(targetEntity="Address", mappedBy="user") */
private $address;
//...
}
class Address
{
//...
/** @OneToOne(targetEntity="User") */
private $user;
//...
}
// SINCE BETA1
// User class DOES NOT CHANGE
class Address
{
//...
/** @OneToOne(targetEntity="User", inversedBy="address") */
private $user;
//...
}
Thus, the inversedBy attribute is the counterpart to the mappedBy attribute. This change
was necessary to enable some simplifications and further performance improvements. We
apologize for the inconvenience.
## Default Property for Field Mappings
The "default" option for database column defaults has been removed. If desired, database column defaults can
be implemented by using the columnDefinition attribute of the @Column annotation (or the approriate XML and YAML equivalents).
Prefer PHP default values, if possible.
## Selecting Partial Objects
Querying for partial objects now has a new syntax. The old syntax to query for partial objects
now has a different meaning. This is best illustrated by an example. If you previously
had a DQL query like this:
[sql]
SELECT u.id, u.name FROM User u
Since BETA1, simple state field path expressions in the select clause are used to select
object fields as plain scalar values (something that was not possible before).
To achieve the same result as previously (that is, a partial object with only id and name populated)
you need to use the following, explicit syntax:
[sql]
SELECT PARTIAL u.{id,name} FROM User u
## XML Mapping Driver
The 'inheritance-type' attribute changed to take last bit of ClassMetadata constant names, i.e.
NONE, SINGLE_TABLE, INHERITANCE_TYPE_JOINED
## YAML Mapping Driver
The way to specify lifecycle callbacks in YAML Mapping driver was changed to allow for multiple callbacks
per event. The Old syntax ways:
[yaml]
lifecycleCallbacks:
doStuffOnPrePersist: prePersist
doStuffOnPostPersist: postPersist
The new syntax is:
[yaml]
lifecycleCallbacks:
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
postPersist: [ doStuffOnPostPersist ]
## PreUpdate Event Listeners
Event Listeners listening to the 'preUpdate' event can only affect the primitive values of entity changesets
by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate listener method. Any changes
to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic
performance benefits for the preUpdate event.
## Collection API
The Collection interface in the Common package has been updated with some missing methods
that were present only on the default implementation, ArrayCollection. Custom collection
implementations need to be updated to adhere to the updated interface.

24
UPGRADE_TO_2_1 Normal file
View File

@@ -0,0 +1,24 @@
This document details all the possible changes that you should investigate when updating
your project from Doctrine 2.0.x to 2.1
## Interface for EntityRepository
The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
## AnnotationReader changes
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:
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
// new code necessary starting here
$reader->setIgnoreNotImportedAnnotations(true);
$reader->setEnableParsePhpImports(false);
$reader = new \Doctrine\Common\Annotations\CachedReader(
new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache()
);
This is already done inside the ``$config->newDefaultAnnotationDriver``, so everything should automatically work if you are using this method. You can verify if everything still works by executing a console command such as schema-validate that loads all metadata into memory.

35
UPGRADE_TO_ALPHA3 Normal file
View File

@@ -0,0 +1,35 @@
# Upgrade from 2.0-ALPHA2 to 2.0-ALPHA3
This section details the changes made to Doctrine 2.0-ALPHA3 to make it easier for you
to upgrade your projects to use this version.
## CLI Changes
The $args variable used in the cli-config.php for configuring the Doctrine CLI has been renamed to $globalArguments.
## Proxy class changes
You are now required to make supply some minimalist configuration with regards to proxy objects. That involves 2 new configuration options. First, the directory where generated proxy classes should be placed needs to be specified. Secondly, you need to configure the namespace used for proxy classes. The following snippet shows an example:
[php]
// step 1: configure directory for proxy classes
// $config instanceof Doctrine\ORM\Configuration
$config->setProxyDir('/path/to/myproject/lib/MyProject/Generated/Proxies');
$config->setProxyNamespace('MyProject\Generated\Proxies');
Note that proxy classes behave exactly like any other classes when it comes to class loading. Therefore you need to make sure the proxy classes can be loaded by some class loader. If you place the generated proxy classes in a namespace and directory under your projects class files, like in the example above, it would be sufficient to register the MyProject namespace on a class loader. Since the proxy classes are contained in that namespace and adhere to the standards for class loading, no additional work is required.
Generating the proxy classes into a namespace within your class library is the recommended setup.
Entities with initialized proxy objects can now be serialized and unserialized properly from within the same application.
For more details refer to the Configuration section of the manual.
## Removed allowPartialObjects configuration option
The allowPartialObjects configuration option together with the `Configuration#getAllowPartialObjects` and `Configuration#setAllowPartialObjects` methods have been removed.
The new behavior is as if the option were set to FALSE all the time, basically disallowing partial objects globally. However, you can still use the `Query::HINT_FORCE_PARTIAL_LOAD` query hint to force a query to return partial objects for optimization purposes.
## Renamed Methods
* Doctrine\ORM\Configuration#getCacheDir() to getProxyDir()
* Doctrine\ORM\Configuration#setCacheDir($dir) to setProxyDir($dir)

36
UPGRADE_TO_ALPHA4 Normal file
View File

@@ -0,0 +1,36 @@
# Upgrade from 2.0-ALPHA3 to 2.0-ALPHA4
## CLI Controller changes
CLI main object changed its name and namespace. Renamed from Doctrine\ORM\Tools\Cli to Doctrine\Common\Cli\CliController.
Doctrine\Common\Cli\CliController now only deals with namespaces. Ready to go, Core, Dbal and Orm are available and you can subscribe new tasks by retrieving the namespace and including new task. Example:
[php]
$cli->getNamespace('Core')->addTask('my-example', '\MyProject\Tools\Cli\Tasks\MyExampleTask');
## CLI Tasks documentation
Tasks have implemented a new way to build documentation. Although it is still possible to define the help manually by extending the basicHelp and extendedHelp, they are now optional.
With new required method AbstractTask::buildDocumentation, its implementation defines the TaskDocumentation instance (accessible through AbstractTask::getDocumentation()), basicHelp and extendedHelp are now not necessary to be implemented.
## Changes in Method Signatures
* A bunch of Methods on both Doctrine\DBAL\Platforms\AbstractPlatform and Doctrine\DBAL\Schema\AbstractSchemaManager
have changed quite significantly by adopting the new Schema instance objects.
## Renamed Methods
* Doctrine\ORM\AbstractQuery::setExpireResultCache() -> expireResultCache()
* Doctrine\ORM\Query::setExpireQueryCache() -> expireQueryCache()
## SchemaTool Changes
* "doctrine schema-tool --drop" now always drops the complete database instead of
only those tables defined by the current database model. The previous method had
problems when foreign keys of orphaned tables pointed to tables that were schedulded
for deletion.
* Use "doctrine schema-tool --update" to get a save incremental update for your
database schema without deleting any unused tables, sequences or foreign keys.
* Use "doctrine schema-tool --complete-update" to do a full incremental update of
your schema.

2
bin/doctrine Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env php
<?php
include('doctrine.php');
include('doctrine.php');

View File

@@ -1,50 +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>.
*/
require_once 'Doctrine/Common/ClassLoader.php';
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');
$classLoader->register();
$classLoader = new \Doctrine\Common\ClassLoader('Symfony');
$classLoader->register();
$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php';
$helperSet = null;
if (file_exists($configFile)) {
if ( ! is_readable($configFile)) {
trigger_error(
'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR
);
}
require $configFile;
foreach ($GLOBALS as $helperSetCandidate) {
if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) {
$helperSet = $helperSetCandidate;
break;
}
}
}
$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet();
\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);

9
bin/doctrine.php Executable file → Normal file
View File

@@ -17,7 +17,14 @@
* <http://www.doctrine-project.org>.
*/
(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php';
require_once 'Doctrine/Common/ClassLoader.php';
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');
$classLoader->register();
$classLoader = new \Doctrine\Common\ClassLoader('Symfony', 'Doctrine');
$classLoader->register();
$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php';
$helperSet = null;

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>
<!--
@@ -19,7 +21,7 @@
-->
<fileset id="bin-scripts" dir="./bin">
<include name="doctrine"/>
<include name="doctrine-pear.php"/>
<include name="doctrine.php"/>
<include name="doctrine.bat"/>
</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}" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" />
<package name="Console" channel="pear.symfony.com" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.com" minimum_version="2.0.0" />
<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-pear.php" />
<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,32 +0,0 @@
{
"name": "doctrine/orm",
"type": "library","version":"2.3.3",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",
"license": "MIT",
"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/dbal": "2.3.*",
"symfony/console": "2.*"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
},
"autoload": {
"psr-0": { "Doctrine\\ORM": "lib/" }
},
"bin": ["bin/doctrine", "bin/doctrine.php"],
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
}
}

View File

@@ -84,69 +84,20 @@
</xs:sequence>
</xs:complexType>
<xs:complexType name="named-native-query">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="query" type="xs:string" use="required"/>
<xs:attribute name="result-class" type="xs:string" />
<xs:attribute name="result-set-mapping" type="xs:string" />
</xs:complexType>
<xs:complexType name="named-native-queries">
<xs:sequence>
<xs:element name="named-native-query" type="orm:named-native-query" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="column-result">
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="field-result">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="column" type="xs:string" />
</xs:complexType>
<xs:complexType name="entity-result">
<xs:sequence>
<xs:element name="field-result" type="orm:field-result" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="entity-class" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="sql-result-set-mapping">
<xs:sequence>
<xs:element name="entity-result" type="orm:entity-result" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="column-result" type="orm:column-result" minOccurs="0" maxOccurs="unbounded" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="sql-result-set-mappings">
<xs:sequence>
<xs:element name="sql-result-set-mapping" type="orm:sql-result-set-mapping" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="entity">
<xs:sequence>
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:element name="indexes" type="orm:indexes" minOccurs="0"/>
<xs:element name="unique-constraints" type="orm:unique-constraints" minOccurs="0"/>
<xs:element name="discriminator-column" type="orm:discriminator-column" minOccurs="0"/>
<xs:element name="discriminator-map" type="orm:discriminator-map" minOccurs="0"/>
<xs:element name="lifecycle-callbacks" type="orm:lifecycle-callbacks" minOccurs="0" maxOccurs="1" />
<xs:element name="named-queries" type="orm:named-queries" minOccurs="0" maxOccurs="1" />
<xs:element name="named-native-queries" type="orm:named-native-queries" minOccurs="0" maxOccurs="1" />
<xs:element name="id" type="orm:id" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="field" type="orm:field" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="one-to-one" type="orm:one-to-one" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="one-to-many" type="orm:one-to-many" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="many-to-one" type="orm:many-to-one" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="many-to-many" type="orm:many-to-many" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="association-overrides" type="orm:association-overrides" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="attribute-overrides" type="orm:attribute-overrides" minOccurs="0" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
@@ -159,23 +110,6 @@
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="option" mixed="true">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="options">
<xs:sequence>
<xs:element name="option" type="orm:option" minOccurs="0" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="mapped-superclass" >
<xs:complexContent>
<xs:extension base="orm:entity">
@@ -209,8 +143,6 @@
<xs:enumeration value="SEQUENCE"/>
<xs:enumeration value="IDENTITY"/>
<xs:enumeration value="AUTO"/>
<xs:enumeration value="UUID"/>
<xs:enumeration value="CUSTOM" />
</xs:restriction>
</xs:simpleType>
@@ -218,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>
@@ -226,13 +158,12 @@
<xs:restriction base="xs:token">
<xs:enumeration value="EAGER"/>
<xs:enumeration value="LAZY"/>
<xs:enumeration value="EXTRA_LAZY"/>
<xs:enumeration value="EXTRALAZY"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="field">
<xs:sequence>
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
@@ -253,10 +184,9 @@
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN"/>
<xs:attribute name="type" type="xs:NMTOKEN" use="required" />
<xs:attribute name="field-name" type="xs:NMTOKEN" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
@@ -323,14 +253,12 @@
<xs:sequence>
<xs:element name="generator" type="orm:generator" minOccurs="0" />
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="custom-id-generator" type="orm:custom-id-generator" minOccurs="0" maxOccurs="1" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="association-key" type="xs:boolean" default="false" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
@@ -344,13 +272,6 @@
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="custom-id-generator">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="class" type="xs:NMTOKEN" use="required" />
</xs:complexType>
<xs:complexType name="inverse-join-columns">
<xs:sequence>
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
@@ -429,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>
@@ -485,35 +405,4 @@
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="association-overrides">
<xs:sequence>
<xs:element name="association-override" type="orm:association-override" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="association-override">
<xs:sequence>
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
<xs:element name="join-columns" type="orm:join-columns" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
</xs:complexType>
<xs:complexType name="attribute-overrides">
<xs:sequence>
<xs:element name="attribute-override" type="orm:attribute-override" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="attribute-override">
<xs:sequence>
<xs:element name="field" type="orm:field" minOccurs="1" />
<xs:any minOccurs="1" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
</xs:complexType>
</xs:schema>

View File

@@ -13,25 +13,22 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Query\QueryException;
use Doctrine\DBAL\Types\Type,
Doctrine\ORM\Query\QueryException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
@@ -64,9 +61,14 @@ abstract class AbstractQuery
const HYDRATE_SIMPLEOBJECT = 5;
/**
* @var \Doctrine\Common\Collections\ArrayCollection The parameter map of this query.
* @var array The parameter map of this query.
*/
protected $parameters;
protected $_params = array();
/**
* @var array The parameter type map of this query.
*/
protected $_paramTypes = array();
/**
* @var ResultSetMapping The user-specified ResultSetMapping to use.
@@ -74,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;
@@ -89,9 +91,23 @@ 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.
@@ -99,34 +115,24 @@ abstract class AbstractQuery
protected $_expireResultCache = false;
/**
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
* @var int Result Cache lifetime.
*/
protected $_hydrationCacheProfile;
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)
{
$this->_em = $em;
$this->parameters = new ArrayCollection();
}
/**
* Gets the SQL query that corresponds to this query object.
* The returned SQL syntax depends on the connection driver that is used
* by this query object at the time of this method call.
*
* @return string SQL query
*/
abstract public function getSQL();
/**
* Retrieves the associated EntityManager of this Query instance.
*
* @return \Doctrine\ORM\EntityManager
* @return Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
@@ -142,68 +148,62 @@ abstract class AbstractQuery
*/
public function free()
{
$this->parameters = new ArrayCollection();
$this->_params = array();
$this->_paramTypes = array();
$this->_hints = array();
}
/**
* Get all defined parameters.
*
* @return \Doctrine\Common\Collections\ArrayCollection The defined query parameters.
* @return array The defined query parameters.
*/
public function getParameters()
{
return $this->parameters;
return $this->_params;
}
/**
* Get all defined parameter types.
*
* @return array The defined query parameter types.
*/
public function getParameterTypes()
{
return $this->_paramTypes;
}
/**
* Gets a query parameter.
*
* @param mixed $key The key (index or name) of the bound parameter.
*
* @return mixed The value of the bound parameter.
*/
public function getParameter($key)
{
$filteredParameters = $this->parameters->filter(
function ($parameter) use ($key)
{
// Must not be identical because of string to integer conversion
return ($key == $parameter->getName());
}
);
return count($filteredParameters) ? $filteredParameters->first() : null;
return isset($this->_params[$key]) ? $this->_params[$key] : null;
}
/**
* Sets a collection of query parameters.
* Gets a query parameter type.
*
* @param \Doctrine\Common\Collections\ArrayCollection|array $parameters
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @param mixed $key The key (index or name) of the bound parameter.
* @return mixed The parameter type of the bound parameter.
*/
public function setParameters($parameters)
public function getParameterType($key)
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
$parameterCollection = new ArrayCollection();
foreach ($parameters as $key => $value) {
$parameter = new Query\Parameter($key, $value);
$parameterCollection->add($parameter);
}
$parameters = $parameterCollection;
}
$this->parameters = $parameters;
return $this;
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
}
/**
* Gets the SQL query that corresponds to this query object.
* The returned SQL syntax depends on the connection driver that is used
* by this query object at the time of this method call.
*
* @return string SQL query
*/
abstract public function getSQL();
/**
* Sets a query parameter.
*
@@ -212,191 +212,81 @@ 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)
{
$filteredParameters = $this->parameters->filter(
function ($parameter) use ($key)
{
// Must not be identical because of string to integer conversion
return ($key == $parameter->getName());
}
);
if (count($filteredParameters)) {
$parameter = $filteredParameters->first();
$parameter->setValue($value, $type);
return $this;
if ($type === null) {
$type = Query\ParameterTypeInferer::inferType($value);
}
$parameter = new Query\Parameter($key, $value, $type);
$this->parameters->add($parameter);
$this->_paramTypes[$key] = $type;
$this->_params[$key] = $value;
return $this;
}
/**
* Process an individual parameter value
* Sets a collection of query parameters.
*
* @param mixed $value
* @return array
* @param array $params
* @param array $types
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function processParameterValue($value)
public function setParameters(array $params, array $types = array())
{
switch (true) {
case is_array($value):
foreach ($value as $key => $paramValue) {
$paramValue = $this->processParameterValue($paramValue);
$value[$key] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
}
return $value;
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value)):
return $this->convertObjectParameterToScalarValue($value);
default:
return $value;
foreach ($params as $key => $value) {
if (isset($types[$key])) {
$this->setParameter($key, $value, $types[$key]);
} else {
$this->setParameter($key, $value);
}
}
}
private 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."
);
}
$values = ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED)
? $this->_em->getUnitOfWork()->getEntityIdentifier($value)
: $class->getIdentifierValues($value);
$value = $values[$class->getSingleIdentifierFieldName()];
if (null === $value) {
throw new \InvalidArgumentException(
"Binding entities to query parameters only allowed for entities that have an identifier."
);
}
return $value;
return $this;
}
/**
* 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;
}
/**
* Set a cache profile for hydration caching.
* Defines a cache driver to be used for caching result sets.
*
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* Important: Hydration caching does NOT register entities in the
* UnitOfWork when retrieved from the cache. Never use result cached
* entities for requests that also flush the EntityManager. If you want
* some form of caching with UnitOfWork registration you should use
* {@see AbstractQuery::setResultCacheProfile()}.
*
* @example
* $lifetime = 100;
* $resultKey = "abc";
* $query->setHydrationCacheProfile(new QueryCacheProfile());
* $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey));
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
* @return \Doctrine\ORM\AbstractQuery
*/
public function setHydrationCacheProfile(QueryCacheProfile $profile = null)
{
if ( ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_hydrationCacheProfile = $profile;
return $this;
}
/**
* @return \Doctrine\DBAL\Cache\QueryCacheProfile
*/
public function getHydrationCacheProfile()
{
return $this->_hydrationCacheProfile;
}
/**
* Set a cache profile for the result cache.
*
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
* @return \Doctrine\ORM\AbstractQuery
*/
public function setResultCacheProfile(QueryCacheProfile $profile = null)
{
if ( ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_queryCacheProfile = $profile;
return $this;
}
/**
* Defines a cache driver to be used for caching result sets and implictly enables caching.
*
* @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();
}
/**
@@ -404,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;
}
@@ -473,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.
*
@@ -498,7 +375,6 @@ abstract class AbstractQuery
}
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
return $this;
}
@@ -507,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;
}
@@ -529,37 +404,37 @@ abstract class AbstractQuery
/**
* Gets the list of results for the query.
*
* Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
* Alias for execute(array(), $hydrationMode = HYDRATE_OBJECT).
*
* @return array
*/
public function getResult($hydrationMode = self::HYDRATE_OBJECT)
{
return $this->execute(null, $hydrationMode);
return $this->execute(array(), $hydrationMode);
}
/**
* Gets the array of results for the query.
*
* Alias for execute(null, HYDRATE_ARRAY).
* Alias for execute(array(), HYDRATE_ARRAY).
*
* @return array
*/
public function getArrayResult()
{
return $this->execute(null, self::HYDRATE_ARRAY);
return $this->execute(array(), self::HYDRATE_ARRAY);
}
/**
* Gets the scalar results for the query.
*
* Alias for execute(null, HYDRATE_SCALAR).
* Alias for execute(array(), HYDRATE_SCALAR).
*
* @return array
*/
public function getScalarResult()
{
return $this->execute(null, self::HYDRATE_SCALAR);
return $this->execute(array(), self::HYDRATE_SCALAR);
}
/**
@@ -571,21 +446,20 @@ abstract class AbstractQuery
*/
public function getOneOrNullResult($hydrationMode = null)
{
$result = $this->execute(null, $hydrationMode);
$result = $this->execute(array(), $hydrationMode);
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
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;
}
/**
@@ -603,21 +477,20 @@ abstract class AbstractQuery
*/
public function getSingleResult($hydrationMode = null)
{
$result = $this->execute(null, $hydrationMode);
$result = $this->execute(array(), $hydrationMode);
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
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;
}
/**
@@ -638,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;
}
@@ -660,7 +532,7 @@ abstract class AbstractQuery
/**
* Return the key value map of query hints that are currently set.
*
*
* @return array
*/
public function getHints()
@@ -672,18 +544,18 @@ abstract class AbstractQuery
* Executes the query and returns an IterableResult that can be used to incrementally
* iterate over the result.
*
* @param \Doctrine\Common\Collections\ArrayCollection|array $parameters The query parameters.
* @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($parameters = null, $hydrationMode = null)
public function iterate(array $params = array(), $hydrationMode = null)
{
if ($hydrationMode !== null) {
$this->setHydrationMode($hydrationMode);
}
if ( ! empty($parameters)) {
$this->setParameters($parameters);
if ($params) {
$this->setParameters($params);
}
$stmt = $this->_doExecute();
@@ -696,59 +568,65 @@ abstract class AbstractQuery
/**
* Executes the query.
*
* @param \Doctrine\Common\Collections\ArrayCollection|array $parameters Query parameters.
* @param array $params Any additional query parameters.
* @param integer $hydrationMode Processing mode to be used during the hydration process.
* @return mixed
*/
public function execute($parameters = null, $hydrationMode = null)
public function execute($params = array(), $hydrationMode = null)
{
if ($hydrationMode !== null) {
$this->setHydrationMode($hydrationMode);
}
if ( ! empty($parameters)) {
$this->setParameters($parameters);
if ($params) {
$this->setParameters($params);
}
$setCacheEntry = function() {};
// Check result cache
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
list($key, $hash) = $this->getResultCacheId();
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($hash);
if ($this->_hydrationCacheProfile !== null) {
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
if ($cached === false || !isset($cached[$key])) {
// Cache miss.
$stmt = $this->_doExecute();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
$result = $cache->fetch($cacheKey);
$result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
if (isset($result[$realCacheKey])) {
return $result[$realCacheKey];
$cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL);
return $result;
} else {
// Cache hit.
return $cached[$key];
}
if ( ! $result) {
$result = array();
}
$setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
};
}
$stmt = $this->_doExecute();
if (is_numeric($stmt)) {
$setCacheEntry($stmt);
return $stmt;
}
$data = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
}
$setCacheEntry($data);
return $data;
/**
* Set the result cache id to use to store the result set cache entry.
* If this is not explicitely set by the developer then a hash is automatically
* generated for you.
*
* @param string $id
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheId($id)
{
$this->_resultCacheId = $id;
return $this;
}
/**
@@ -758,56 +636,38 @@ abstract class AbstractQuery
*
* @return array ($key, $hash)
*/
protected function getHydrationCacheId()
protected function getResultCacheId()
{
$parameters = array();
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;
}
}
foreach ($this->getParameters() as $parameter) {
$parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue());
$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));
}
$sql = $this->getSQL();
$queryCacheProfile = $this->getHydrationCacheProfile();
$hints = $this->getHints();
$hints['hydrationMode'] = $this->getHydrationMode();
ksort($hints);
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $hints);
}
/**
* Set the result cache id to use to store the result set cache entry.
* If this is not explicitly set by the developer then a hash is automatically
* generated for you.
*
* @param string $id
* @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());
return $this;
}
/**
* Get the result cache id to use to store the result set cache entry if set.
*
* @deprecated
* @return string
*/
public function getResultCacheId()
{
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null;
}
/**
* 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();
@@ -818,8 +678,8 @@ abstract class AbstractQuery
*/
public function __clone()
{
$this->parameters = new ArrayCollection();
$this->_params = array();
$this->_paramTypes = array();
$this->_hints = array();
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -23,14 +23,8 @@ use Doctrine\Common\Cache\Cache,
Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationRegistry,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\Common\Persistence\Mapping\Driver\MappingDriver,
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
Doctrine\ORM\Mapping\QuoteStrategy,
Doctrine\ORM\Mapping\DefaultQuoteStrategy,
Doctrine\ORM\Mapping\NamingStrategy,
Doctrine\ORM\Mapping\DefaultNamingStrategy,
Doctrine\Common\Annotations\SimpleAnnotationReader,
Doctrine\Common\Annotations\CachedReader;
Doctrine\ORM\Mapping\Driver\Driver,
Doctrine\ORM\Mapping\Driver\AnnotationDriver;
/**
* Configuration container for all configuration options of Doctrine.
@@ -62,9 +56,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getProxyDir()
{
return isset($this->_attributes['proxyDir'])
? $this->_attributes['proxyDir']
: null;
return isset($this->_attributes['proxyDir']) ?
$this->_attributes['proxyDir'] : null;
}
/**
@@ -75,9 +68,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getAutoGenerateProxyClasses()
{
return isset($this->_attributes['autoGenerateProxyClasses'])
? $this->_attributes['autoGenerateProxyClasses']
: true;
return isset($this->_attributes['autoGenerateProxyClasses']) ?
$this->_attributes['autoGenerateProxyClasses'] : true;
}
/**
@@ -93,19 +85,18 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the namespace where proxy classes reside.
*
*
* @return string
*/
public function getProxyNamespace()
{
return isset($this->_attributes['proxyNamespace'])
? $this->_attributes['proxyNamespace']
: null;
return isset($this->_attributes['proxyNamespace']) ?
$this->_attributes['proxyNamespace'] : null;
}
/**
* Sets the namespace where proxy classes reside.
*
*
* @param string $ns
*/
public function setProxyNamespace($ns)
@@ -116,40 +107,45 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Sets the cache driver implementation that is used for metadata caching.
*
* @param MappingDriver $driverImpl
* @param Driver $driverImpl
* @todo Force parameter to be a Closure to ensure lazy evaluation
* (as soon as a metadata cache is in effect, the driver never needs to initialize).
*/
public function setMetadataDriverImpl(MappingDriver $driverImpl)
public function setMetadataDriverImpl(Driver $driverImpl)
{
$this->_attributes['metadataDriverImpl'] = $driverImpl;
}
/**
* Add a new default annotation driver with a correctly configured annotation reader. If $useSimpleAnnotationReader
* is true, the notation `@Entity` will work, otherwise, the notation `@ORM\Entity` will be supported.
*
* Add a new default annotation driver with a correctly configured annotation reader.
*
* @param array $paths
* @param bool $useSimpleAnnotationReader
* @return AnnotationDriver
* @return Mapping\Driver\AnnotationDriver
*/
public function newDefaultAnnotationDriver($paths = array(), $useSimpleAnnotationReader = true)
public function newDefaultAnnotationDriver($paths = array())
{
AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php');
if ($useSimpleAnnotationReader) {
if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
// Register the ORM Annotations in the AnnotationRegistry
$reader = new SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$cachedReader = new CachedReader($reader, new ArrayCache());
return new AnnotationDriver($cachedReader, (array) $paths);
AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php');
$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);
$reader->setEnableParsePhpImports(false);
$reader = new \Doctrine\Common\Annotations\CachedReader(
new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache()
);
} else {
$reader = new AnnotationReader();
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
}
return new AnnotationDriver(
new CachedReader(new AnnotationReader(), new ArrayCache()),
(array) $paths
);
return new AnnotationDriver($reader, (array)$paths);
}
/**
@@ -166,9 +162,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Resolves a registered namespace alias to the full namespace.
*
* @param string $entityNamespaceAlias
* @throws ORMException
* @param string $entityNamespaceAlias
* @return string
* @throws MappingException
*/
public function getEntityNamespace($entityNamespaceAlias)
{
@@ -182,16 +178,17 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Set the entity alias map
*
* @param array $entityNamespaces
* @param array $entityAliasMap
* @return void
*/
public function setEntityNamespaces(array $entityNamespaces)
{
$this->_attributes['entityNamespaces'] = $entityNamespaces;
}
/**
* Retrieves the list of registered entity namespace aliases.
*
*
* @return array
*/
public function getEntityNamespaces()
@@ -203,13 +200,33 @@ class Configuration extends \Doctrine\DBAL\Configuration
* Gets the cache driver implementation that is used for the mapping metadata.
*
* @throws ORMException
* @return MappingDriver
* @return Mapping\Driver\Driver
*/
public function getMetadataDriverImpl()
{
return isset($this->_attributes['metadataDriverImpl'])
? $this->_attributes['metadataDriverImpl']
: null;
return isset($this->_attributes['metadataDriverImpl']) ?
$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;
}
/**
@@ -219,9 +236,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getQueryCacheImpl()
{
return isset($this->_attributes['queryCacheImpl'])
? $this->_attributes['queryCacheImpl']
: null;
return isset($this->_attributes['queryCacheImpl']) ?
$this->_attributes['queryCacheImpl'] : null;
}
/**
@@ -234,28 +250,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['queryCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for the hydration cache (SQL cache).
*
* @return \Doctrine\Common\Cache\Cache
*/
public function getHydrationCacheImpl()
{
return isset($this->_attributes['hydrationCacheImpl'])
? $this->_attributes['hydrationCacheImpl']
: null;
}
/**
* Sets the cache driver implementation that is used for the hydration cache (SQL cache).
*
* @param \Doctrine\Common\Cache\Cache $cacheImpl
*/
public function setHydrationCacheImpl(Cache $cacheImpl)
{
$this->_attributes['hydrationCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for metadata caching.
*
@@ -263,9 +257,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getMetadataCacheImpl()
{
return isset($this->_attributes['metadataCacheImpl'])
? $this->_attributes['metadataCacheImpl']
: null;
return isset($this->_attributes['metadataCacheImpl']) ?
$this->_attributes['metadataCacheImpl'] : null;
}
/**
@@ -293,7 +286,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
* Gets a previously registered named DQL query.
*
* @param string $name The name of the query.
* @throws ORMException
* @return string The DQL query.
*/
public function getNamedQuery($name)
@@ -301,16 +293,15 @@ class Configuration extends \Doctrine\DBAL\Configuration
if ( ! isset($this->_attributes['namedQueries'][$name])) {
throw ORMException::namedQueryNotFound($name);
}
return $this->_attributes['namedQueries'][$name];
}
/**
* Adds a named native query to the configuration.
*
* @param string $name The name of the query.
* @param string $sql The native SQL query string.
* @param Query\ResultSetMapping $rsm The ResultSetMapping used for the results of the SQL query.
* @param string $name The name of the query.
* @param string $sql The native SQL query string.
* @param ResultSetMapping $rsm The ResultSetMapping used for the results of the SQL query.
*/
public function addNamedNativeQuery($name, $sql, Query\ResultSetMapping $rsm)
{
@@ -320,17 +311,15 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the components of a previously registered named native query.
*
* @param string $name The name of the query.
* @throws ORMException
* @return array A tuple with the first element being the SQL string and the second
* element being the ResultSetMapping.
* @param string $name The name of the query.
* @return array A tuple with the first element being the SQL string and the second
* element being the ResultSetMapping.
*/
public function getNamedNativeQuery($name)
{
if ( ! isset($this->_attributes['namedNativeQueries'][$name])) {
throw ORMException::namedNativeQueryNotFound($name);
}
return $this->_attributes['namedNativeQueries'][$name];
}
@@ -343,14 +332,12 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function ensureProductionSettings()
{
if ( ! $this->getQueryCacheImpl()) {
if ( !$this->getQueryCacheImpl()) {
throw ORMException::queryCacheNotConfigured();
}
if ( ! $this->getMetadataCacheImpl()) {
if ( !$this->getMetadataCacheImpl()) {
throw ORMException::metadataCacheNotConfigured();
}
if ($this->getAutoGenerateProxyClasses()) {
throw ORMException::proxyClassesAlwaysRegenerating();
}
@@ -365,30 +352,23 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name
* @param string $className
* @throws ORMException
*/
public function addCustomStringFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customStringFunctions'][strtolower($name)] = $className;
}
/**
* Gets the implementation class name of a registered custom string DQL function.
*
*
* @param string $name
* @return string
*/
public function getCustomStringFunction($name)
{
$name = strtolower($name);
return isset($this->_attributes['customStringFunctions'][$name])
? $this->_attributes['customStringFunctions'][$name]
: null;
return isset($this->_attributes['customStringFunctions'][$name]) ?
$this->_attributes['customStringFunctions'][$name] : null;
}
/**
@@ -403,9 +383,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function setCustomStringFunctions(array $functions)
{
foreach ($functions as $name => $className) {
$this->addCustomStringFunction($name, $className);
}
$this->_attributes['customStringFunctions'] = array_change_key_case($functions);
}
/**
@@ -417,30 +395,23 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name
* @param string $className
* @throws ORMException
*/
public function addCustomNumericFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customNumericFunctions'][strtolower($name)] = $className;
}
/**
* Gets the implementation class name of a registered custom numeric DQL function.
*
*
* @param string $name
* @return string
*/
public function getCustomNumericFunction($name)
{
$name = strtolower($name);
return isset($this->_attributes['customNumericFunctions'][$name])
? $this->_attributes['customNumericFunctions'][$name]
: null;
return isset($this->_attributes['customNumericFunctions'][$name]) ?
$this->_attributes['customNumericFunctions'][$name] : null;
}
/**
@@ -455,9 +426,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function setCustomNumericFunctions(array $functions)
{
foreach ($functions as $name => $className) {
$this->addCustomNumericFunction($name, $className);
}
$this->_attributes['customNumericFunctions'] = array_change_key_case($functions);
}
/**
@@ -469,30 +438,23 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name
* @param string $className
* @throws ORMException
*/
public function addCustomDatetimeFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customDatetimeFunctions'][strtolower($name)] = $className;
}
/**
* Gets the implementation class name of a registered custom date/time DQL function.
*
*
* @param string $name
* @return string
*/
public function getCustomDatetimeFunction($name)
{
$name = strtolower($name);
return isset($this->_attributes['customDatetimeFunctions'][$name])
? $this->_attributes['customDatetimeFunctions'][$name]
: null;
return isset($this->_attributes['customDatetimeFunctions'][$name]) ?
$this->_attributes['customDatetimeFunctions'][$name] : null;
}
/**
@@ -507,23 +469,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function setCustomDatetimeFunctions(array $functions)
{
foreach ($functions as $name => $className) {
$this->addCustomDatetimeFunction($name, $className);
}
}
/**
* Set the custom hydrator modes in one pass.
*
* @param array An array of ($modeName => $hydrator)
*/
public function setCustomHydrationModes($modes)
{
$this->_attributes['customHydrationModes'] = array();
foreach ($modes as $modeName => $hydrator) {
$this->addCustomHydrationMode($modeName, $hydrator);
}
$this->_attributes['customDatetimeFunctions'] = array_change_key_case($functions);
}
/**
@@ -534,9 +480,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getCustomHydrationMode($modeName)
{
return isset($this->_attributes['customHydrationModes'][$modeName])
? $this->_attributes['customHydrationModes'][$modeName]
: null;
return isset($this->_attributes['customHydrationModes'][$modeName]) ?
$this->_attributes['customHydrationModes'][$modeName] : null;
}
/**
@@ -552,8 +497,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Set a class metadata factory.
*
* @param string $cmfName
*
* @param string $cmf
*/
public function setClassMetadataFactoryName($cmfName)
{
@@ -565,119 +510,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getClassMetadataFactoryName()
{
if ( ! isset($this->_attributes['classMetadataFactoryName'])) {
if (!isset($this->_attributes['classMetadataFactoryName'])) {
$this->_attributes['classMetadataFactoryName'] = 'Doctrine\ORM\Mapping\ClassMetadataFactory';
}
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\Common\Persistence\ObjectRepository
*/
public function setDefaultRepositoryClassName($className)
{
$reflectionClass = new \ReflectionClass($className);
if ( ! $reflectionClass->implementsInterface('Doctrine\Common\Persistence\ObjectRepository')) {
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';
}
/**
* Set naming strategy.
*
* @since 2.3
* @param NamingStrategy $namingStrategy
*/
public function setNamingStrategy(NamingStrategy $namingStrategy)
{
$this->_attributes['namingStrategy'] = $namingStrategy;
}
/**
* Get naming strategy..
*
* @since 2.3
* @return NamingStrategy
*/
public function getNamingStrategy()
{
if ( ! isset($this->_attributes['namingStrategy'])) {
$this->_attributes['namingStrategy'] = new DefaultNamingStrategy();
}
return $this->_attributes['namingStrategy'];
}
/**
* Set quote strategy.
*
* @since 2.3
* @param Doctrine\ORM\Mapping\QuoteStrategy $quoteStrategy
*/
public function setQuoteStrategy(QuoteStrategy $quoteStrategy)
{
$this->_attributes['quoteStrategy'] = $quoteStrategy;
}
/**
* Get quote strategy.
*
* @since 2.3
* @return Doctrine\ORM\Mapping\QuoteStrategy
*/
public function getQuoteStrategy()
{
if ( ! isset($this->_attributes['quoteStrategy'])) {
$this->_attributes['quoteStrategy'] = new DefaultQuoteStrategy();
}
return $this->_attributes['quoteStrategy'];
}
}
}

View File

@@ -13,13 +13,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
use Exception,
use Closure, Exception,
Doctrine\Common\EventManager,
Doctrine\Common\Persistence\ObjectManager,
Doctrine\DBAL\Connection,
@@ -27,8 +27,7 @@ use 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,46 +110,36 @@ 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)
{
$this->conn = $conn;
$this->config = $config;
$this->conn = $conn;
$this->config = $config;
$this->eventManager = $eventManager;
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
$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->unitOfWork = new UnitOfWork($this);
$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()
{
@@ -160,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()
{
@@ -179,19 +168,20 @@ 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;
}
/**
* Starts a transaction on the underlying database connection.
*
* @deprecated Use {@link getConnection}.beginTransaction().
*/
public function beginTransaction()
{
@@ -208,34 +198,31 @@ class EntityManager implements ObjectManager
* If an exception occurs during execution of the function or flushing or transaction commit,
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
*
* @param callable $func The function to execute transactionally.
* @return mixed Returns the non-empty value returned from the closure or true instead
* @param Closure $func The function to execute transactionally.
*/
public function transactional($func)
public function transactional(Closure $func)
{
if (!is_callable($func)) {
throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"');
}
$this->conn->beginTransaction();
try {
$return = call_user_func($func, $this);
$return = $func($this);
$this->flush();
$this->conn->commit();
return $return ?: true;
} catch (Exception $e) {
$this->close();
$this->conn->rollback();
throw $e;
}
}
/**
* Commits a transaction on the underlying database connection.
*
* @deprecated Use {@link getConnection}.commit().
*/
public function commit()
{
@@ -244,6 +231,8 @@ class EntityManager implements ObjectManager
/**
* Performs a rollback on the underlying database connection.
*
* @deprecated Use {@link getConnection}.rollback().
*/
public function rollback()
{
@@ -255,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)
@@ -271,17 +260,15 @@ class EntityManager implements ObjectManager
/**
* Creates a new Query object.
*
* @param string $dql The DQL string.
* @return \Doctrine\ORM\Query
* @param string The DQL string.
* @return Doctrine\ORM\Query
*/
public function createQuery($dql = "")
{
$query = new Query($this);
if ( ! empty($dql)) {
$query->setDql($dql);
}
return $query;
}
@@ -289,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)
{
@@ -306,10 +293,8 @@ class EntityManager implements ObjectManager
public function createNativeQuery($sql, ResultSetMapping $rsm)
{
$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,95 +325,29 @@ 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();
}
/**
* Finds an Entity by its identifier.
*
* @param string $entityName
* @param mixed $id
* @param integer $lockMode
* @param integer $lockVersion
* This is just a convenient shortcut for getRepository($entityName)->find($id).
*
* @param string $entityName
* @param mixed $identifier
* @param int $lockMode
* @param int $lockVersion
* @return object
*/
public function find($entityName, $id, $lockMode = LockMode::NONE, $lockVersion = null)
public function find($entityName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null)
{
$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];
}
$unitOfWork = $this->getUnitOfWork();
// Check identity map first
if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
if ( ! ($entity instanceof $class->name)) {
return null;
}
switch ($lockMode) {
case LockMode::OPTIMISTIC:
$this->lock($entity, $lockMode, $lockVersion);
break;
case LockMode::PESSIMISTIC_READ:
case LockMode::PESSIMISTIC_WRITE:
$persister = $unitOfWork->getEntityPersister($class->name);
$persister->refresh($sortedId, $entity, $lockMode);
break;
}
return $entity; // Hit!
}
$persister = $unitOfWork->getEntityPersister($class->name);
switch ($lockMode) {
case LockMode::NONE:
return $persister->load($sortedId);
case LockMode::OPTIMISTIC:
if ( ! $class->isVersioned) {
throw OptimisticLockException::notVersioned($class->name);
}
$entity = $persister->load($sortedId);
$unitOfWork->lock($entity, $lockMode, $lockVersion);
return $entity;
default:
if ( ! $this->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $persister->load($sortedId, null, null, array(), $lockMode);
}
return $this->getRepository($entityName)->find($identifier, $lockMode, $lockVersion);
}
/**
@@ -437,44 +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)) !== false) {
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;
}
@@ -502,20 +403,16 @@ class EntityManager implements ObjectManager
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
// Check identity map first, if its already in there just return it.
if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) {
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);
}
$entity = $class->newInstance();
$class->setIdentifierValues($entity, $identifier);
$this->unitOfWork->registerManaged($entity, $identifier, array());
$this->unitOfWork->markReadOnly($entity);
return $entity;
}
@@ -524,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.");
}
}
/**
@@ -539,7 +441,6 @@ class EntityManager implements ObjectManager
public function close()
{
$this->clear();
$this->closed = true;
}
@@ -548,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.
*
@@ -557,11 +458,9 @@ class EntityManager implements ObjectManager
public function persist($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()' , $entity);
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->persist($entity);
}
@@ -576,11 +475,9 @@ class EntityManager implements ObjectManager
public function remove($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()' , $entity);
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->remove($entity);
}
@@ -593,11 +490,9 @@ class EntityManager implements ObjectManager
public function refresh($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()' , $entity);
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->refresh($entity);
}
@@ -613,9 +508,8 @@ class EntityManager implements ObjectManager
public function detach($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()' , $entity);
throw new \InvalidArgumentException(gettype($entity));
}
$this->unitOfWork->detach($entity);
}
@@ -630,11 +524,9 @@ class EntityManager implements ObjectManager
public function merge($entity)
{
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()' , $entity);
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
return $this->unitOfWork->merge($entity);
}
@@ -674,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;
@@ -701,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()
{
@@ -719,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()
{
@@ -740,7 +631,7 @@ class EntityManager implements ObjectManager
/**
* Check if the Entity manager is open or closed.
*
*
* @return bool
*/
public function isOpen()
@@ -751,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()
{
@@ -765,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)
{
@@ -780,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)) !== null) {
return new $class($this);
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
$hydrator = new $class($this);
break;
}
throw ORMException::invalidHydrationMode($hydrationMode);
}
throw ORMException::invalidHydrationMode($hydrationMode);
return $hydrator;
}
/**
@@ -819,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.
*
@@ -842,61 +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

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -31,4 +31,4 @@ class EntityNotFoundException extends ORMException
{
parent::__construct('Entity was not found.');
}
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -22,11 +22,6 @@ namespace Doctrine\ORM;
use Doctrine\DBAL\LockMode;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\ExpressionBuilder;
/**
* An EntityRepository serves as a repository for entities with generic as well as
* business specific methods for retrieving entities.
@@ -40,7 +35,7 @@ use Doctrine\Common\Collections\ExpressionBuilder;
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class EntityRepository implements ObjectRepository, Selectable
class EntityRepository implements ObjectRepository
{
/**
* @var string
@@ -53,7 +48,7 @@ class EntityRepository implements ObjectRepository, Selectable
protected $_em;
/**
* @var \Doctrine\ORM\Mapping\ClassMetadata
* @var Doctrine\ORM\Mapping\ClassMetadata
*/
protected $_class;
@@ -66,8 +61,8 @@ class EntityRepository implements ObjectRepository, Selectable
public function __construct($em, Mapping\ClassMetadata $class)
{
$this->_entityName = $class->name;
$this->_em = $em;
$this->_class = $class;
$this->_em = $em;
$this->_class = $class;
}
/**
@@ -94,21 +89,6 @@ class EntityRepository implements ObjectRepository, Selectable
return $this->_em->createQuery($this->_class->getNamedQuery($queryName));
}
/**
* Creates a native SQL query.
*
* @param string $queryName
* @return NativeQuery
*/
public function createNativeNamedQuery($queryName)
{
$queryMapping = $this->_class->getNamedNativeQuery($queryName);
$rsm = new Query\ResultSetMappingBuilder($this->_em);
$rsm->addNamedNativeQueryMapping($this->_class, $queryMapping);
return $this->_em->createNativeQuery($queryMapping['query'], $rsm);
}
/**
* Clears the repository, causing all managed entities to become detached.
*/
@@ -120,15 +100,50 @@ class EntityRepository implements ObjectRepository, Selectable
/**
* Finds an entity by its primary key / identifier.
*
* @param mixed $id The identifier.
* @param integer $lockMode
* @param integer $lockVersion
*
* @param $id The identifier.
* @param int $lockMode
* @param int $lockVersion
* @return object The entity.
*/
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
return $this->_em->find($this->_entityName, $id, $lockMode, $lockVersion);
// Check identity map first
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
if (!($entity instanceof $this->_class->name)) {
return null;
}
if ($lockMode != LockMode::NONE) {
$this->_em->lock($entity, $lockMode, $lockVersion);
}
return $entity; // Hit!
}
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);
}
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);
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
return $entity;
} else {
if (!$this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
}
}
/**
@@ -152,23 +167,18 @@ class EntityRepository implements ObjectRepository, Selectable
*/
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
{
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
return $persister->loadAll($criteria, $orderBy, $limit, $offset);
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->loadAll($criteria, $orderBy, $limit, $offset);
}
/**
* Finds a single entity by a set of criteria.
*
* @param array $criteria
* @param array|null $orderBy
* @return object
*/
public function findOneBy(array $criteria, array $orderBy = null)
public function findOneBy(array $criteria)
{
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
return $persister->load($criteria, null, null, array(), 0, 1, $orderBy);
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria);
}
/**
@@ -181,50 +191,31 @@ class EntityRepository implements ObjectRepository, Selectable
*/
public function __call($method, $arguments)
{
switch (true) {
case (0 === strpos($method, 'findBy')):
$by = substr($method, 6);
$method = 'findBy';
break;
case (0 === strpos($method, 'findOneBy')):
$by = substr($method, 9);
$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)) {
switch (count($arguments)) {
case 1:
return $this->$method(array($fieldName => $arguments[0]));
case 2:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1]);
case 3:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2]);
case 4:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2], $arguments[3]);
default:
// Do nothing
}
return $this->$method(array($fieldName => $arguments[0]));
} else {
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/**
@@ -235,14 +226,6 @@ class EntityRepository implements ObjectRepository, Selectable
return $this->_entityName;
}
/**
* @return string
*/
public function getClassName()
{
return $this->getEntityName();
}
/**
* @return EntityManager
*/
@@ -258,20 +241,4 @@ class EntityRepository implements ObjectRepository, Selectable
{
return $this->_class;
}
/**
* Select all elements from a selectable that match the expression and
* return a new collection containing these elements.
*
* @param \Doctrine\Common\Collections\Criteria $criteria
*
* @return \Doctrine\Common\Collections\Collection
*/
public function matching(Criteria $criteria)
{
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
return new ArrayCollection($persister->loadCriteria($criteria));
}
}
}

View File

@@ -13,65 +13,48 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* 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\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;
}
/**
* Retrieve 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 MIT license. 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

@@ -13,9 +13,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* 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

@@ -1,5 +1,7 @@
<?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
@@ -13,72 +15,64 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
*/
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,58 +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 MIT license. 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,50 +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 MIT license. 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
* @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,21 +1,4 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
@@ -25,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];
}
/**
@@ -92,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

@@ -1,5 +1,7 @@
<?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
@@ -13,7 +15,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -33,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';
@@ -89,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.
@@ -143,4 +127,4 @@ final class Events
* @var string
*/
const onClear = 'onClear';
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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.
*
@@ -45,4 +45,4 @@ abstract class AbstractIdGenerator
{
return false;
}
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -42,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

@@ -1,66 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
/**
* Id generator that obtains IDs from special "identity" columns. These are columns
* that automatically get a database-generated, auto-incremented identifier on INSERT.
* This generator obtains the last insert id after such an insert.
*/
class BigIntegerIdentityGenerator extends AbstractIdGenerator
{
/**
* The name of the sequence to pass to lastInsertId(), if any.
*
* @var string
*/
private $sequenceName;
/**
* Constructor.
*
* @param string|null $seqName The name of the sequence to pass to lastInsertId()
* to obtain the last generated identifier within the current
* database session/connection, if any.
*/
public function __construct($sequenceName = null)
{
$this->sequenceName = $sequenceName;
}
/**
* {@inheritdoc}
*/
public function generate(EntityManager $em, $entity)
{
return (string)$em->getConnection()->lastInsertId($this->sequenceName);
}
/**
* {@inheritdoc}
*/
public function isPostInsertGenerator()
{
return true;
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -28,21 +28,17 @@ use Doctrine\ORM\EntityManager;
*/
class IdentityGenerator extends AbstractIdGenerator
{
/**
* The name of the sequence to pass to lastInsertId(), if any.
*
* @var string
*/
private $sequenceName;
/** @var string The name of the sequence to pass to lastInsertId(), if any. */
private $_seqName;
/**
* @param string $seqName The name of the sequence to pass to lastInsertId()
* to obtain the last generated identifier within the current
* database session/connection, if any.
*/
public function __construct($sequenceName = null)
public function __construct($seqName = null)
{
$this->sequenceName = $sequenceName;
$this->_seqName = $seqName;
}
/**
@@ -50,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
return (int)$em->getConnection()->lastInsertId($this->sequenceName);
return $em->getConnection()->lastInsertId($this->_seqName);
}
/**
@@ -60,4 +56,4 @@ class IdentityGenerator extends AbstractIdGenerator
{
return true;
}
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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

@@ -1,48 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Id;
use Serializable, Doctrine\ORM\EntityManager;
/**
* Represents an ID generator that uses the database UUID expression
*
* @since 2.3
* @author Maarten de Keizer <m.de.keizer@markei.nl>
*/
class UuidGenerator extends AbstractIdGenerator
{
/**
* Generates an ID for the given entity.
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to user
* @param object $entity
* @return string The generated value.
* @override
*/
public function generate(EntityManager $em, $entity)
{
$conn = $em->getConnection();
$sql = 'SELECT ' . $conn->getDatabasePlatform()->getGuidExpression();
return $conn->query($sql)->fetchColumn(0);
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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,19 +100,19 @@ 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

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -22,37 +22,34 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\Events,
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
{
/** @var \Doctrine\ORM\Query\ResultSetMapping The ResultSetMapping. */
/** @var ResultSetMapping The ResultSetMapping. */
protected $_rsm;
/** @var EntityManager The EntityManager instance. */
protected $_em;
/** @var \Doctrine\DBAL\Platforms\AbstractPlatform The dbms Platform instance */
/** @var AbstractPlatform The dbms Platform instance */
protected $_platform;
/** @var \Doctrine\ORM\UnitOfWork The UnitOfWork of the associated EntityManager. */
/** @var UnitOfWork The UnitOfWork of the associated EntityManager. */
protected $_uow;
/** @var array The cache used during row-by-row hydration. */
protected $_cache = array();
/** @var \Doctrine\DBAL\Driver\Statement The statement that provides the data to hydrate. */
/** @var Statement The statement that provides the data to hydrate. */
protected $_stmt;
/** @var array The query hints. */
@@ -61,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();
}
/**
@@ -75,20 +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;
$evm = $this->_em->getEventManager();
$evm->addEventListener(array(Events::onClear), $this);
$this->prepare();
$this->_prepare();
return new IterableResult($this);
}
@@ -97,21 +88,16 @@ abstract class AbstractHydrator
*
* @param object $stmt
* @param object $resultSetMapping
* @param array $hints
* @return mixed
*/
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;
}
@@ -124,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;
}
@@ -142,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;
}
@@ -166,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;
}
@@ -251,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) {
@@ -280,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
@@ -288,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();
@@ -376,15 +306,6 @@ abstract class AbstractHydrator
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
}
}
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
/**
* When executed in a hydrate() loop we have to clear internal state to
* decrease memory consumption.
*/
public function onClear($eventArgs)
{
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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,17 +90,12 @@ 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.
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) {
$first = reset($this->_resultPointers);
$first = reset($this->_resultPointers);
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][key($first)];
} else if (isset($this->_resultPointers[$parent])) {
@@ -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,49 +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."
);
}
/**
* @since 2.3
* @param string $entityName
* @param string $discrColumnName
* @param string $dqlAlias
* @return HydrationException
*/
public static function missingDiscriminatorColumn($entityName, $discrColumnName, $dqlAlias)
{
return new self(sprintf(
'The discriminator column "%s" is missing for "%s" using the DQL alias "%s".',
$discrColumnName, $entityName, $dqlAlias
));
}
/**
* @since 2.3
* @param string $entityName
* @param string $discrColumnName
* @param string $dqlAlias
* @return HydrationException
*/
public static function missingDiscriminatorMetaMappingColumn($entityName, $discrColumnName, $dqlAlias)
{
return new self(sprintf(
'The meta mapping for the discriminator column "%s" is missing for "%s" using the DQL alias "%s".',
$discrColumnName, $entityName, $dqlAlias
));
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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)
{
@@ -101,4 +101,4 @@ class IterableResult implements \Iterator
{
return ($this->_current!=false);
}
}
}

View File

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
@@ -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
@@ -54,66 +49,63 @@ class ObjectHydrator extends AbstractHydrator
private $_rootAliases = array();
private $_initializedCollections = array();
private $_existingCollections = array();
//private $_createdEntities;
/** @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;
}
}
}
}
}
}
}
}
}
@@ -121,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();
}
@@ -140,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
@@ -160,41 +151,36 @@ class ObjectHydrator extends AbstractHydrator
/**
* Initializes a related collection.
*
* @param object $entity The entity to which the collection belongs.
* @param ClassMetadata $class
* @param string $fieldName The name of the field on the entity that holds the collection.
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
* @param object $entity The entity to which the collection belongs.
* @param string $name The name of the field on the entity that holds the 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!
@@ -206,55 +192,32 @@ class ObjectHydrator extends AbstractHydrator
/**
* Gets an entity instance.
*
* @param array $data The instance data.
* @param string $dqlAlias The DQL alias of the entity's class.
*
* @param $data The instance data.
* @param $dqlAlias The DQL alias of the entity's class.
* @return object The entity.
*/
private function _getEntity(array $data, $dqlAlias)
{
$className = $this->_rsm->aliasMap[$dqlAlias];
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
if ( ! isset($this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]])) {
throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $this->_rsm->discriminatorColumns[$dqlAlias], $dqlAlias);
}
$discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]];
if ( ! isset($data[$discrColumn])) {
throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $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);
}
/**
* @param string $className
* @param array $data
* @return mixed
*/
private function _getEntityFromIdentityMap($className, array $data)
{
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
$class = $this->_ce[$className];
/* @var $class ClassMetadata */
if ($class->isIdentifierComposite) {
$idHash = '';
@@ -277,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
*/
@@ -286,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.
*
* @param array $row The data of the row to process.
* @param array $cache The cache to use.
* 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;
}
@@ -342,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 {
@@ -367,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]]);
@@ -393,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 {
@@ -408,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
@@ -446,9 +397,6 @@ class ObjectHydrator extends AbstractHydrator
}
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;
} else {
$this->_uow->setOriginalEntityProperty($oid, $relationField, null);
$reflField->setValue($parentObject, null);
}
// else leave $reflFieldValue null for single-valued associations
} else {
@@ -459,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;
@@ -508,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;
@@ -519,33 +456,9 @@ 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;
}
}
}
/**
* When executed in a hydrate() loop we may have to clear internal state to
* decrease memory consumption.
*/
public function onClear($eventArgs)
{
parent::onClear($eventArgs);
$aliases = array_keys($this->_identifierMap);
$this->_identifierMap = array();
foreach ($aliases as $alias) {
$this->_identifierMap[$alias] = array();
}
}
}

View File

@@ -13,43 +13,38 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection;
/**
* Hydrator that produces flat, rectangular results of scalar data.
* 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

@@ -13,18 +13,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <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,136 +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 ( ! isset($sqlResult[$discrColumnName])) {
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
}
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);
case (isset($this->_rsm->metaMappings[$column])):
return array(
'name' => $this->_rsm->metaMappings[$column]
);
default:
return null;
}
}
}
}

View File

@@ -13,44 +13,37 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
interface Annotation
{
}

View File

@@ -1,56 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* This annotation is used to override association mapping of property for an entity relationship.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class AssociationOverride implements Annotation
{
/**
* The name of the relationship property whose mapping is being overridden
*
* @var string
*/
public $name;
/**
* The join column that is being mapped to the persistent attribute.
*
* @var array<\Doctrine\ORM\Mapping\JoinColumn>
*/
public $joinColumns;
/**
* The join table that maps the relationship.
*
* @var \Doctrine\ORM\Mapping\JoinTable
*/
public $joinTable;
}

View File

@@ -1,41 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* This annotation is used to override association mappings of relationship properties.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("CLASS")
*/
final class AssociationOverrides implements Annotation
{
/**
* Mapping overrides of relationship properties
*
* @var array<\Doctrine\ORM\Mapping\AssociationOverride>
*/
public $value;
}

View File

@@ -1,47 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* This annotation is used to override the mapping of a entity property.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class AttributeOverride implements Annotation
{
/**
* The name of the property whose mapping is being overridden.
*
* @var string
*/
public $name;
/**
* The column definition.
*
* @var \Doctrine\ORM\Mapping\Column
*/
public $column;
}

View File

@@ -1,41 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* This annotation is used to override the mapping of a entity property.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("CLASS")
*/
final class AttributeOverrides implements Annotation
{
/**
* One or more field or property mapping overrides.
*
* @var array<\Doctrine\ORM\Mapping\AttributeOverride>
*/
public $value;
}

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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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

@@ -13,17 +13,334 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
use ReflectionClass, ReflectionProperty;
/**
* {@inheritDoc}
* 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.
*
* @todo remove or rename ClassMetadataInfo to ClassMetadata
* <b>IMPORTANT NOTE:</b>
*
* The fields of this class are only public for 2 reasons:
* 1) To allow fast READ access.
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* @author Roman Borschel <roman@code-factory.org>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
*/
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

@@ -13,27 +13,22 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
use ReflectionException;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\EntityManager;
use Doctrine\DBAL\Platforms;
use Doctrine\ORM\Events;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\ORM\Id\IdentityGenerator;
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use ReflectionException,
Doctrine\ORM\ORMException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events,
Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface;
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
* metadata mapping information of a class which describes how a class should be mapped
* metadata mapping informations of a class which describes how a class should be mapped
* to a relational database.
*
* @since 2.0
@@ -42,20 +37,20 @@ use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class ClassMetadataFactory extends AbstractClassMetadataFactory
class ClassMetadataFactory implements ClassMetadataFactoryInterface
{
/**
* @var EntityManager
*/
private $em;
/**
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
* @var AbstractPlatform
*/
private $targetPlatform;
/**
* @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
* @var Driver\Driver
*/
private $driver;
@@ -65,7 +60,22 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private $evm;
/**
* @param EntityManager $em
* @var \Doctrine\Common\Cache\Cache
*/
private $cacheDriver;
/**
* @var array
*/
private $loadedMetadata = array();
/**
* @var bool
*/
private $initialized = false;
/**
* @param EntityManager $$em
*/
public function setEntityManager(EntityManager $em)
{
@@ -73,9 +83,55 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
/**
* {@inheritDoc}.
* Sets the cache driver used by the factory to cache ClassMetadata instances.
*
* @param Doctrine\Common\Cache\Cache $cacheDriver
*/
protected function initialize()
public function setCacheDriver($cacheDriver)
{
$this->cacheDriver = $cacheDriver;
}
/**
* Gets the cache driver used by the factory to cache ClassMetadata instances.
*
* @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()
{
if ( ! $this->initialized) {
$this->initialize();
}
$metadata = array();
foreach ($this->driver->getAllClassNames() as $className) {
$metadata[] = $this->getMetadataFor($className);
}
return $metadata;
}
/**
* Lazy initialization of this stuff, especially the metadata driver,
* since these are not needed at all when a metadata cache is active.
*/
private function initialize()
{
$this->driver = $this->em->getConfiguration()->getMetadataDriverImpl();
$this->targetPlatform = $this->em->getConnection()->getDatabasePlatform();
@@ -84,202 +140,248 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
/**
* {@inheritDoc}
* Gets the class metadata descriptor for a class.
*
* @param string $className The name of the class.
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents)
public function getMetadataFor($className)
{
/* @var $class ClassMetadata */
/* @var $parent ClassMetadata */
if ($parent) {
$class->setInheritanceType($parent->inheritanceType);
$class->setDiscriminatorColumn($parent->discriminatorColumn);
$class->setIdGeneratorType($parent->generatorType);
$this->addInheritedFields($class, $parent);
$this->addInheritedRelations($class, $parent);
$class->setIdentifier($parent->identifier);
$class->setVersioned($parent->isVersioned);
$class->setVersionField($parent->versionField);
$class->setDiscriminatorMap($parent->discriminatorMap);
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
if ( ! isset($this->loadedMetadata[$className])) {
$realClassName = $className;
if ($parent->isMappedSuperclass) {
$class->setCustomRepositoryClass($parent->customRepositoryClassName);
// Check for namespace alias
if (strpos($className, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $className);
$realClassName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
if (isset($this->loadedMetadata[$realClassName])) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
return $this->loadedMetadata[$realClassName];
}
}
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
"$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
);
}
}
} else {
$this->loadMetadata($realClassName);
}
if ($className != $realClassName) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
}
}
// Invoke driver
try {
$this->driver->loadMetadataForClass($class->getName(), $class);
} catch (ReflectionException $e) {
throw MappingException::reflectionFailure($class->getName(), $e);
return $this->loadedMetadata[$className];
}
/**
* 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.
*/
public function hasMetadataFor($className)
{
return isset($this->loadedMetadata[$className]);
}
/**
* 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
* @param ClassMetadata $class
*/
public function setMetadataFor($className, $class)
{
$this->loadedMetadata[$className] = $class;
}
/**
* Get array of parent classes for the given entity class
*
* @param string $name
* @return array $parentClasses
*/
protected function getParentClasses($name)
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
foreach (array_reverse(class_parents($name)) as $parentClass) {
if ( ! $this->driver->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
}
return $parentClasses;
}
/**
* Loads the metadata of the class in question and all it's ancestors whose metadata
* is still not loaded.
*
* @param string $name The name of the class for which the metadata should get loaded.
* @param array $tables The metadata collection to which the loaded metadata is added.
*/
protected function loadMetadata($name)
{
if ( ! $this->initialized) {
$this->initialize();
}
// If this class has a parent the id generator strategy is inherited.
// However this is only true if the hierarchy of parents contains the root entity,
// if it consists of mapped superclasses these don't necessarily include the id field.
if ($parent && $rootEntityFound) {
if ($parent->isIdGeneratorSequence()) {
$class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
} else if ($parent->isIdGeneratorTable()) {
$class->tableGeneratorDefinition = $parent->tableGeneratorDefinition;
$loaded = array();
$parentClasses = $this->getParentClasses($name);
$parentClasses[] = $name;
// Move down the hierarchy of parent classes, starting from the topmost class
$parent = null;
$rootEntityFound = false;
$visited = array();
foreach ($parentClasses as $className) {
if (isset($this->loadedMetadata[$className])) {
$parent = $this->loadedMetadata[$className];
if ( ! $parent->isMappedSuperclass) {
$rootEntityFound = true;
array_unshift($visited, $className);
}
continue;
}
if ($parent->generatorType) {
$class = $this->newClassMetadataInstance($className);
if ($parent) {
$class->setInheritanceType($parent->inheritanceType);
$class->setDiscriminatorColumn($parent->discriminatorColumn);
$class->setIdGeneratorType($parent->generatorType);
$this->addInheritedFields($class, $parent);
$this->addInheritedRelations($class, $parent);
$class->setIdentifier($parent->identifier);
$class->setVersioned($parent->isVersioned);
$class->setVersionField($parent->versionField);
$class->setDiscriminatorMap($parent->discriminatorMap);
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
}
if ($parent->idGenerator) {
$class->setIdGenerator($parent->idGenerator);
// Invoke driver
try {
$this->driver->loadMetadataForClass($className, $class);
} catch (ReflectionException $e) {
throw MappingException::reflectionFailure($className, $e);
}
} else {
$this->completeIdGeneratorMapping($class);
// If this class has a parent the id generator strategy is inherited.
// However this is only true if the hierachy of parents contains the root entity,
// if it consinsts of mapped superclasses these don't necessarily include the id field.
if ($parent && $rootEntityFound) {
if ($parent->isIdGeneratorSequence()) {
$class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
} else if ($parent->isIdGeneratorTable()) {
$class->getTableGeneratorDefinition($parent->tableGeneratorDefinition);
}
if ($parent->generatorType) {
$class->setIdGeneratorType($parent->generatorType);
}
if ($parent->idGenerator) {
$class->setIdGenerator($parent->idGenerator);
}
} else {
$this->completeIdGeneratorMapping($class);
}
if ($parent && $parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
$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->validateRuntimeMetadata($class, $parent);
$this->loadedMetadata[$className] = $class;
$parent = $class;
if ( ! $class->isMappedSuperclass) {
$rootEntityFound = true;
array_unshift($visited, $className);
}
$loaded[] = $className;
}
if ($parent && $parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent && !empty($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
if ($parent && !empty($parent->namedNativeQueries)) {
$this->addInheritedNamedNativeQueries($class, $parent);
}
if ($parent && !empty($parent->sqlResultSetMappings)) {
$this->addInheritedSqlResultSetMappings($class, $parent);
}
$class->setParentClasses($nonSuperclassParents);
if ( $class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
$this->addDefaultDiscriminatorMap($class);
}
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
$eventArgs = new LoadClassMetadataEventArgs($class, $this->em);
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
}
$this->wakeupReflection($class, $this->getReflectionService());
$this->validateRuntimeMetadata($class, $parent);
return $loaded;
}
/**
* Validate runtime metadata is correctly defined.
*
* @param ClassMetadata $class
* @param $parent
* @throws MappingException
* @param ClassMetadata $parent
*/
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) {
if (!$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
if (!$parent) {
if (count($class->discriminatorMap) == 0) {
throw MappingException::missingDiscriminatorMap($class->name);
}
if ( ! $class->discriminatorColumn) {
if (!$class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name);
}
} else if ($parent && !$class->reflClass->isAbstract() && !in_array($class->name, array_values($class->discriminatorMap))) {
// enforce discriminator map for all entities of an inheritance hierarchy, otherwise problems will occur.
// enforce discriminator map for all entities of an inheritance hierachy, otherwise problems will occur.
throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName);
}
} else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
// second condition is necessary for mapped superclasses in the middle of an inheritance hierachy
throw MappingException::noInheritanceOnMappedSuperClass($class->name);
}
}
/**
* {@inheritDoc}
* Creates a new ClassMetadata instance for the given class name.
*
* @param string $className
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
protected function newClassMetadataInstance($className)
{
return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy());
}
/**
* Adds a default discriminator map if no one is given
*
* If an entity is of any inheritance type and does not contain a
* discriminator map, then the map is generated automatically. This process
* is expensive computation wise.
*
* The automatically generated discriminator map contains the lowercase short name of
* each class as key.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $class
* @throws MappingException
*/
private function addDefaultDiscriminatorMap(ClassMetadata $class)
{
$allClasses = $this->driver->getAllClassNames();
$fqcn = $class->getName();
$map = array($this->getShortName($class->name) => $fqcn);
$duplicates = array();
foreach ($allClasses as $subClassCandidate) {
if (is_subclass_of($subClassCandidate, $fqcn)) {
$shortName = $this->getShortName($subClassCandidate);
if (isset($map[$shortName])) {
$duplicates[] = $shortName;
}
$map[$shortName] = $subClassCandidate;
}
}
if ($duplicates) {
throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map);
}
$class->setDiscriminatorMap($map);
}
/**
* Get the lower-case short name of a class.
*
* @param string $className
* @return string
*/
private function getShortName($className)
{
if (strpos($className, "\\") === false) {
return strtolower($className);
}
$parts = explode("\\", $className);
return strtolower(end($parts));
return new ClassMetadata($className);
}
/**
* 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)
{
foreach ($parentClass->fieldMappings as $mapping) {
foreach ($parentClass->fieldMappings as $fieldName => $mapping) {
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
}
@@ -296,9 +398,8 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
/**
* Adds inherited association mappings to the subclass mapping.
*
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
* @throws MappingException
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
{
@@ -321,83 +422,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
}
/**
* 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']
));
}
}
}
/**
* Adds inherited named native queries to the subclass mapping.
*
* @since 2.3
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->namedNativeQueries as $name => $query) {
if ( ! isset ($subClass->namedNativeQueries[$name])) {
$subClass->addNamedNativeQuery(array(
'name' => $query['name'],
'query' => $query['query'],
'isSelfClass' => $query['isSelfClass'],
'resultSetMapping' => $query['resultSetMapping'],
'resultClass' => $query['isSelfClass'] ? $subClass->name : $query['resultClass'],
));
}
}
}
/**
* Adds inherited sql result set mappings to the subclass mapping.
*
* @since 2.3
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
if ( ! isset ($subClass->sqlResultSetMappings[$name])) {
$entities = array();
foreach ($mapping['entities'] as $entity) {
$entities[] = array(
'fields' => $entity['fields'],
'isSelfClass' => $entity['isSelfClass'],
'discriminatorColumn' => $entity['discriminatorColumn'],
'entityClass' => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'],
);
}
$subClass->addSqlResultSetMapping(array(
'name' => $mapping['name'],
'columns' => $mapping['columns'],
'entities' => $entities,
));
}
}
}
/**
* Completes the ID generator mapping. If "auto" is specified we choose the generator
* most appropriate for the targeted database platform.
*
* @param ClassMetadataInfo $class
* @throws ORMException
* @param Doctrine\ORM\Mapping\ClassMetadata $class
*/
private function completeIdGeneratorMapping(ClassMetadataInfo $class)
{
@@ -418,126 +447,35 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
// For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to
// <table>_<column>_seq in PostgreSQL for SERIAL columns.
// Not pretty but necessary and the simplest solution that currently works.
$sequenceName = null;
$fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
if ($this->targetPlatform instanceof Platforms\PostgreSQLPlatform) {
$columnName = $class->getSingleIdentifierColumnName();
$quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
$sequenceName = $class->getTableName() . '_' . $columnName . '_seq';
$definition = array(
'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName)
);
if ($quoted) {
$definition['quoted'] = true;
}
$sequenceName = $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform);
}
$generator = ($fieldName && $class->fieldMappings[$fieldName]['type'] === "bigint")
? new BigIntegerIdentityGenerator($sequenceName)
: new IdentityGenerator($sequenceName);
$class->setIdGenerator($generator);
$seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ?
$class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
null;
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName));
break;
case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
// If there is no sequence definition yet, create a default definition
$definition = $class->sequenceGeneratorDefinition;
if ( ! $definition) {
$fieldName = $class->getSingleIdentifierFieldName();
$columnName = $class->getSingleIdentifierColumnName();
$quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
$sequenceName = $class->getTableName() . '_' . $columnName . '_seq';
$definition = array(
'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName),
'allocationSize' => 1,
'initialValue' => 1,
);
if ($quoted) {
$definition['quoted'] = true;
}
$sequenceName = $class->getTableName() . '_' . $class->getSingleIdentifierColumnName() . '_seq';
$definition['sequenceName'] = $this->targetPlatform->fixSchemaElementName($sequenceName);
$definition['allocationSize'] = 1;
$definition['initialValue'] = 1;
$class->setSequenceGeneratorDefinition($definition);
}
$sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator(
$this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform),
$definition['sequenceName'],
$definition['allocationSize']
);
$class->setIdGenerator($sequenceGenerator);
break;
case ClassMetadata::GENERATOR_TYPE_NONE:
$class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
break;
case ClassMetadata::GENERATOR_TYPE_UUID:
$class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator());
break;
case ClassMetadata::GENERATOR_TYPE_TABLE:
throw new ORMException("TableGenerator not yet implemented.");
break;
case ClassMetadata::GENERATOR_TYPE_CUSTOM:
$definition = $class->customGeneratorDefinition;
if ( ! class_exists($definition['class'])) {
throw new ORMException("Can't instantiate custom generator : " .
$definition['class']);
}
$class->setIdGenerator(new $definition['class']);
break;
default:
throw new ORMException("Unknown generator type: " . $class->generatorType);
}
}
/**
* {@inheritDoc}
*/
protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService)
{
/* @var $class ClassMetadata */
$class->wakeupReflection($reflService);
}
/**
* {@inheritDoc}
*/
protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService)
{
/* @var $class ClassMetadata */
$class->initializeReflection($reflService);
}
/**
* {@inheritDoc}
*/
protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
{
return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
/**
* {@inheritDoc}
*/
protected function getDriver()
{
return $this->driver;
}
/**
* {@inheritDoc}
*/
protected function isEntity(ClassMetadataInterface $class)
{
return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
}
}

File diff suppressed because it is too large Load Diff

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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
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,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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* References name of a column in the SELECT clause of a SQL query.
* Scalar result types can be included in the query result by specifying this annotation in the metadata.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class ColumnResult implements Annotation
{
/**
* The name of a column in the SELECT clause of a SQL query
*
* @var string
*/
public $name;
}

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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class CustomIdGenerator implements Annotation
{
/** @var string */
public $class;
}

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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* The default NamingStrategy
*
*
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultNamingStrategy implements NamingStrategy
{
/**
* {@inheritdoc}
*/
public function classToTableName($className)
{
if (strpos($className, '\\') !== false) {
return substr($className, strrpos($className, '\\') + 1);
}
return $className;
}
/**
* {@inheritdoc}
*/
public function propertyToColumnName($propertyName)
{
return $propertyName;
}
/**
* {@inheritdoc}
*/
public function referenceColumnName()
{
return 'id';
}
/**
* {@inheritdoc}
*/
public function joinColumnName($propertyName)
{
return $propertyName . '_' . $this->referenceColumnName();
}
/**
* {@inheritdoc}
*/
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
{
return strtolower($this->classToTableName($sourceEntity) . '_' .
$this->classToTableName($targetEntity));
}
/**
* {@inheritdoc}
*/
public function joinKeyColumnName($entityName, $referencedColumnName = null)
{
return strtolower($this->classToTableName($entityName) . '_' .
($referencedColumnName ?: $this->referenceColumnName()));
}
}

View File

@@ -1,140 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* A set of rules for determining the physical column, alias and table quotes
*
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultQuoteStrategy implements QuoteStrategy
{
/**
* {@inheritdoc}
*/
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($class->fieldMappings[$fieldName]['quoted'])
? $platform->quoteIdentifier($class->fieldMappings[$fieldName]['columnName'])
: $class->fieldMappings[$fieldName]['columnName'];
}
/**
* {@inheritdoc}
*/
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
{
return isset($class->table['quoted'])
? $platform->quoteIdentifier($class->table['name'])
: $class->table['name'];
}
/**
* {@inheritdoc}
*/
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($definition['quoted'])
? $platform->quoteIdentifier($definition['sequenceName'])
: $definition['sequenceName'];
}
/**
* {@inheritdoc}
*/
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
}
/**
* {@inheritdoc}
*/
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['referencedColumnName'])
: $joinColumn['referencedColumnName'];
}
/**
* {@inheritdoc}
*/
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
{
return isset($association['joinTable']['quoted'])
? $platform->quoteIdentifier($association['joinTable']['name'])
: $association['joinTable']['name'];
}
/**
* {@inheritdoc}
*/
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
{
$quotedColumnNames = array();
foreach ($class->identifier as $fieldName) {
if (isset($class->fieldMappings[$fieldName])) {
$quotedColumnNames[] = $this->getColumnName($fieldName, $class, $platform);
continue;
}
// Association defined as Id field
$joinColumns = $class->associationMappings[$fieldName]['joinColumns'];
$assocQuotedColumnNames = array_map(
function ($joinColumn) use ($platform)
{
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
},
$joinColumns
);
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
}
return $quotedColumnNames;
}
/**
* {@inheritdoc}
*/
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
{
// Trim the column alias to the maximum identifier length of the platform.
// If the alias is to long, characters are cut off from the beginning.
// And strip non alphanumeric characters
$columnName = $columnName . $counter;
$columnName = substr($columnName, -$platform->getMaxIdentifierLength());
$columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName);
return $platform->getSQLResultCasing($columnName);
}
}

View File

@@ -1,38 +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 MIT license. 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)
/** @var string */
public $columnDefinition;
}

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 MIT license. 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

@@ -0,0 +1,210 @@
<?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\Mapping\Driver;
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
* class name, including namespace, with the namespace delimiters '\', replaced by dots '.'.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractFileDriver implements Driver
{
/**
* The paths where to look for mapping files.
*
* @var array
*/
protected $_paths = array();
/**
* The file extension of mapping documents.
*
* @var string
*/
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)
{
$this->addPaths((array) $paths);
}
/**
* Append lookup paths to metadata driver.
*
* @param array $paths
*/
public function addPaths(array $paths)
{
$this->_paths = array_unique(array_merge($this->_paths, $paths));
}
/**
* Retrieve the defined metadata lookup paths.
*
* @return array
*/
public function getPaths()
{
return $this->_paths;
}
/**
* Get the file extension used to look for mapping files under
*
* @return void
*/
public function getFileExtension()
{
return $this->_fileExtension;
}
/**
* Set the file extension used to look for mapping files under
*
* @param string $fileExtension The file extension to set
* @return void
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
/**
* Get the element of schema meta data for the class from the mapping file.
* This will lazily load the mapping file if it is not loaded yet
*
* @return array $element The element of schema meta data
*/
public function getElement($className)
{
$result = $this->_loadMappingFile($this->_findMappingFile($className));
return $result[$className];
}
/**
* Whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a
* MappedSuperclass.
*
* @param string $className
* @return boolean
*/
public function isTransient($className)
{
$fileName = str_replace('\\', '.', $className) . $this->_fileExtension;
// Check whether file exists
foreach ((array) $this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) {
return false;
}
}
return true;
}
/**
* 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()
{
$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) {
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;
}
/**
* Finds the mapping file for the class with the given name by searching
* through the configured paths.
*
* @param $className
* @return string The (absolute) file name.
* @throws MappingException
*/
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)) {
return $path . DIRECTORY_SEPARATOR . $fileName;
}
}
throw MappingException::mappingFileNotFound($className, $fileName);
}
/**
* 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
*/
abstract protected function _loadMappingFile($file);
}

View File

@@ -13,18 +13,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\MappingException,
Doctrine\ORM\Mapping\JoinColumn,
Doctrine\ORM\Mapping\Column,
Doctrine\Common\Persistence\Mapping\ClassMetadata,
Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\Common\Annotations\AnnotationRegistry,
Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException;
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
@@ -35,37 +34,102 @@ use Doctrine\Common\Annotations\AnnotationReader,
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class AnnotationDriver extends AbstractAnnotationDriver
class AnnotationDriver implements Driver
{
/**
* {@inheritDoc}
* The AnnotationReader.
*
* @var AnnotationReader
*/
protected $entityAnnotationClasses = array(
'Doctrine\ORM\Mapping\Entity' => 1,
'Doctrine\ORM\Mapping\MappedSuperclass' => 2,
);
protected $_reader;
/**
* {@inheritDoc}
* The paths where to look for mapping files.
*
* @var array
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
protected $_paths = array();
/**
* The file extension of mapping documents.
*
* @var string
*/
protected $_fileExtension = '.php';
/**
* @param array
*/
protected $_classNames;
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
* @param AnnotationReader $reader The AnnotationReader to use, duck-typed.
* @param string|array $paths One or multiple paths where mapping classes can be found.
*/
public function __construct($reader, $paths = null)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
$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);
$this->_reader = $reader;
if ($paths) {
$this->addPaths((array) $paths);
}
}
$classAnnotations = $this->reader->getClassAnnotations($class);
/**
* Append lookup paths to metadata driver.
*
* @param array $paths
*/
public function addPaths(array $paths)
{
$this->_paths = array_unique(array_merge($this->_paths, $paths));
}
if ($classAnnotations) {
foreach ($classAnnotations as $key => $annot) {
if ( ! is_numeric($key)) {
continue;
}
/**
* Retrieve the defined metadata lookup paths.
*
* @return array
*/
public function getPaths()
{
return $this->_paths;
}
/**
* Get the file extension used to look for mapping files under
*
* @return void
*/
public function getFileExtension()
{
return $this->_fileExtension;
}
/**
* Set the file extension used to look for mapping files under
*
* @param string $fileExtension The file extension to set
* @return void
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
/**
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$class = $metadata->getReflectionClass();
$classAnnotations = $this->_reader->getClassAnnotations($class);
// Compatibility with Doctrine Common 3.x
if ($classAnnotations && is_int(key($classAnnotations))) {
foreach ($classAnnotations as $annot) {
$classAnnotations[get_class($annot)] = $annot;
}
}
@@ -73,15 +137,12 @@ class AnnotationDriver extends AbstractAnnotationDriver
// 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);
@@ -97,99 +158,28 @@ class AnnotationDriver extends AbstractAnnotationDriver
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
);
}
}
if ($tableAnnot->options !== null) {
$primaryTable['options'] = $tableAnnot->options;
}
$metadata->setPrimaryTable($primaryTable);
}
// Evaluate NamedNativeQueries annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'])) {
$namedNativeQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'];
foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
$metadata->addNamedNativeQuery(array(
'name' => $namedNativeQuery->name,
'query' => $namedNativeQuery->query,
'resultClass' => $namedNativeQuery->resultClass,
'resultSetMapping' => $namedNativeQuery->resultSetMapping,
));
}
}
// Evaluate SqlResultSetMappings annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'])) {
$sqlResultSetMappingsAnnot = $classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'];
foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
$entities = array();
$columns = array();
foreach ($resultSetMapping->entities as $entityResultAnnot) {
$entityResult = array(
'fields' => array(),
'entityClass' => $entityResultAnnot->entityClass,
'discriminatorColumn' => $entityResultAnnot->discriminatorColumn,
);
foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
$entityResult['fields'][] = array(
'name' => $fieldResultAnnot->name,
'column' => $fieldResultAnnot->column
);
}
$entities[] = $entityResult;
}
foreach ($resultSetMapping->columns as $columnResultAnnot) {
$columns[] = array(
'name' => $columnResultAnnot->name,
);
}
$metadata->addSqlResultSetMapping(array(
'name' => $resultSetMapping->name,
'entities' => $entities,
'columns' => $columns
));
}
}
// Evaluate NamedQueries annotation
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
@@ -209,8 +199,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
$metadata->setDiscriminatorColumn(array(
'name' => $discrColumnAnnot->name,
'type' => $discrColumnAnnot->type,
'length' => $discrColumnAnnot->length,
'columnDefinition' => $discrColumnAnnot->columnDefinition
'length' => $discrColumnAnnot->length
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
@@ -232,7 +221,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
@@ -248,53 +236,81 @@ class AnnotationDriver extends AbstractAnnotationDriver
// Check for JoinColummn/JoinColumns annotations
$joinColumns = array();
if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
$joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
} else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
if ($joinColumnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
$joinColumns[] = array(
'name' => $joinColumnAnnot->name,
'referencedColumnName' => $joinColumnAnnot->referencedColumnName,
'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')) {
foreach ($joinColumnsAnnot->value as $joinColumn) {
$joinColumns[] = $this->joinColumnToArray($joinColumn);
$joinColumns[] = array(
'name' => $joinColumn->name,
'referencedColumnName' => $joinColumn->referencedColumnName,
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
}
// Field can only be annotated with one of:
// @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
if ($columnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
if ($columnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
if ($columnAnnot->type == null) {
throw MappingException::propertyTypeIsRequired($className, $property->getName());
}
$mapping = $this->columnToArray($property->getName(), $columnAnnot);
$mapping['type'] = $columnAnnot->type;
$mapping['length'] = $columnAnnot->length;
$mapping['precision'] = $columnAnnot->precision;
$mapping['scale'] = $columnAnnot->scale;
$mapping['nullable'] = $columnAnnot->nullable;
$mapping['unique'] = $columnAnnot->unique;
if ($columnAnnot->options) {
$mapping['options'] = $columnAnnot->options;
}
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
if (isset($columnAnnot->name)) {
$mapping['columnName'] = $columnAnnot->name;
}
if (isset($columnAnnot->columnDefinition)) {
$mapping['columnDefinition'] = $columnAnnot->columnDefinition;
}
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
if ($generatedValueAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
}
if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
if ($versionAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
$metadata->setVersionMapping($mapping);
}
$metadata->mapField($mapping);
// Check for SequenceGenerator/TableGenerator definition
if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
if ($seqGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
$metadata->setSequenceGeneratorDefinition(array(
'sequenceName' => $seqGeneratorAnnot->sequenceName,
'allocationSize' => $seqGeneratorAnnot->allocationSize,
'initialValue' => $seqGeneratorAnnot->initialValue
));
} else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
} else if ($tblGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
throw MappingException::tableIdGeneratorNotImplemented($className);
} else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
$metadata->setCustomGeneratorDefinition(array(
'class' => $customGeneratorAnnot->class
));
}
} else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
} else if ($oneToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
@@ -304,23 +320,23 @@ class AnnotationDriver extends AbstractAnnotationDriver
$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')) {
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
$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')) {
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
} else if ($manyToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
$mapping['id'] = true;
}
@@ -328,23 +344,39 @@ class AnnotationDriver extends AbstractAnnotationDriver
$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')) {
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
if ($joinTableAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema
);
foreach ($joinTableAnnot->joinColumns as $joinColumn) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
$joinTable['joinColumns'][] = array(
'name' => $joinColumn->name,
'referencedColumnName' => $joinColumn->referencedColumnName,
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
$joinTable['inverseJoinColumns'][] = array(
'name' => $joinColumn->name,
'referencedColumnName' => $joinColumn->referencedColumnName,
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
}
@@ -354,10 +386,9 @@ class AnnotationDriver extends AbstractAnnotationDriver
$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')) {
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
@@ -365,69 +396,16 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
}
// Evaluate AssociationOverrides annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'])) {
$associationOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'];
foreach ($associationOverridesAnnot->value as $associationOverride) {
$override = array();
$fieldName = $associationOverride->name;
// Check for JoinColummn/JoinColumns annotations
if ($associationOverride->joinColumns) {
$joinColumns = array();
foreach ($associationOverride->joinColumns as $joinColumn) {
$joinColumns[] = $this->joinColumnToArray($joinColumn);
}
$override['joinColumns'] = $joinColumns;
}
// Check for JoinTable annotations
if ($associationOverride->joinTable) {
$joinTable = null;
$joinTableAnnot = $associationOverride->joinTable;
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema
);
foreach ($joinTableAnnot->joinColumns as $joinColumn) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
}
foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate AttributeOverrides annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'])) {
$attributeOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'];
foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) {
$attributeOverride = $this->columnToArray($attributeOverrideAnnot->name, $attributeOverrideAnnot->column);
$metadata->setAttributeOverride($attributeOverrideAnnot->name, $attributeOverride);
}
}
// Evaluate @HasLifecycleCallbacks annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods() as $method) {
// filter for the declaring class only, callbacks from parents will already be registered.
if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) {
$annotations = $this->reader->getMethodAnnotations($method);
$annotations = $this->_reader->getMethodAnnotations($method);
if ($annotations) {
foreach ($annotations as $key => $annot) {
if ( ! is_numeric($key)) {
continue;
}
// Compatibility with Doctrine Common 3.x
if ($annotations && is_int(key($annotations))) {
foreach ($annotations as $annot) {
$annotations[get_class($annot)] = $annot;
}
}
@@ -459,82 +437,94 @@ class AnnotationDriver extends AbstractAnnotationDriver
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);
}
}
}
}
}
/**
* Attempts to resolve the fetch mode.
* Whether the class with the specified name is transient. Only non-transient
* classes, that is entities and mapped superclasses, should have their metadata loaded.
* A class is non-transient if it is annotated with either @Entity or
* @MappedSuperclass in the class doc block.
*
* @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
* @param string $className
* @return boolean
*/
private function getFetchMode($className, $fetchMode)
public function isTransient($className)
{
if( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
throw MappingException::invalidFetchMode($className, $fetchMode);
$classAnnotations = $this->_reader->getClassAnnotations(new \ReflectionClass($className));
// 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;
}
if ($annot instanceof \Doctrine\ORM\Mapping\MappedSuperclass) {
return false;
}
}
return true;
}
return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
return ! isset($classAnnotations['Doctrine\ORM\Mapping\Entity']) &&
! isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass']);
}
/**
* Parse the given JoinColumn as array
*
* @param JoinColumn $joinColumn
* @return array
* {@inheritDoc}
*/
private function joinColumnToArray(JoinColumn $joinColumn)
public function getAllClassNames()
{
return array(
'name' => $joinColumn->name,
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'columnDefinition' => $joinColumn->columnDefinition,
'referencedColumnName' => $joinColumn->referencedColumnName,
);
}
/**
* Parse the given Column as array
*
* @param string $fieldName
* @param Column $column
* @return array
*/
private function columnToArray($fieldName, Column $column)
{
$mapping = array(
'fieldName' => $fieldName,
'type' => $column->type,
'scale' => $column->scale,
'length' => $column->length,
'unique' => $column->unique,
'nullable' => $column->nullable,
'precision' => $column->precision
);
if ($column->options) {
$mapping['options'] = $column->options;
if ($this->_classNames !== null) {
return $this->_classNames;
}
if (isset($column->name)) {
$mapping['columnName'] = $column->name;
if (!$this->_paths) {
throw MappingException::pathRequired();
}
if (isset($column->columnDefinition)) {
$mapping['columnDefinition'] = $column->columnDefinition;
$classes = array();
$includedFiles = array();
foreach ($this->_paths as $path) {
if ( ! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RegexIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+\\' . $this->_fileExtension . '$/i',
\RecursiveRegexIterator::GET_MATCH
);
foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}
return $mapping;
$declared = get_declared_classes();
foreach ($declared as $className) {
$rc = new \ReflectionClass($className);
$sourceFile = $rc->getFileName();
if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
$classes[] = $className;
}
}
$this->_classNames = $classes;
return $classes;
}
/**
@@ -548,8 +538,8 @@ class AnnotationDriver extends AbstractAnnotationDriver
{
if ($reader == null) {
$reader = new AnnotationReader();
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
}
return new self($reader, $paths);
}
}

View File

@@ -13,31 +13,31 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\DBAL\Schema\AbstractSchemaManager,
use Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\DBAL\Schema\AbstractSchemaManager,
Doctrine\DBAL\Schema\SchemaException,
Doctrine\Common\Persistence\Mapping\Driver\MappingDriver,
Doctrine\Common\Persistence\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\Common\Util\Inflector,
Doctrine\ORM\Mapping\MappingException;
Doctrine\ORM\Mapping\MappingException,
Doctrine\Common\Util\Inflector;
/**
* The DatabaseDriver reverse engineers the mapping metadata from a database.
*
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class DatabaseDriver implements MappingDriver
class DatabaseDriver implements Driver
{
/**
* @var AbstractSchemaManager
@@ -74,8 +74,10 @@ class DatabaseDriver implements MappingDriver
private $namespace;
/**
*
* @param AbstractSchemaManager $schemaManager
* 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)
{
@@ -92,12 +94,12 @@ class DatabaseDriver implements MappingDriver
public function setTables($entityTables, $manyToManyTables)
{
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
foreach ($entityTables as $table) {
foreach ($entityTables AS $table) {
$className = $this->getClassNameForTable($table->getName());
$this->classToTableNames[$className] = $table->getName();
$this->tables[$table->getName()] = $table;
}
foreach ($manyToManyTables as $table) {
foreach ($manyToManyTables AS $table) {
$this->manyToManyTables[$table->getName()] = $table;
}
}
@@ -109,14 +111,14 @@ class DatabaseDriver implements MappingDriver
}
$tables = array();
foreach ($this->_sm->listTableNames() as $tableName) {
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
}
$this->tables = $this->manyToManyTables = $this->classToTableNames = array();
foreach ($tables as $tableName => $table) {
/* @var $table \Doctrine\DBAL\Schema\Table */
foreach ($tables AS $tableName => $table) {
/* @var $table Table */
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $table->getForeignKeys();
} else {
@@ -124,17 +126,10 @@ class DatabaseDriver implements MappingDriver
}
$allForeignKeyColumns = array();
foreach ($foreignKeys as $foreignKey) {
foreach ($foreignKeys AS $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
if ( ! $table->hasPrimaryKey()) {
throw new MappingException(
"Table " . $table->getName() . " has no primary key. Doctrine does not ".
"support reverse engineering from tables that don't have a primary key."
);
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
@@ -150,11 +145,11 @@ class DatabaseDriver implements MappingDriver
}
}
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$this->reverseEngineerMappingFromDatabase();
@@ -174,7 +169,7 @@ class DatabaseDriver implements MappingDriver
} catch(SchemaException $e) {
$primaryKeyColumns = array();
}
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
} else {
@@ -182,7 +177,7 @@ class DatabaseDriver implements MappingDriver
}
$allForeignKeyColumns = array();
foreach ($foreignKeys as $foreignKey) {
foreach ($foreignKeys AS $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
@@ -190,11 +185,10 @@ class DatabaseDriver implements MappingDriver
$fieldMappings = array();
foreach ($columns as $column) {
$fieldMapping = array();
if (in_array($column->getName(), $allForeignKeyColumns)) {
continue;
} else if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) {
$fieldMapping['id'] = true;
} else if (in_array($column->getName(), $allForeignKeyColumns)) {
continue;
}
$fieldMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $column->getName(), false);
@@ -230,13 +224,13 @@ class DatabaseDriver implements MappingDriver
$metadata->mapField($fieldMapping);
}
foreach ($this->manyToManyTables as $manyTable) {
foreach ($manyTable->getForeignKeys() as $foreignKey) {
foreach ($this->manyToManyTables AS $manyTable) {
foreach ($manyTable->getForeignKeys() AS $foreignKey) {
// foreign key maps to the table of the current entity, many to many association probably exists
if (strtolower($tableName) == strtolower($foreignKey->getForeignTableName())) {
$myFk = $foreignKey;
$otherFk = null;
foreach ($manyTable->getForeignKeys() as $foreignKey) {
foreach ($manyTable->getForeignKeys() AS $foreignKey) {
if ($foreignKey != $myFk) {
$otherFk = $foreignKey;
break;
@@ -297,32 +291,18 @@ class DatabaseDriver implements MappingDriver
$associationMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $localColumn, true);
$associationMapping['targetEntity'] = $this->getClassNameForTable($foreignTable);
if (isset($metadata->fieldMappings[$associationMapping['fieldName']])) {
$associationMapping['fieldName'] = $associationMapping['fieldName'] . "2";
}
if ($primaryKeyColumns && in_array($localColumn, $primaryKeyColumns)) {
$associationMapping['id'] = true;
}
for ($i = 0; $i < count($cols); $i++) {
$associationMapping['joinColumns'][] = array(
'name' => $cols[$i],
'referencedColumnName' => $fkCols[$i],
);
}
//Here we need to check if $cols are the same as $primaryKeyColums
if (!array_diff($cols,$primaryKeyColumns)) {
$metadata->mapOneToOne($associationMapping);
} else {
$metadata->mapManyToOne($associationMapping);
}
$metadata->mapManyToOne($associationMapping);
}
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function isTransient($className)
{
@@ -330,7 +310,11 @@ class DatabaseDriver implements MappingDriver
}
/**
* {@inheritDoc}
* Return all the class names supported by this driver.
*
* IMPORTANT: This method must return an array of class not tables names.
*
* @return array
*/
public function getAllClassNames()
{

View File

@@ -13,54 +13,194 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <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__.'/../CustomIdGenerator.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';
require_once __DIR__.'/../FieldResult.php';
require_once __DIR__.'/../ColumnResult.php';
require_once __DIR__.'/../EntityResult.php';
require_once __DIR__.'/../NamedNativeQuery.php';
require_once __DIR__.'/../NamedNativeQueries.php';
require_once __DIR__.'/../SqlResultSetMapping.php';
require_once __DIR__.'/../SqlResultSetMappings.php';
require_once __DIR__.'/../AssociationOverride.php';
require_once __DIR__.'/../AssociationOverrides.php';
require_once __DIR__.'/../AttributeOverride.php';
require_once __DIR__.'/../AttributeOverrides.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

@@ -1,6 +1,7 @@
<?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
@@ -18,59 +19,41 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC1476;
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* @Entity()
* Contract for metadata drivers.
*
* @since 2.0
* @author Jonathan H. Wage <jonwage@gmail.com>
* @todo Rename: MetadataDriver or MappingDriver
*/
class DDC1476EntityWithDefaultFieldType
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();
/**
* @Id
* @Column()
* @GeneratedValue("NONE")
* Whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a
* MappedSuperclass.
*
* @param string $className
* @return boolean
*/
protected $id;
/** @column() */
protected $name;
/**
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
{
$metadata->mapField(array(
'id' => true,
'fieldName' => 'id',
));
$metadata->mapField(array(
'fieldName' => 'name',
));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_NONE);
}
function isTransient($className);
}

View File

@@ -13,19 +13,114 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\ORM\Mapping\Driver\Driver,
Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException;
/**
* {@inheritDoc}
* The DriverChain allows you to add multiple other mapping drivers for
* certain namespaces
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename: MappingDriverChain or MetadataDriverChain
*/
class DriverChain extends MappingDriverChain
class DriverChain implements Driver
{
/**
* @var array
*/
private $_drivers = array();
/**
* Add a nested driver.
*
* @param Driver $nestedDriver
* @param string $namespace
*/
public function addDriver(Driver $nestedDriver, $namespace)
{
$this->_drivers[$namespace] = $nestedDriver;
}
/**
* Get the array of nested drivers.
*
* @return array $drivers
*/
public function getDrivers()
{
return $this->_drivers;
}
/**
* Loads the metadata for the specified class into the provided container.
*
* @param string $className
* @param ClassMetadataInfo $metadata
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
foreach ($this->_drivers as $namespace => $driver) {
if (strpos($className, $namespace) === 0) {
$driver->loadMetadataForClass($className, $metadata);
return;
}
}
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
}
/**
* 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()
{
$classNames = array();
$driverClasses = array();
foreach ($this->_drivers AS $namespace => $driver) {
$oid = spl_object_hash($driver);
if (!isset($driverClasses[$oid])) {
$driverClasses[$oid] = $driver->getAllClassNames();
}
foreach ($driverClasses[$oid] AS $className) {
if (strpos($className, $namespace) === 0) {
$classNames[$className] = true;
}
}
}
return array_keys($classNames);
}
/**
* Whether the class with the specified name should have its metadata loaded.
*
* This is only the case for non-transient classes either mapped as an Entity or MappedSuperclass.
*
* @param string $className
* @return boolean
*/
public function isTransient($className)
{
foreach ($this->_drivers AS $namespace => $driver) {
if (strpos($className, $namespace) === 0) {
return $driver->isTransient($className);
}
}
// class isTransient, i.e. not an entity or mapped superclass
return true;
}
}

View File

@@ -13,19 +13,57 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
use Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\DBAL\Schema\AbstractSchemaManager,
Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException,
Doctrine\Common\Util\Inflector,
Doctrine\ORM\Mapping\Driver\AbstractFileDriver;
/**
* {@inheritDoc}
* The PHPDriver includes php files which just populate ClassMetadataInfo
* instances with plain php code
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver instead
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename: PHPDriver
*/
class PHPDriver extends CommonPHPDriver
class PHPDriver extends AbstractFileDriver
{
/**
* {@inheritdoc}
*/
protected $_fileExtension = '.php';
protected $_metadata;
/**
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$this->_metadata = $metadata;
$this->_loadMappingFile($this->_findMappingFile($className));
}
/**
* {@inheritdoc}
*/
protected function _loadMappingFile($file)
{
$metadata = $this->_metadata;
include $file;
}
}

View File

@@ -1,43 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* 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
{
const DEFAULT_FILE_EXTENSION = '.orm.xml';
/**
* {@inheritDoc}
*/
public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
$locator = new SymfonyFileLocator((array) $prefixes, $fileExtension);
parent::__construct($locator, $fileExtension);
}
}

View File

@@ -1,43 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* 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
{
const DEFAULT_FILE_EXTENSION = '.orm.yml';
/**
* {@inheritDoc}
*/
public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION)
{
$locator = new SymfonyFileLocator((array) $prefixes, $fileExtension);
parent::__construct($locator, $fileExtension);
}
}

View File

@@ -13,19 +13,126 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException;
/**
* {@inheritDoc}
* The StaticPHPDriver calls a static loadMetadata() method on your entity
* classes where you can manually populate the ClassMetadata instance.
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver instead
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class StaticPHPDriver extends CommonStaticPHPDriver
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';
public function __construct($paths)
{
$this->addPaths((array) $paths);
}
public function addPaths(array $paths)
{
$this->_paths = array_unique(array_merge($this->_paths, $paths));
}
/**
* {@inheritdoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
call_user_func_array(array($className, 'loadMetadata'), array($metadata));
}
/**
* {@inheritDoc}
* @todo Same code exists in AnnotationDriver, should we re-use it somehow or not worry about it?
*/
public function getAllClassNames()
{
if ($this->_classNames !== null) {
return $this->_classNames;
}
if (!$this->_paths) {
throw MappingException::pathRequired();
}
$classes = array();
$includedFiles = array();
foreach ($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) {
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
continue;
}
$sourceFile = realpath($file->getPathName());
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}
$declared = get_declared_classes();
foreach ($declared as $className) {
$rc = new \ReflectionClass($className);
$sourceFile = $rc->getFileName();
if (in_array($sourceFile, $includedFiles) && !$this->isTransient($className)) {
$classes[] = $className;
}
}
$this->_classNames = $classes;
return $classes;
}
/**
* {@inheritdoc}
*/
public function isTransient($className)
{
return method_exists($className, 'loadMetadata') ? false : true;
}
}

View File

@@ -1,5 +1,7 @@
<?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
@@ -13,15 +15,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use SimpleXMLElement,
Doctrine\Common\Persistence\Mapping\Driver\FileDriver,
Doctrine\Common\Persistence\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException;
/**
@@ -30,43 +31,34 @@ use SimpleXMLElement,
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class XmlDriver extends FileDriver
class XmlDriver extends AbstractFileDriver
{
const DEFAULT_FILE_EXTENSION = '.dcm.xml';
/**
* {@inheritdoc}
*/
protected $_fileExtension = '.dcm.xml';
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
parent::__construct($locator, $fileExtension);
}
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
/* @var $xmlRoot SimpleXMLElement */
$xmlRoot = $this->getElement($className);
if ($xmlRoot->getName() == 'entity') {
if (isset($xmlRoot['repository-class'])) {
$metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']);
}
if (isset($xmlRoot['read-only']) && $this->evaluateBoolean($xmlRoot['read-only'])) {
$metadata->markReadOnly();
}
} else if ($xmlRoot->getName() == 'mapped-superclass') {
$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->isMappedSuperclass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
@@ -81,7 +73,7 @@ class XmlDriver extends FileDriver
$metadata->setPrimaryTable($table);
// Evaluate named queries
if (isset($xmlRoot->{'named-queries'})) {
if (isset($xmlRoot['named-queries'])) {
foreach ($xmlRoot->{'named-queries'}->{'named-query'} as $namedQueryElement) {
$metadata->addNamedQuery(array(
'name' => (string)$namedQueryElement['name'],
@@ -90,63 +82,11 @@ class XmlDriver extends FileDriver
}
}
// Evaluate native named queries
if (isset($xmlRoot->{'named-native-queries'})) {
foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} as $nativeQueryElement) {
$metadata->addNamedNativeQuery(array(
'name' => isset($nativeQueryElement['name']) ? (string)$nativeQueryElement['name'] : null,
'query' => isset($nativeQueryElement->query) ? (string)$nativeQueryElement->query : null,
'resultClass' => isset($nativeQueryElement['result-class']) ? (string)$nativeQueryElement['result-class'] : null,
'resultSetMapping' => isset($nativeQueryElement['result-set-mapping']) ? (string)$nativeQueryElement['result-set-mapping'] : null,
));
}
}
// Evaluate sql result set mapping
if (isset($xmlRoot->{'sql-result-set-mappings'})) {
foreach ($xmlRoot->{'sql-result-set-mappings'}->{'sql-result-set-mapping'} as $rsmElement) {
$entities = array();
$columns = array();
foreach ($rsmElement as $entityElement) {
//<entity-result/>
if (isset($entityElement['entity-class'])) {
$entityResult = array(
'fields' => array(),
'entityClass' => (string)$entityElement['entity-class'],
'discriminatorColumn' => isset($entityElement['discriminator-column']) ? (string)$entityElement['discriminator-column'] : null,
);
foreach ($entityElement as $fieldElement) {
$entityResult['fields'][] = array(
'name' => isset($fieldElement['name']) ? (string)$fieldElement['name'] : null,
'column' => isset($fieldElement['column']) ? (string)$fieldElement['column'] : null,
);
}
$entities[] = $entityResult;
}
//<column-result/>
if (isset($entityElement['name'])) {
$columns[] = array(
'name' => (string)$entityElement['name'],
);
}
}
$metadata->addSqlResultSetMapping(array(
'name' => (string)$rsmElement['name'],
'entities' => $entities,
'columns' => $columns
));
}
}
/* not implemented specially anyway. use table = schema.table
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));
@@ -156,10 +96,9 @@ class XmlDriver extends FileDriver
if (isset($xmlRoot->{'discriminator-column'})) {
$discrColumn = $xmlRoot->{'discriminator-column'};
$metadata->setDiscriminatorColumn(array(
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
'columnDefinition' => isset($discrColumn['column-definition']) ? (string)$discrColumn['column-definition'] : null
'name' => (string)$discrColumn['name'],
'type' => (string)$discrColumn['type'],
'length' => (string)$discrColumn['length']
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
@@ -168,7 +107,7 @@ class XmlDriver extends FileDriver
// Evaluate <discriminator-map...>
if (isset($xmlRoot->{'discriminator-map'})) {
$map = array();
foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} AS $discrMapElement) {
$map[(string)$discrMapElement['value']] = (string)$discrMapElement['class'];
}
$metadata->setDiscriminatorMap($map);
@@ -219,64 +158,72 @@ class XmlDriver extends FileDriver
}
}
if (isset($xmlRoot->options)) {
$metadata->table['options'] = $this->_parseOptions($xmlRoot->options->children());
}
// The mapping assignement is done in 2 times as a bug might occurs on some php/xml lib versions
// The internal SimpleXmlIterator get resetted, to this generate a duplicate field exception
$mappings = array();
// Evaluate <field ...> mappings
if (isset($xmlRoot->field)) {
foreach ($xmlRoot->field as $fieldMapping) {
$mapping = $this->columnToArray($fieldMapping);
$mapping = array(
'fieldName' => (string)$fieldMapping['name'],
'type' => (string)$fieldMapping['type']
);
if (isset($mapping['version'])) {
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string)$fieldMapping['column'];
}
if (isset($fieldMapping['length'])) {
$mapping['length'] = (int)$fieldMapping['length'];
}
if (isset($fieldMapping['precision'])) {
$mapping['precision'] = (int)$fieldMapping['precision'];
}
if (isset($fieldMapping['scale'])) {
$mapping['scale'] = (int)$fieldMapping['scale'];
}
if (isset($fieldMapping['unique'])) {
$mapping['unique'] = ((string)$fieldMapping['unique'] == "false") ? false : true;
}
if (isset($fieldMapping['options'])) {
$mapping['options'] = (array)$fieldMapping['options'];
}
if (isset($fieldMapping['nullable'])) {
$mapping['nullable'] = ((string)$fieldMapping['nullable'] == "false") ? false : true;
}
if (isset($fieldMapping['version']) && $fieldMapping['version']) {
$metadata->setVersionMapping($mapping);
unset($mapping['version']);
}
if (isset($fieldMapping['column-definition'])) {
$mapping['columnDefinition'] = (string)$fieldMapping['column-definition'];
}
$metadata->mapField($mapping);
}
}
foreach ($mappings as $mapping) {
if (isset($mapping['version'])) {
$metadata->setVersionMapping($mapping);
}
$metadata->mapField($mapping);
}
// Evaluate <id ...> mappings
$associationIds = array();
foreach ($xmlRoot->id as $idElement) {
if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) {
$associationIds[(string)$idElement['name']] = true;
if ((bool)$idElement['association-key'] == 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['length'])) {
$mapping['length'] = (string)$idElement['length'];
}
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)) {
@@ -294,11 +241,6 @@ class XmlDriver extends FileDriver
'allocationSize' => (string)$seqGenerator['allocation-size'],
'initialValue' => (string)$seqGenerator['initial-value']
));
} else if (isset($idElement->{'custom-id-generator'})) {
$customGenerator = $idElement->{'custom-id-generator'};
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement->{'table-generator'})) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}
@@ -329,10 +271,10 @@ class XmlDriver extends FileDriver
$joinColumns = array();
if (isset($oneToOneElement->{'join-column'})) {
$joinColumns[] = $this->joinColumnToArray($oneToOneElement->{'join-column'});
$joinColumns[] = $this->_getJoinColumnMapping($oneToOneElement->{'join-column'});
} else if (isset($oneToOneElement->{'join-columns'})) {
foreach ($oneToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
}
@@ -344,7 +286,7 @@ class XmlDriver extends FileDriver
}
if (isset($oneToOneElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($oneToOneElement['orphan-removal']);
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphan-removal'];
}
$metadata->mapOneToOne($mapping);
@@ -369,21 +311,19 @@ class XmlDriver extends FileDriver
}
if (isset($oneToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphan-removal'];
}
if (isset($oneToManyElement->{'order-by'})) {
$orderBy = array();
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) {
$orderBy[(string)$orderByField['name']] = (string)$orderByField['direction'];
}
$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);
@@ -413,10 +353,10 @@ class XmlDriver extends FileDriver
$joinColumns = array();
if (isset($manyToOneElement->{'join-column'})) {
$joinColumns[] = $this->joinColumnToArray($manyToOneElement->{'join-column'});
$joinColumns[] = $this->_getJoinColumnMapping($manyToOneElement->{'join-column'});
} else if (isset($manyToOneElement->{'join-columns'})) {
foreach ($manyToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
}
@@ -426,6 +366,10 @@ class XmlDriver extends FileDriver
$mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
}
if (isset($manyToOneElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement->{'orphan-removal'};
}
$metadata->mapManyToOne($mapping);
}
}
@@ -442,10 +386,6 @@ class XmlDriver extends FileDriver
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
}
if (isset($manyToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = $this->evaluateBoolean($manyToManyElement['orphan-removal']);
}
if (isset($manyToManyElement['mapped-by'])) {
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
} else if (isset($manyToManyElement->{'join-table'})) {
@@ -463,11 +403,11 @@ class XmlDriver extends FileDriver
}
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
$joinTable['joinColumns'][] = $this->_getJoinColumnMapping($joinColumnElement);
}
foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
$joinTable['inverseJoinColumns'][] = $this->_getJoinColumnMapping($joinColumnElement);
}
$mapping['joinTable'] = $joinTable;
@@ -477,80 +417,26 @@ class XmlDriver extends FileDriver
$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) {
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) {
$orderBy[(string)$orderByField['name']] = (string)$orderByField['direction'];
}
$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);
}
}
// Evaluate association-overrides
if (isset($xmlRoot->{'attribute-overrides'})) {
foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) {
$fieldName = (string) $overrideElement['name'];
foreach ($overrideElement->field as $field) {
$mapping = $this->columnToArray($field);
$mapping['fieldName'] = $fieldName;
$metadata->setAttributeOverride($fieldName, $mapping);
}
}
}
// Evaluate association-overrides
if (isset($xmlRoot->{'association-overrides'})) {
foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) {
$fieldName = (string) $overrideElement['name'];
$override = array();
// Check for join-columns
if (isset($overrideElement->{'join-columns'})) {
$joinColumns = array();
foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinColumns'] = $joinColumns;
}
// Check for join-table
if ($overrideElement->{'join-table'}) {
$joinTable = null;
$joinTableElement = $overrideElement->{'join-table'};
$joinTable = array(
'name' => (string) $joinTableElement['name'],
'schema' => (string) $joinTableElement['schema']
);
if (isset($joinTableElement->{'join-columns'})) {
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
if (isset($joinTableElement->{'inverse-join-columns'})) {
foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate <lifecycle-callbacks...>
if (isset($xmlRoot->{'lifecycle-callbacks'})) {
foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
@@ -559,44 +445,14 @@ class XmlDriver extends FileDriver
}
}
/**
* Parses (nested) option elements.
*
* @param SimpleXMLElement $options the XML element.
* @return array The options array.
*/
private function _parseOptions(SimpleXMLElement $options)
{
$array = array();
/* @var $option SimpleXMLElement */
foreach ($options as $option) {
if ($option->count()) {
$value = $this->_parseOptions($option->children());
} else {
$value = (string) $option;
}
$attr = $option->attributes();
if (isset($attr->name)) {
$array[(string) $attr->name] = $value;
} else {
$array[] = $value;
}
}
return $array;
}
/**
* Constructs a joinColumn mapping array based on the information
* found in the given SimpleXMLElement.
*
* @param SimpleXMLElement $joinColumnElement the XML element.
* @param $joinColumnElement The XML element.
* @return array The mapping array.
*/
private function joinColumnToArray(SimpleXMLElement $joinColumnElement)
private function _getJoinColumnMapping(SimpleXMLElement $joinColumnElement)
{
$joinColumn = array(
'name' => (string)$joinColumnElement['name'],
@@ -604,17 +460,21 @@ class XmlDriver extends FileDriver
);
if (isset($joinColumnElement['unique'])) {
$joinColumn['unique'] = $this->evaluateBoolean($joinColumnElement['unique']);
$joinColumn['unique'] = ((string)$joinColumnElement['unique'] == "false") ? false : true;
}
if (isset($joinColumnElement['nullable'])) {
$joinColumn['nullable'] = $this->evaluateBoolean($joinColumnElement['nullable']);
$joinColumn['nullable'] = ((string)$joinColumnElement['nullable'] == "false") ? false : true;
}
if (isset($joinColumnElement['on-delete'])) {
$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'];
}
@@ -622,71 +482,15 @@ class XmlDriver extends FileDriver
return $joinColumn;
}
/**
* Parse the given field as array
*
* @param SimpleXMLElement $fieldMapping
* @return array
*/
private function columnToArray(SimpleXMLElement $fieldMapping)
{
$mapping = array(
'fieldName' => (string) $fieldMapping['name'],
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string) $fieldMapping['type'];
}
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string) $fieldMapping['column'];
}
if (isset($fieldMapping['length'])) {
$mapping['length'] = (int) $fieldMapping['length'];
}
if (isset($fieldMapping['precision'])) {
$mapping['precision'] = (int) $fieldMapping['precision'];
}
if (isset($fieldMapping['scale'])) {
$mapping['scale'] = (int) $fieldMapping['scale'];
}
if (isset($fieldMapping['unique'])) {
$mapping['unique'] = $this->evaluateBoolean($fieldMapping['unique']);
}
if (isset($fieldMapping['nullable'])) {
$mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']);
}
if (isset($fieldMapping['version']) && $fieldMapping['version']) {
$mapping['version'] = $this->evaluateBoolean($fieldMapping['version']);
}
if (isset($fieldMapping['column-definition'])) {
$mapping['columnDefinition'] = (string) $fieldMapping['column-definition'];
}
if (isset($fieldMapping->options)) {
$mapping['options'] = $this->_parseOptions($fieldMapping->options->children());
}
return $mapping;
}
/**
* Gathers a list of cascade options found in the given cascade element.
*
* @param SimpleXMLElement $cascadeElement the cascade element.
* @param $cascadeElement The cascade element.
* @return array The list of cascade options.
*/
private function _getCascadeMappings($cascadeElement)
{
$cascades = array();
/* @var $action SimpleXmlElement */
foreach ($cascadeElement->children() as $action) {
// According to the JPA specifications, XML uses "cascade-persist"
// instead of "persist". Here, both variations
@@ -699,9 +503,9 @@ class XmlDriver extends FileDriver
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
protected function loadMappingFile($file)
protected function _loadMappingFile($file)
{
$result = array();
$xmlElement = simplexml_load_file($file);
@@ -720,12 +524,4 @@ class XmlDriver extends FileDriver
return $result;
}
protected function evaluateBoolean($element)
{
$flag = (string)$element;
return ($flag === true || $flag == "true" || $flag == "1");
}
}

View File

@@ -13,16 +13,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata,
Doctrine\Common\Persistence\Mapping\Driver\FileDriver,
Doctrine\ORM\Mapping\MappingException,
Symfony\Component\Yaml\Yaml;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\MappingException;
/**
* The YamlDriver reads the mapping metadata from yaml schema files.
@@ -33,37 +31,28 @@ use Doctrine\Common\Persistence\Mapping\ClassMetadata,
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class YamlDriver extends FileDriver
class YamlDriver extends AbstractFileDriver
{
const DEFAULT_FILE_EXTENSION = '.dcm.yml';
/**
* {@inheritdoc}
*/
protected $_fileExtension = '.dcm.yml';
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
parent::__construct($locator, $fileExtension);
}
/**
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
$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);
@@ -91,68 +80,6 @@ class YamlDriver extends FileDriver
}
}
// Evaluate named native queries
if (isset($element['namedNativeQueries'])) {
foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
if (!isset($mappingElement['name'])) {
$mappingElement['name'] = $name;
}
$metadata->addNamedNativeQuery(array(
'name' => $mappingElement['name'],
'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null,
'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null,
'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null,
));
}
}
// Evaluate sql result set mappings
if (isset($element['sqlResultSetMappings'])) {
foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
if (!isset($resultSetMapping['name'])) {
$resultSetMapping['name'] = $name;
}
$entities = array();
$columns = array();
if (isset($resultSetMapping['entityResult'])) {
foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
$entityResult = array(
'fields' => array(),
'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null,
'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null,
);
if (isset($entityResultElement['fieldResult'])) {
foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
$entityResult['fields'][] = array(
'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null,
'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null,
);
}
}
$entities[] = $entityResult;
}
}
if (isset($resultSetMapping['columnResult'])) {
foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
$columns[] = array(
'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null,
);
}
}
$metadata->addSqlResultSetMapping(array(
'name' => $resultSetMapping['name'],
'entities' => $entities,
'columns' => $columns
));
}
}
/* not implemented specially anyway. use table = schema.table
if (isset($element['schema'])) {
$metadata->table['schema'] = $element['schema'];
@@ -166,10 +93,9 @@ class YamlDriver extends FileDriver
if (isset($element['discriminatorColumn'])) {
$discrColumn = $element['discriminatorColumn'];
$metadata->setDiscriminatorColumn(array(
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null
'name' => $discrColumn['name'],
'type' => $discrColumn['type'],
'length' => $discrColumn['length']
));
} else {
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
@@ -198,7 +124,6 @@ class YamlDriver extends FileDriver
if (is_string($index['columns'])) {
$columns = explode(',', $index['columns']);
$columns = array_map('trim', $columns);
} else {
$columns = $index['columns'];
}
@@ -218,7 +143,6 @@ class YamlDriver extends FileDriver
if (is_string($unique['columns'])) {
$columns = explode(',', $unique['columns']);
$columns = array_map('trim', $columns);
} else {
$columns = $unique['columns'];
}
@@ -229,10 +153,6 @@ class YamlDriver extends FileDriver
}
}
if (isset($element['options'])) {
$metadata->table['options'] = $element['options'];
}
$associationIds = array();
if (isset($element['id'])) {
// Evaluate identifier settings
@@ -242,15 +162,16 @@ class YamlDriver extends FileDriver
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'];
}
@@ -259,10 +180,6 @@ class YamlDriver extends FileDriver
$mapping['length'] = $idElement['length'];
}
if (isset($idElement['columnDefinition'])) {
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {
@@ -272,11 +189,6 @@ class YamlDriver extends FileDriver
// Check for SequenceGenerator/TableGenerator definition
if (isset($idElement['sequenceGenerator'])) {
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
} else if (isset($idElement['customIdGenerator'])) {
$customGenerator = $idElement['customIdGenerator'];
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement['tableGenerator'])) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}
@@ -286,9 +198,19 @@ class YamlDriver extends FileDriver
// Evaluate fields
if (isset($element['fields'])) {
foreach ($element['fields'] as $name => $fieldMapping) {
if (!isset($fieldMapping['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$mapping = $this->columnToArray($name, $fieldMapping);
$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'])) {
@@ -296,10 +218,32 @@ class YamlDriver extends FileDriver
. strtoupper($fieldMapping['generator']['strategy'])));
}
}
if (isset($mapping['version'])) {
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = $fieldMapping['column'];
}
if (isset($fieldMapping['length'])) {
$mapping['length'] = $fieldMapping['length'];
}
if (isset($fieldMapping['precision'])) {
$mapping['precision'] = $fieldMapping['precision'];
}
if (isset($fieldMapping['scale'])) {
$mapping['scale'] = $fieldMapping['scale'];
}
if (isset($fieldMapping['unique'])) {
$mapping['unique'] = (bool)$fieldMapping['unique'];
}
if (isset($fieldMapping['options'])) {
$mapping['options'] = $fieldMapping['options'];
}
if (isset($fieldMapping['nullable'])) {
$mapping['nullable'] = $fieldMapping['nullable'];
}
if (isset($fieldMapping['version']) && $fieldMapping['version']) {
$metadata->setVersionMapping($mapping);
unset($mapping['version']);
}
if (isset($fieldMapping['columnDefinition'])) {
$mapping['columnDefinition'] = $fieldMapping['columnDefinition'];
}
$metadata->mapField($mapping);
@@ -332,14 +276,14 @@ class YamlDriver extends FileDriver
$joinColumns = array();
if (isset($oneToOneElement['joinColumn'])) {
$joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']);
$joinColumns[] = $this->_getJoinColumnMapping($oneToOneElement['joinColumn']);
} else if (isset($oneToOneElement['joinColumns'])) {
foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
foreach ($oneToOneElement['joinColumns'] as $name => $joinColumnElement) {
if (!isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
}
@@ -414,14 +358,14 @@ class YamlDriver extends FileDriver
$joinColumns = array();
if (isset($manyToOneElement['joinColumn'])) {
$joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']);
$joinColumns[] = $this->_getJoinColumnMapping($manyToOneElement['joinColumn']);
} else if (isset($manyToOneElement['joinColumns'])) {
foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
foreach ($manyToOneElement['joinColumns'] as $name => $joinColumnElement) {
if (!isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
}
@@ -431,6 +375,10 @@ class YamlDriver extends FileDriver
$mapping['cascade'] = $manyToOneElement['cascade'];
}
if (isset($manyToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement['orphanRemoval'];
}
$metadata->mapManyToOne($mapping);
}
}
@@ -450,6 +398,9 @@ class YamlDriver extends FileDriver
if (isset($manyToManyElement['mappedBy'])) {
$mapping['mappedBy'] = $manyToManyElement['mappedBy'];
} else if (isset($manyToManyElement['joinTable'])) {
if (isset($manyToManyElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
}
$joinTableElement = $manyToManyElement['joinTable'];
$joinTable = array(
@@ -460,33 +411,33 @@ class YamlDriver extends FileDriver
$joinTable['schema'] = $joinTableElement['schema'];
}
foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
if (!isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
$joinTable['joinColumns'][] = $this->_getJoinColumnMapping($joinColumnElement);
}
foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $joinColumnName;
foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
if (!isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
$joinTable['inverseJoinColumns'][] = $this->_getJoinColumnMapping($joinColumnElement);
}
$mapping['joinTable'] = $joinTable;
}
if (isset($manyToManyElement['inversedBy'])) {
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
}
if (isset($manyToManyElement['cascade'])) {
$mapping['cascade'] = $manyToManyElement['cascade'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
if (isset($manyToManyElement['orderBy'])) {
$mapping['orderBy'] = $manyToManyElement['orderBy'];
}
@@ -495,76 +446,10 @@ class YamlDriver extends FileDriver
$mapping['indexBy'] = $manyToManyElement['indexBy'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
$metadata->mapManyToMany($mapping);
}
}
// Evaluate associationOverride
if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
$override = array();
// Check for joinColumn
if (isset($associationOverrideElement['joinColumn'])) {
$joinColumns = array();
foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinColumns'] = $joinColumns;
}
// Check for joinTable
if (isset($associationOverrideElement['joinTable'])) {
$joinTableElement = $associationOverrideElement['joinTable'];
$joinTable = array(
'name' => $joinTableElement['name']
);
if (isset($joinTableElement['schema'])) {
$joinTable['schema'] = $joinTableElement['schema'];
}
foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
if ( ! isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
}
$override['joinTable'] = $joinTable;
}
$metadata->setAssociationOverride($fieldName, $override);
}
}
// Evaluate associationOverride
if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
$mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
$metadata->setAttributeOverride($fieldName, $mapping);
}
}
// Evaluate lifeCycleCallbacks
if (isset($element['lifecycleCallbacks'])) {
foreach ($element['lifecycleCallbacks'] as $type => $methods) {
@@ -579,19 +464,15 @@ class YamlDriver extends FileDriver
* Constructs a joinColumn mapping array based on the information
* found in the given join column element.
*
* @param array $joinColumnElement The array join column element
* @param $joinColumnElement The array join column element
* @return array The mapping array.
*/
private function joinColumnToArray($joinColumnElement)
private function _getJoinColumnMapping($joinColumnElement)
{
$joinColumn = array();
if (isset($joinColumnElement['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
}
if (isset($joinColumnElement['name'])) {
$joinColumn['name'] = (string) $joinColumnElement['name'];
}
$joinColumn = array(
'name' => $joinColumnElement['name'],
'referencedColumnName' => $joinColumnElement['referencedColumnName']
);
if (isset($joinColumnElement['fieldName'])) {
$joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
@@ -609,6 +490,10 @@ class YamlDriver extends FileDriver
$joinColumn['onDelete'] = $joinColumnElement['onDelete'];
}
if (isset($joinColumnElement['onUpdate'])) {
$joinColumn['onUpdate'] = $joinColumnElement['onUpdate'];
}
if (isset($joinColumnElement['columnDefinition'])) {
$joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
}
@@ -617,72 +502,10 @@ class YamlDriver extends FileDriver
}
/**
* Parse the given column as array
*
* @param string $fieldName
* @param array $column
* @return array
* {@inheritdoc}
*/
private function columnToArray($fieldName, $column)
protected function _loadMappingFile($file)
{
$mapping = array(
'fieldName' => $fieldName
);
if (isset($column['type'])) {
$params = explode('(', $column['type']);
$column['type'] = $params[0];
$mapping['type'] = $column['type'];
if (isset($params[1])) {
$column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1);
}
}
if (isset($column['column'])) {
$mapping['columnName'] = $column['column'];
}
if (isset($column['length'])) {
$mapping['length'] = $column['length'];
}
if (isset($column['precision'])) {
$mapping['precision'] = $column['precision'];
}
if (isset($column['scale'])) {
$mapping['scale'] = $column['scale'];
}
if (isset($column['unique'])) {
$mapping['unique'] = (bool)$column['unique'];
}
if (isset($column['options'])) {
$mapping['options'] = $column['options'];
}
if (isset($column['nullable'])) {
$mapping['nullable'] = $column['nullable'];
}
if (isset($column['version']) && $column['version']) {
$mapping['version'] = $column['version'];
}
if (isset($column['columnDefinition'])) {
$mapping['columnDefinition'] = $column['columnDefinition'];
}
return $mapping;
}
/**
* {@inheritDoc}
*/
protected function loadMappingFile($file)
{
return Yaml::parse($file);
return \Symfony\Component\Yaml\Yaml::parse($file);
}
}

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 MIT license. 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 MIT license. 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,58 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* References an entity in the SELECT clause of a SQL query.
* If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object.
* This should include foreign key columns to related entities.
* The results obtained when insufficient data is available are undefined.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class EntityResult implements Annotation
{
/**
* The class of the result
*
* @var string
*/
public $entityClass;
/**
* Maps the columns specified in the SELECT list of the query to the properties or fields of the entity class.
*
* @var array<\Doctrine\ORM\Mapping\FieldResult>
*/
public $fields = array();
/**
* Specifies the column name of the column in the SELECT list that is used to determine the type of the entity instance.
*
* @var string
*/
public $discriminatorColumn;
}

View File

@@ -1,48 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to map the columns specified in the SELECT list of the query to the properties or fields of the entity class.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class FieldResult implements Annotation
{
/**
* Name of the column in the SELECT clause.
*
* @var string
*/
public $name;
/**
* Name of the persistent field or property of the class.
*
* @var string
*/
public $column;
}

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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. 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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
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 MIT license. 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 MIT license. 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 MIT license. 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

@@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
@@ -34,18 +34,8 @@ class MappingException extends \Doctrine\ORM\ORMException
public static function identifierRequired($entityName)
{
if (false !== ($parent = get_parent_class($entityName))) {
return new self(sprintf(
'No identifier/primary key specified for Entity "%s" sub class of "%s". Every Entity must have an identifier/primary key.',
$entityName, $parent
));
}
return new self(sprintf(
'No identifier/primary key specified for Entity "%s". Every Entity must have an identifier/primary key.',
$entityName
));
return new self("No identifier/primary key specified for Entity '$entityName'."
. " Every Entity must have an identifier/primary key.");
}
public static function invalidInheritanceType($entityName, $type)
@@ -78,28 +68,6 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No mapping file found named '$fileName' for class '$entityName'.");
}
/**
* Exception for invalid property name override.
*
* @param string $className The entity's name
* @param string $fieldName
*/
public static function invalidOverrideFieldName($className, $fieldName)
{
return new self("Invalid field override named '$fieldName' for class '$className'.");
}
/**
* Exception for invalid property type override.
*
* @param string $className The entity's name
* @param string $fieldName
*/
public static function invalidOverrideFieldType($className, $fieldName)
{
return new self("The column type of attribute '$fieldName' on class '$className' could not be changed.");
}
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' on class '$className'.");
@@ -110,41 +78,6 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No query found named '$queryName' on class '$className'.");
}
public static function resultMappingNotFound($className, $resultName)
{
return new self("No result set mapping found named '$resultName' on class '$className'.");
}
public static function emptyQueryMapping($entity, $queryName)
{
return new self('Query named "'.$queryName.'" in "'.$entity.'" could not be empty.');
}
public static function nameIsMandatoryForQueryMapping($className)
{
return new self("Query name on entity class '$className' is not defined.");
}
public static function missingQueryMapping($entity, $queryName)
{
return new self('Query named "'.$queryName.'" in "'.$entity.' requires a result class or result set mapping.');
}
public static function missingResultSetMappingEntity($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a entity class name.');
}
public static function missingResultSetMappingFieldName($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a field name.');
}
public static function nameIsMandatoryForSqlResultSetMapping($className)
{
return new self("Result set mapping name on entity class '$className' is not defined.");
}
public static function oneToManyRequiresMappedBy($fieldName)
{
return new self("OneToMany mapping on field '$fieldName' requires the 'mappedBy' attribute.");
@@ -206,17 +139,7 @@ class MappingException extends \Doctrine\ORM\ORMException
public static function classIsNotAValidEntityOrMappedSuperClass($className)
{
if (false !== ($parent = get_parent_class($className))) {
return new self(sprintf(
'Class "%s" sub class of "%s" is not a valid entity or mapped super class.',
$className, $parent
));
}
return new self(sprintf(
'Class "%s" is not a valid entity or mapped super class.',
$className
));
return new self('Class '.$className.' is not a valid entity or mapped super class.');
}
public static function propertyTypeIsRequired($className, $propertyName)
@@ -230,36 +153,27 @@ class MappingException extends \Doctrine\ORM\ORMException
}
/**
*
* @param string $entity The entity's name
* @param string $fieldName The name of the field that was already declared
*/
public static function duplicateFieldMapping($entity, $fieldName)
{
public static function duplicateFieldMapping($entity, $fieldName) {
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
public static function duplicateAssociationMapping($entity, $fieldName)
{
public static function duplicateAssociationMapping($entity, $fieldName) {
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
public static function duplicateQueryMapping($entity, $queryName)
{
public static function duplicateQueryMapping($entity, $queryName) {
return new self('Query named "'.$queryName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
public static function duplicateResultSetMapping($entity, $resultName)
{
return new self('Result set mapping named "'.$resultName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
public static function singleIdNotAllowedOnCompositePrimaryKey($entity)
{
public static function singleIdNotAllowedOnCompositePrimaryKey($entity) {
return new self('Single id is not allowed on composite primary key in entity '.$entity);
}
public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType)
{
public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType) {
return new self('Locking type "'.$unsupportedType.'" (specified in "'.$entity.'", field "'.$fieldName.'") '
.'is not supported by Doctrine.'
);
@@ -270,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!'
@@ -285,25 +199,13 @@ class MappingException extends \Doctrine\ORM\ORMException
* @param string $owningClass The class that declares the discriminator map.
* @return self
*/
public static function invalidClassInDiscriminatorMap($className, $owningClass)
{
public static function invalidClassInDiscriminatorMap($className, $owningClass) {
return new self(
"Entity class '$className' used in the discriminator map of class '$owningClass' ".
"does not exist."
);
}
public static function duplicateDiscriminatorEntry($className, array $entries, array $map)
{
return new self(
"The entries " . implode(', ', $entries) . " in discriminator map of class '" . $className . "' is duplicated. " .
"If the discriminator map is automatically generated you have to convert it to an explicit discriminator map now. " .
"The entries of the current map are: @DiscriminatorMap({" . implode(', ', array_map(
function($a, $b) { return "'$a': '$b'"; }, array_keys($map), array_values($map)
)) . "})"
);
}
public static function missingDiscriminatorMap($className)
{
return new self("Entity class '$className' is using inheritance but no discriminator map was defined.");
@@ -319,21 +221,11 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("Discriminator column type on entity class '$className' is not allowed to be '$type'. 'string' or 'integer' type variables are suggested!");
}
public static function nameIsMandatoryForDiscriminatorColumns($className)
{
return new self("Discriminator column name on entity class '$className' is not defined.");
}
public static function cannotVersionIdField($className, $fieldName)
{
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
@@ -378,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'.");
@@ -393,49 +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."'.");
}
public static function invalidCascadeOption(array $cascades, $className, $propertyName)
{
$cascades = implode(", ", array_map(function ($e) { return "'" . $e . "'"; }, $cascades));
return new self(sprintf(
"You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'",
$className,
$propertyName,
$cascades
));
}
}
}

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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to specify an array of native SQL named queries.
* The NamedNativeQueries annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("CLASS")
*/
final class NamedNativeQueries implements Annotation
{
/**
* One or more NamedNativeQuery annotations.
*
* @var array<\Doctrine\ORM\Mapping\NamedNativeQuery>
*/
public $value = array();
}

View File

@@ -1,63 +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 MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Is used to specify a native SQL named query.
* The NamedNativeQuery annotation can be applied to an entity or mapped superclass.
*
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
* @since 2.3
*
* @Annotation
* @Target("ANNOTATION")
*/
final class NamedNativeQuery implements Annotation
{
/**
* The name used to refer to the query with the EntityManager methods that create query objects.
*
* @var string
*/
public $name;
/**
* The SQL query string.
*
* @var string
*/
public $query;
/**
* The class of the result.
*
* @var string
*/
public $resultClass;
/**
* The name of a SqlResultSetMapping, as defined in metadata.
*
* @var string
*/
public $resultSetMapping;
}

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 MIT license. 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 MIT license. 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;
}

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