Compare commits

..

680 Commits

Author SHA1 Message Date
Benjamin Eberlei d679154fba Release 2.2.0 2012-01-29 17:04:23 +01:00
Benjamin Eberlei 7cf4337dc1 Bump and bind dependencies of ORM 2.2 2012-01-29 15:22:06 +01:00
Benjamin Eberlei 41cf2ce4b1 Fix test for non-mysql like datetimes. 2012-01-29 15:01:36 +01:00
Benjamin Eberlei 13b8d05def Bump dependencies to release versions. 2012-01-29 13:12:25 +01:00
Benjamin Eberlei 209d098672 Fix Oracle Tests 2012-01-29 13:09:51 +01:00
Benjamin Eberlei 53600484cd Merge branch 'DDC-1526' into 2.2 2012-01-28 12:26:54 +01:00
Benjamin Eberlei ac25d62a24 [DDC-1526] Collections are not marked as initialized when they are fetch joined but dont contain any results. This only occurs when using LEFT JOINs on the assocations and causes another query to be fired when the empty collection is accessed again. 2012-01-28 12:26:25 +01:00
Benjamin Eberlei f7936bda70 Merge branch 'DDC-1617' into 2.2 2012-01-28 11:17:08 +01:00
Benjamin Eberlei 78899cedac [DDC-1617] Implement support for Generating Unique Constraints/Indexes in @Table annotation of EntityGenerator. 2012-01-28 11:16:58 +01:00
Benjamin Eberlei 73fef2867f Merge remote-tracking branch 'origin/2.2' into 2.2 2012-01-25 23:29:44 +01:00
armetiz c883ff2644 Update lib/Doctrine/ORM/Tools/SchemaTool.php 2012-01-25 22:06:37 +01:00
Benjamin Eberlei 7595025f26 Merge branch 'DDC-1619' into 2.2 2012-01-25 10:26:42 +01:00
Benjamin Eberlei 8fb6f986dd [DDC-1619] Add QueryBuilder#distinct 2012-01-25 10:25:38 +01:00
Benjamin Eberlei 6dbb368995 Merge branch 'DDC-1618' into 2.2 2012-01-25 00:02:44 +01:00
Thomas Rabaix c39ad9250a Add SqlWalker::HINT_DISTINCT constant 2012-01-25 00:02:16 +01:00
Thomas Rabaix 8adc267d87 Fix DDC-1618 - add more check before throwing an iterateWithFetchJoinNotAllowed exception 2012-01-25 00:02:16 +01:00
Benjamin Eberlei 2a8dd72b33 Bump dev version to 2.2.0 2012-01-22 17:54:32 +01:00
Benjamin Eberlei e44289dbdb Release 2.2.0-RC1 2012-01-22 17:54:32 +01:00
Benjamin Eberlei dbf1c4cdb9 Bump DBAL to 2.2.0-RC3 2012-01-22 17:54:23 +01:00
Benjamin Eberlei aa0c89e45e Fix MySqlSchemaTest failing with current DBAL adjustments. 2012-01-22 17:30:28 +01:00
Benjamin Eberlei f77a1c2c8b Merge branch 'DDC-1613' into 2.2 2012-01-22 13:36:07 +01:00
Benjamin Eberlei ab1835a9db [DDC-1613] Merge KnpLabs/Pagerfanta Pagination into a Doctrine\ORM\Tools\Pagination namespace. Thanks to @hobodave, pablo and the knplabs team for developing and maintaining this code. 2012-01-22 13:35:45 +01:00
Benjamin Eberlei e5950d5fe9 Merge branch 'DDC-1603' into 2.2 2012-01-21 15:36:17 +01:00
armetiz 41f41d2bd8 Unique key name isn't correctly set - DDC-1603 2012-01-21 15:35:54 +01:00
Benjamin Eberlei da47aa3ea2 Merge branch 'DDC-1610' into 2.2 2012-01-21 13:58:52 +01:00
Benjamin Eberlei 2f976ea03a [DDC-1610] Add test and fix wakeup reflection in combination with event listener 2012-01-21 13:58:44 +01:00
Benjamin Eberlei e10d865b01 Merge branch 'DDC-1612' into 2.2 2012-01-21 13:07:00 +01:00
Benjamin Eberlei d91e633eff [DDC-1612] Fix bug with EntityManager#flush($entity) on new entities. 2012-01-21 13:06:53 +01:00
Benjamin Eberlei 845d152604 Merge branch 'DBAL-204' into 2.2 2012-01-21 11:30:10 +01:00
Benjamin Eberlei 01eb894c4e [DBAL-204] Filter namespaced assets if Schemas/Emulation is not supported. 2012-01-21 11:29:48 +01:00
Benjamin Eberlei d668d50ca4 DDC-742 - Flush Memcache, otherwise fail. 2012-01-18 21:31:49 +01:00
Benjamin Eberlei cecfac5222 Merge branch 'DDC-1608' into 2.2 2012-01-18 20:15:26 +01:00
Guilherme Blanco d391e28ffb Fixed DDC-1608. Non-initialized PersistentCollection methods removeElement and contains now deal correctly with managed entities. 2012-01-18 20:11:37 +01:00
Daniel Holmes f94b405f6e Updated some comparisons to strict equality 2012-01-18 20:11:37 +01:00
Daniel Holmes be6890e5aa Added fix for collection->contains when many-to-many extra lazy fetchMode 2012-01-18 20:11:37 +01:00
Guilherme Blanco 286eef1ca3 Fixes DDC-1596. Added table alias to discriminator column when using STI. 2012-01-16 14:09:29 +01:00
Guilherme Blanco 0aecff7f71 Added coverage to DDC-1595 and DDC-1596. 2012-01-16 14:01:57 +01:00
Guilherme Blanco c73dae141f Fixed DDC-657. Added type conversion to scalar result. 2012-01-16 14:01:48 +01:00
Benjamin Eberlei d535e1c2bc Merge branch 'DDC-1604' into 2.2 2012-01-16 12:52:22 +01:00
Benjamin Eberlei f6d41ad9ce [DDC-1604] Have ORM Proxy implement new \Doctrine\Common\Persistence\Proxy
* Adjust ProxyFactory to generate proxies according to new naming schema.
* Change proxy naming and file-name generation to be a bit more consistent than previous approach.

[DDC-1598] Additional regexp to check for simple ID methods to make it even more safe.
2012-01-16 12:51:55 +01:00
Benjamin Eberlei 60de86e678 Fix 2.2 composer.json to have common and dbal versions correctly 2012-01-15 21:59:52 +01:00
jsor a37aabb11f Pass options attribute in @Column annotation to Schema\Column's customSchemaOptions 2012-01-15 18:07:41 +01:00
Benjamin Eberlei 789ce1604f Merge branch 'DDC-1594' into 2.2 2012-01-15 17:44:53 +01:00
Benjamin Eberlei e058b47966 DDC-1594 - Fix problem with merge and an existing managed proxy instance. 2012-01-15 17:43:00 +01:00
Benjamin Eberlei 7d77373a71 Merge branch 'DDC-1585' into 2.2 2012-01-15 14:59:48 +01:00
Benjamin Eberlei b6896a04e5 DDC-1585 - Throw exception if setting target entity of the wrong type to an assocation. 2012-01-15 14:59:40 +01:00
Benjamin Eberlei 45fbc058a9 Merge remote-tracking branch 'origin/2.2' into 2.2 2012-01-15 12:15:17 +01:00
Benjamin Eberlei 1574d482fe Merge branch 'DDC-1601' into 2.2 2012-01-15 12:12:51 +01:00
Benjamin Eberlei fb85cdfce0 [DDC-1601] Fix failing test and remove unused code 2012-01-15 12:12:40 +01:00
Benjamin Eberlei 0b6b87912c [DDC-1601] Fix bugs in SchemaValidator, using all modelsets as testdata for a large test 2012-01-15 12:12:40 +01:00
Benjamin Eberlei 212e1d6df6 Fix notice when using regenerate if exists and file is not new. 2012-01-12 11:21:11 +01:00
Benjamin Eberlei 41ae873048 DDC-1588 - Improve ResultCache API. The default cache impl is passed to new query cache profiles automatically now. 2012-01-09 08:26:07 +01:00
Benjamin Eberlei 0014afe746 Fix Typo 2012-01-09 08:04:21 +01:00
Benjamin Eberlei e16803de61 [doctrine/common-GH-92] Fixing notice when annotation driver is used in combination with static reflection. 2012-01-09 08:02:53 +01:00
Benjamin Eberlei d34c39555d Bump dev version to 2.2.0 2012-01-03 22:27:03 +01:00
Benjamin Eberlei 8d3d604ed3 Release 2.2.0-BETA2 2012-01-03 22:27:03 +01:00
Benjamin Eberlei 4deeb23af0 Update dependencies 2012-01-03 21:56:04 +01:00
Benjamin Eberlei 133232eb6b Merge pull request #249 from doctrine/DCOM-93
[DCOM-93] Remove Reflection dependency from ClassMetadata
2012-01-03 10:12:03 -08:00
Benjamin Eberlei ef8703e3e9 DCOM-93 - Allow to check testsuite with any constructor-less cache implementation 2012-01-03 19:01:53 +01:00
Benjamin Eberlei a07fc515c7 DCOM-93 - Fix docblocks 2012-01-03 18:41:48 +01:00
Benjamin Eberlei 76e4f5a80b DCOM-93 - Removed reflection dependency from ClassMetadata completly, moving all the code into ClassMetadataInfo for BC reasons. 2012-01-02 21:32:18 +01:00
Benjamin Eberlei c7d8c9f34e DCOM-93 - Factor out ClassMetadata constructor into delegate method initializeReflection 2012-01-02 17:06:22 +01:00
Benjamin Eberlei 1cecc9c429 DCOM-93 - Factor out __wakeup into a delegate-method from ClassMetadataFactory#wakeupReflection to ClassMetadataInfo#wakeupReflection 2012-01-02 15:57:32 +01:00
Benjamin Eberlei ea2d4e4282 DCOM-93 - Add ClassMetadataFactory#wakeupReflection implementation 2012-01-02 15:46:20 +01:00
Benjamin Eberlei 80408ac34f DCOM-93 - Add empty initialize and wakeup methods. 2012-01-02 15:36:36 +01:00
Benjamin Eberlei 9bdf9a9904 DCOM-93 - Adjust ClassMetadataFactory#getClassParents() to use reflection service. 2012-01-02 15:30:25 +01:00
Benjamin Eberlei 239ffe468a Merge pull request #237 from asm89/ddc-551-collections-filters
[DDC-551] Support for inheritance with filters in lazy collections
2012-01-02 06:11:34 -08:00
Benjamin Eberlei 87e0c69381 Merge remote-tracking branch 'origin/2.2' into 2.2 2011-12-28 20:29:53 +01:00
Benjamin Eberlei a6deb51a05 DDC-1360 - Bugfix in quoting mechanism inside ClassMetadataInfo 2011-12-28 20:29:01 +01:00
holtkamp 21cfe4ba9f Allow ExporterDrivers that implement the exportClassMetadata() function to return FALSE when no content is available/needs to be written to a file by the AbstractExporter, preventing empty files to be generated foreach processed ClassMetadataInfo instance. 2011-12-28 09:03:00 +01:00
Adrien BRAULT bd49aa5d2c Fix some PHPDoc @return type. 2011-12-28 08:50:17 +01:00
Alexander 4cf5f70bea Update test 2011-12-22 23:21:56 +01:00
Alexander c3c174512a Added tests for OneToMany associations and lazy collection to CTI entity 2011-12-22 21:10:13 +01:00
Alexander f49a4e9c40 Added tests for OneToMany associations and lazy collection to STI entity 2011-12-22 20:50:57 +01:00
Alexander 223c47069e Added tests for ManyToMany associations and lazy collection to CTI entity 2011-12-22 17:49:57 +01:00
Alexander 62be27b295 Added tests for ManyToMany associations and lazy collection to STI entity 2011-12-22 00:25:21 +01:00
Benjamin Eberlei b91689fe2f Update common with fix on interface detection 2011-12-21 23:57:33 +01:00
Benjamin Eberlei f6f2acad4c Merge Improve Error Messages into 2.2 2011-12-21 23:56:25 +01:00
Benjamin Eberlei ca470d8ba7 Fix glitch in Version produced by build-script 2011-12-21 00:00:43 +01:00
Benjamin Eberlei 0551ccca92 Bump dev version to 2.2.01 2011-12-20 22:39:27 +01:00
Benjamin Eberlei 6136654dad Release 2.2.0-BETA1 2011-12-20 22:39:27 +01:00
Benjamin Eberlei 9d906fa31e Update build common 2011-12-20 22:39:12 +01:00
Benjamin Eberlei dcaf1b5891 Prepare 2.2 beta 2011-12-20 22:38:38 +01:00
Benjamin Eberlei 9f81d5d077 Fix PEAR path 2011-12-20 21:55:58 +01:00
Alexander d3e697143f Merge pull request #234 from FabioBatSilva/testJoinQueries
Fix QueryTest#testJoinQueries order
2011-12-20 11:25:04 -08:00
Fabio B. Silva e90545cef5 ORDER BY CmsArticle#topic 2011-12-20 17:22:14 -02:00
Fabio B. Silva 0a01b14830 fix QueryTest#testJoinQueries order 2011-12-20 16:14:01 -02:00
Guilherme Blanco 4bc014c696 Merge pull request #233 from FabioBatSilva/DDC-1539
[DDC-1539] Fix DDC-1539
2011-12-20 08:36:18 -08:00
Fabio B. Silva e45ebbac46 remove white spaces 2011-12-20 10:40:29 -02:00
Fabio B. Silva 24dc74a800 Fixed DDC-1539 2011-12-20 10:31:00 -02:00
Guilherme Blanco 772f58a95b Removed test since I'm unable to test now. 2011-12-20 00:48:19 -05:00
Guilherme Blanco f6eb83705a Added coverage to DDC-1521. Small CS changes. 2011-12-20 00:05:14 -05:00
Benjamin Eberlei 6c4aaab2d6 Merge branch 'TrailingWhitespaces' 2011-12-19 22:56:52 +01:00
Benjamin Eberlei cd6131c9b8 Remove all trailing whitespaces 2011-12-19 22:56:19 +01:00
Benjamin Eberlei f2d8102bbf Fix bug in test, removed an assertion that is not necessary and violates sqlites autoincrement assumptions 2011-12-19 22:32:50 +01:00
Benjamin Eberlei 86f67788c5 Merge pull request #231 from FabioBatSilva/tmp2
[DDC 1213]  bit comparison ( BIT_AND() , BIT_OR() )
2011-12-19 11:08:05 -08:00
Fabio B. Silva ea5108ea0f rebase upstream/master 2011-12-19 16:25:31 -02:00
Fabio B. Silva 5c89d7ffcb support for bit comparison 2011-12-19 16:24:16 -02:00
Benjamin Eberlei 568698e321 Add dependency to doctrine-build-common and refactor build.xml and build.properties 2011-12-19 19:16:26 +01:00
Benjamin Eberlei b545525e13 Update ORM to Doctrine Common master 2011-12-19 18:03:53 +01:00
Benjamin Eberlei bf32125bad DDC-1545 - Fix issue with changing values from null to something new.
This issue was introduced by a side-effect in 2.1.3 with
d9f9228d95. In this commit read-only
objects where prevented to be updated. This lead to an invalid check not
being performed in UnitOfWork#computeChangeSet which was present before
where an association that was null would be injected into the
originalEntityData using the UnitOfWork#setOriginalEntityProperty()
method in the AbstractHydrator.

This commit now explicitly sets this field to null using the same API so
that is present during UnitOfWork#computeChangeSet.
2011-12-19 17:55:19 +01:00
Benjamin Eberlei a9035e1533 Merge remote-tracking branch 'origin/master' 2011-12-19 17:11:19 +01:00
Guilherme Blanco 68663fac4b Fixed issue when one to one badly populated when containing null values. Fixed DDC-1548. 2011-12-19 10:55:29 -05:00
Benjamin Eberlei b1b10042d2 Revert "Fixed issue with fetched association not being considered during changeSet calculation. Fixes DDC-1545."
This reverts commit a8478d5766.
2011-12-19 16:31:26 +01:00
Alexander 108cb53eef Merge pull request #229 from bschussek/DDC-1545
DDC-1545
2011-12-19 03:22:49 -08:00
Bernhard Schussek e035fe7949 Fixed class name of test for DDC-1545 2011-12-19 11:20:37 +01:00
Benjamin Eberlei 40800bd3cd DDC-1530 - Validate field types in SchemaValidator 2011-12-19 10:11:11 +01:00
Alexander 4f67ea3869 Merge pull request #228 from asm89/ddc-551-parameter-inference
Fixed testsuite
2011-12-19 01:02:30 -08:00
Alexander 8c6c49a6ee Fixed testsuite 2011-12-19 09:55:49 +01:00
Benjamin Eberlei 7f8f39168a Merge pull request #227 from asm89/ddc-551-parameter-inference
[DDC-551] Add type inference to SQLFilter::setParameter() + cleaned tests
2011-12-19 00:47:58 -08:00
Alexander bd07f8d3dd [DDC-551] Add type inference to SQLFilter::setParameter() + cleaned tests 2011-12-19 08:43:42 +01:00
Guilherme Blanco a8478d5766 Fixed issue with fetched association not being considered during changeSet calculation. Fixes DDC-1545. 2011-12-19 01:39:48 -05:00
Guilherme Blanco f6d9344d89 Merge pull request #219 from FabioBatSilva/DDC-1468
Fixed DDC-1468
2011-12-18 19:20:33 -08:00
Benjamin Eberlei 91e700a70e Merge pull request #226 from asm89/ddc-1505
[DDC-1505] joinColumn "nullable" should be handled true by default
2011-12-18 12:59:49 -08:00
Alexander de769c6c3c [DDC-1505] joinColumn "nullable" should be handled true by default 2011-12-18 21:33:38 +01:00
Benjamin Eberlei 29fabbd81f Merge pull request #225 from asm89/fix-pgsql-testsuite
[DDC-551] Fix testcase on pgsql
2011-12-18 10:59:35 -08:00
Alexander 5160bdc1a8 [DDC-551] Fix testcase on pgsql 2011-12-18 19:58:32 +01:00
Benjamin Eberlei 003d1410b0 Merge pull request #224 from doctrine/DDC-551
DDC-551 - Filter branch
2011-12-18 08:03:23 -08:00
Bernhard Schussek 9b877499c7 Added test case for DDC-1545 2011-12-18 12:13:58 +01:00
Benjamin Eberlei 9cd8f85a8c DDC-1456 - Disallow setting id generators on composite identifiers. 2011-12-18 00:32:35 +01:00
Benjamin Eberlei 072094f722 DDC-1368 - Fix tests 2011-12-17 23:38:39 +01:00
Benjamin Eberlei 170271fd72 DDC-1368 - Improve schema validator 2011-12-17 23:27:39 +01:00
Benjamin Eberlei bb47e90696 Merge pull request #223 from doctrine/DDC-1544
DDC-1544
2011-12-17 14:04:54 -08:00
Benjamin Eberlei 20c859611a Merge pull request #222 from EvanDotPro/DDC-1544
DDC-1544 Unit test / assertions for ResolveTargetEntityListener
2011-12-17 14:03:33 -08:00
Evan Coury 36a47e391c DDC-1544 - Add unit test and assertions for ResolveTargetEntityListener 2011-12-17 15:00:05 -07:00
Benjamin Eberlei 267ce7df88 DDC-1544 - Add ResolveTargetEntityListener 2011-12-17 19:35:10 +01:00
Benjamin Eberlei cfe1259400 DDC-1541 - Fix wrong references in ClassMetadataBuilder 2011-12-17 12:39:44 +01:00
Benjamin Eberlei 6015253064 DDC-1524 - Add validation and error messages for annotation named query code. 2011-12-17 12:35:22 +01:00
Benjamin Eberlei 98bd5cae64 Revert "Incorporated setAssociationTargetClass, which solves biggest problem of modular system in ZF. Any questions, pelase forward to @EvanDotPro."
This reverts commit cac9928f28.
2011-12-17 11:36:23 +01:00
Guilherme Blanco cac9928f28 Incorporated setAssociationTargetClass, which solves biggest problem of modular system in ZF. Any questions, pelase forward to @EvanDotPro. 2011-12-16 16:16:22 -05:00
Benjamin Eberlei cd04cbc7c4 Merge branch 'DDC-1514' 2011-12-15 23:00:13 +01:00
Benjamin Eberlei 5b5fb2b732 DDC-1514 - Fix complex self-referencing + proxy hydration problem. 2011-12-15 23:00:01 +01:00
Benjamin Eberlei e8a47b3921 DDC-1519 - Fix bug in merging of entities that contain foreign identifiers 2011-12-15 20:49:25 +01:00
Fabio B. Silva 017a7d889f Fixed DDC-1468 2011-12-15 17:12:01 -02:00
Guilherme Blanco 41a3d90a57 Merge pull request #214 from yethee/xml_driver
Fixed typo in the XmlDriver
2011-12-13 20:07:43 -08:00
Benjamin Eberlei 99e46a23c6 Bugfix in UnitOfWorklib/Doctrine/ORM/UnitOfWork.phptriggerEagerLoads() 2011-12-13 21:26:04 +01:00
Guilherme Blanco 65c2b498ad Removed broken test. 2011-12-12 23:40:48 -05:00
Benjamin Eberlei f7ede572e0 DDC-1415 - Remove EntityEventDelegatee, the API sucks and we need another approach. 2011-12-12 16:46:53 +01:00
Benjamin Eberlei 43ef8765fd DDC-1527 - Port bugfix for master branch 2011-12-12 16:39:52 +01:00
Benjamin Eberlei bda98150c4 Merge pull request #216 from andrewmackrodt/DDC-1025
DDC-1025 - Absolute Namespace Annotations
2011-12-11 14:32:02 -08:00
Andrew Mackrodt ef12a09ae0 Added remaining absolute namespace paths to phpdoc annotations - issue DDC-1025. 2011-12-11 21:56:27 +00:00
Andrew Mackrodt 2fdb55a878 Added absolute namespace paths to phpdoc annotations - issue DDC-1025. 2011-12-11 21:56:26 +00:00
Benjamin Eberlei b6d776f75d DDC-551 - rework walker filtering 2011-12-11 21:14:09 +01:00
Benjamin Eberlei ad6130b02d DDC-551 - Cleanup filters branch, especially inheritance related code and yoda conditions and some inconsistencies 2011-12-11 19:29:36 +01:00
Benjamin Eberlei ca5dbb182a DDC-551 - Make filters case-sensitive everywhere 2011-12-11 19:27:50 +01:00
Benjamin Eberlei 69b1eb5c64 DDC-551 - Fix locking mess with filters 2011-12-11 18:46:57 +01:00
Benjamin Eberlei 0f501114eb Merge branch 'master' into DDC-551 2011-12-11 18:39:11 +01:00
Benjamin Eberlei f7175c229e DDC-551 - Fix some ugly yoda conditions and a wrong nesting. 2011-12-11 18:39:04 +01:00
Benjamin Eberlei 853a0ee865 Merge branch 'DDC-1515' 2011-12-11 17:09:11 +01:00
Benjamin Eberlei 40d094fea2 DDC-1515 - Now the real bugfix 2011-12-11 17:08:58 +01:00
Benjamin Eberlei f6d2b00d5c DDC-1400 - var_dump(), seriously? 2011-12-11 16:42:59 +01:00
Benjamin Eberlei 57970499fd Revert "DDC-1515 - Merge from 2.1.x"
This reverts commit bd0fb574e3.
2011-12-11 16:11:16 +01:00
Benjamin Eberlei bd0fb574e3 DDC-1515 - Merge from 2.1.x 2011-12-11 16:07:35 +01:00
Deni 2ce9246733 Fixed typo in the XmlDriver 2011-12-11 17:24:38 +04:00
Guilherme Blanco 954b5077e4 Fixed nesting recursion error in some situations. Complement to DDC-1276. 2011-12-09 10:59:53 -05:00
Guilherme Blanco 0febf06114 Made ClassMetadataBuilder support ClassMetadataInfo instead of ClassMetadata. Fixed DDC-1508. 2011-12-09 00:04:47 -05:00
Guilherme Blanco 33c5b639b0 Merge pull request #211 from FabioBatSilva/DDC-1057
DDC-1057
2011-12-07 07:25:45 -08:00
Fabio B. Silva 8e50a31b98 trying remove whitespaces 2011-12-07 12:31:23 -02:00
Fabio B. Silva c6a89c64f3 put return after comment 2011-12-07 12:16:27 -02:00
Fabio B. Silva df19e68a86 Fixed DDC-1057 2011-12-07 11:23:15 -02:00
Alexander 5e91f0c1ca [DDC-551] Update SQLWalker to reflect filter requirements for inheritance 2011-12-07 10:02:15 +01:00
Alexander efe7a01482 [DDC-551] Fixed CS, comments by @stof 2011-12-05 23:00:52 +01:00
Alexander f4663f4512 [DDC-551] Another batch of small refactorings 2011-12-05 22:19:54 +01:00
Alexander e8d30068e2 [DDC-551] Various refactorings 2011-12-05 22:05:42 +01:00
Alexander 04635ad4ff Merge remote-tracking branch 'upstream/master' into DDC-551
Conflicts:
	lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
	lib/Doctrine/ORM/Persisters/OneToManyPersister.php
2011-12-05 21:53:34 +01:00
Guilherme Blanco eaec259186 Merge pull request #209 from FabioBatSilva/DDC1170
DDC-1170
2011-12-05 12:16:39 -08:00
Alexander 3b7d16c60f [DDC-551] General cleanup of the code. 2011-12-05 21:14:31 +01:00
Fabio B. Silva 33c68df3ba Fixed DDC-1170 2011-12-05 17:35:49 -02:00
Alexander 4c842974b4 [DDC-551] Add filters only on root entities in SingleTablePersister 2011-12-05 18:56:44 +01:00
Alexander 752b502326 [DDC-551] Add filters only on root entities in JoinedSubclassPersister 2011-12-05 18:26:56 +01:00
Alexander e98c775f0d Revert "[DDC-551] Initial support for filters in the JoinedSubclassPersister"
This reverts commit f6d5f0481e.
2011-12-05 16:14:04 +01:00
Guilherme Blanco 0380d5ae58 Implemented multiple enhancements in InExpression support for DQL. Fixed DDC-1472 and DDC-1416. 2011-12-04 02:41:54 -05:00
Guilherme Blanco a26990c3e8 DDC-1457: Fixed wrong docblock. 2011-12-04 02:14:47 -05:00
Guilherme Blanco 2f6b930a8d Implemented missing support in CollectionMemberComparison. Removed old todo in ArrayHydrator. Finished implementation of IdentificationVariable in ArithmeticPrimary. 2011-12-03 15:19:21 -05:00
Guilherme Blanco 2642daa438 Fixed DDC-1236: GROUP BY now supports ResultVariable and IdentificationVariable. Composite PK is also supported. If you are willing to group by an aggregate function or a function itself, just place it in SELECT expression then refer to it in the GROUP BY clause. If you are not willing to have the function being part of your resultset, just mark the column as HIDDEN and you are done. 2011-12-01 23:52:35 -05:00
Benjamin Eberlei 619a31913a DDC-1517 - Fix EntityRepository#find() and EntityManager#getReference() breaking on invalid or missing identifiers. 2011-12-01 21:18:39 +01:00
Guilherme Blanco 5e3e8b3957 More refactorings and optimizations. 2011-12-01 10:00:26 -05:00
Alexander bf1cc29a2a [DDC-551] Fixed some comments 2011-12-01 09:46:02 +01:00
Alexander f6d5f0481e [DDC-551] Initial support for filters in the JoinedSubclassPersister
Still some things to do.
2011-11-30 23:01:10 +01:00
Alexander 4c94a7ccc5 [DDC-551] Various minor fixes after merge and cleanup 2011-11-30 16:40:55 +01:00
Guilherme Blanco 5b73f1bd82 Improved code readability. Improved performance. 2011-11-30 09:57:54 -05:00
Guilherme Blanco 356f5874bf Added support to removeElement remove items without initializing the PersistentCollection. 2011-11-29 11:29:17 -05:00
Guilherme Blanco 24f6b74427 Refactored UnitOfWork::createEntity, improving its performance. 2011-11-29 10:36:32 -05:00
Benjamin Eberlei 62ec98a9fc Merge pull request #205 from Seldaek/psr0
PSR-0 compliance
2011-11-28 05:05:50 -08:00
Benjamin Eberlei f2467dd30e Merge branch 'DDC-1512' 2011-11-28 11:16:35 +01:00
Benjamin Eberlei 0c12d3ed5a DDC-1512 - Make ClassMetadataFactory::isTransient() entity namespace aware. 2011-11-28 11:16:23 +01:00
Benjamin Eberlei f2f32ca70f DDC-1509 - Fix regression in doMerge() introduced with the DDC-1383 bugfix 2011-11-28 10:04:33 +01:00
Jordi Boggiano b8ac2fb416 Add requires to new files for BC 2011-11-27 18:16:18 +01:00
Jordi Boggiano 10e74040af PSR-0 compliance 2011-11-27 12:59:17 +01:00
Benjamin Eberlei 2b7360e738 Merge pull request #200 from velovint/StandaloneTestsFailing
Register DoctrineAnnotations on call to OrmTestCase::createAnnotationDri...
2011-11-26 00:17:12 -08:00
Alexander be48821e86 Merge remote-tracking branch 'origin/master' into DDC-551
Conflicts:
	lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
	lib/Doctrine/ORM/Query.php
2011-11-23 22:43:42 +01:00
Alexander 68027e1b5f Merge remote-tracking branch 'upstream/master' 2011-11-23 22:31:17 +01:00
Guilherme Blanco ef33454301 Reverted PR which broke suite. Issue is still valid, but it requires more investigation. 2011-11-23 08:40:47 -05:00
Guilherme Blanco bfcea9460b Merge pull request #202 from realestateconz/master
Fixed array flip breaking discriminator map SQL generation
2011-11-22 18:36:30 -08:00
warezthebeef b80ef58cab Fixed array_flip breaking discriminator map SQL generation 2011-11-23 12:15:23 +13:00
Benjamin Eberlei be4eb63c62 Merge branch 'DBAL-15' 2011-11-21 21:38:05 +01:00
jsor 16aa558292 Remove sql conversion from where clauses and update statements 2011-11-21 15:08:36 +01:00
Benjamin Eberlei 135e515e7f DDC-1500 - Fix potential security problem in EntityRepository ORDER BY orientations 2011-11-21 15:04:46 +01:00
Guilherme Blanco 7ca43b72c9 Merge pull request #201 from jonathaningram/patch-1
Fixed typo
2011-11-21 05:16:40 -08:00
Jonathan Ingram 248c9bdeff Fixed typo 2011-11-21 12:34:20 +11:00
Jan Sorgalla 4042bc53ce Fix argument on wrong method call 2011-11-20 19:57:04 +01:00
Jan Sorgalla 841d12e9b6 Move check for conversion SQL to ClassMetadataInfo 2011-11-20 19:50:51 +01:00
Vitali 507c8f45b4 Register DoctrineAnnotations on call to OrmTestCase::createAnnotationDriver() 2011-11-20 17:02:15 +03:00
Benjamin Eberlei bda593a66d DDC-1448 - Add support for ObjectManagerAware interface and PersistentObject in ORM 2011-11-19 13:06:24 +01:00
Benjamin Eberlei 8eaf160ead Update Doctrine Common Vendor 2011-11-19 09:29:32 +01:00
Benjamin Eberlei 53b3030aa2 Clarify EntityManager#transactional() docblock 2011-11-19 08:58:58 +01:00
Benjamin Eberlei dc0a03ab30 DDC-1400 working testcase 2011-11-19 08:50:49 +01:00
Jan Sorgalla 6f35679911 Initial implementation of Doctrine\DBAL\Types\Type::convertToDatabaseValueSQL() and Doctrine\DBAL\Types\Type::convertToPHPValueSQL() integration 2011-11-19 00:35:29 +01:00
Benjamin Eberlei f9a4dcb2d0 Remove code that could allow users of xml and yaml to define orphan removal on the wrong association sides. 2011-11-18 18:33:03 +01:00
Benjamin Eberlei a0d6d84a4f Merge branch 'DBAL-171' 2011-11-18 17:42:38 +01:00
Benjamin Eberlei 166c05dfaa Fix tests to be more stable 2011-11-18 17:42:32 +01:00
Benjamin Eberlei ab4d3c3a09 Merge branch 'DBAL-171' 2011-11-18 17:30:26 +01:00
Benjamin Eberlei 9e8a950f2e DBAL-171 - Fix bug where params where resorted but types where not in DQL Query 2011-11-18 17:29:31 +01:00
Benjamin Eberlei 0d4e0626cf Merge pull request #158 from goetas/cascade-all
Collapsed cascade elements, if cascade-all.
2011-11-18 06:49:40 -08:00
Benjamin Eberlei ef0a901cf5 Merge branch 'DDC-1496' 2011-11-18 15:44:19 +01:00
Benjamin Eberlei ceadc95439 DDC-1496 - Fix bug with OneToMany collections having orphanRemoval=true and Collection#clear() being called. 2011-11-18 15:44:06 +01:00
Benjamin Eberlei 61e371cbdc DDC-1069 - Fix error in docblocks of query builder 2011-11-18 14:43:47 +01:00
Benjamin Eberlei b44ff9b849 Merge pull request #194 from FabioBatSilva/DDC-1430-PGSQL-TEST
DDC-1430 - fix broken test on postgres
2011-11-18 05:14:15 -08:00
Benjamin Eberlei 2187f33477 Add test for DDC-1436 and DDC-1452 showing they are the same issues 2011-11-18 13:28:56 +01:00
Fabio B. Silva f4da4591fa fix broken test on postgres 2011-11-16 09:48:11 -02:00
Benjamin Eberlei 43b1e79ec4 Merge pull request #193 from FabioBatSilva/DDC-1430
DDC 1430
2011-11-15 14:47:45 -08:00
Fabio B. Silva aeb2ab132b group by all fields when entity has foreign keys 2011-11-15 20:27:45 -02:00
Fabio B. Silva 4cbd5eac95 Test Foreign Keys 2011-11-15 18:54:53 -02:00
Benjamin Eberlei 2d14be86f3 Merge pull request #192 from FabioBatSilva/DDC-1474
DDC-1474
2011-11-15 12:10:19 -08:00
Fabio B. Silva 08edf34057 move tests to SelectSqlGenerationTest 2011-11-15 17:27:17 -02:00
Benjamin Eberlei 9916f34262 Merge pull request #191 from FabioBatSilva/DDC1430
DDC-1430
2011-11-15 11:07:30 -08:00
Benjamin Eberlei a0ee72f264 Fix bug introduced in recent XmlDriver commit 2011-11-15 20:03:56 +01:00
Fabio B. Silva 3f8347a4d9 fixed DDC-1474 2011-11-15 17:00:19 -02:00
Guilherme Blanco 14f20c16bc Changed the RSM to make is behavior as mixed if you alias an entity. 2011-11-15 15:14:57 -02:00
Fabio B. Silva 3dd5d14977 Fixed DDC-1430 2011-11-15 14:28:57 -02:00
Guilherme Blanco 77e076f1fd Fixed DDC-1492. 2011-11-15 01:10:27 -02:00
Guilherme Blanco 45d95ad130 Fixed wrong indentation by my previous commit. 2011-11-15 01:09:48 -02:00
Benjamin Eberlei 9b32a2d87a DDC-1452 - Fix missing fetched parameter in BasicEntityPersister 2011-11-14 23:37:02 +01:00
Benjamin Eberlei 3e95eed76e Merge branch 'DDC-1452' 2011-11-14 23:06:00 +01:00
Benjamin Eberlei 34c94dbd94 DDC-1452 - Fixed bug with multiple fetch joins of the same "propery-path" of Class+field name combinations 2011-11-14 23:05:33 +01:00
Benjamin Eberlei 98033cc878 Merge branch 'master' into DDC-1452 2011-11-14 21:53:36 +01:00
Benjamin Eberlei 909504c074 DDC-1461 - Fix test failures 2011-11-14 21:05:44 +01:00
Benjamin Eberlei 4c7e4296c9 Merge pull request #189 from FabioBatSilva/DDC-1404
DDC-1404
2011-11-14 10:32:31 -08:00
Benjamin Eberlei 1b7eacd9fa Merge pull request #188 from FabioBatSilva/DDC-1476
DDC-1476
2011-11-14 10:31:30 -08:00
Fabio B. Silva 8af0f9d071 added support for Inherited Named Queries 2011-11-14 16:07:37 -02:00
Fabio B. Silva 0632b37492 fix default field type 2011-11-14 13:17:56 -02:00
Guilherme Blanco 81cc6d9da8 Implemented alias support for EntityResult. This addresses DDC-1096 and DDC-1424. Improved DQL Parser, SQL Walker and Hydrators in general. Performance is generally improved by a factor of 20%. There is still more to be done, like remove the isMixed in ResultSetMapping, mainly because this query - SELECT u AS user FROM User u -, it should return an array('user' => [User object]), while currently it doesn't due to this before mentioned 'bug' in RSM. Will open a separate ticket for this. Also, UnitOfWork and Hydrators share code that could be abstracted/improved. 2011-11-14 01:36:39 -02:00
Benjamin Eberlei e8eda4aeae Merge branch 'DDC-1461' 2011-11-13 23:14:40 +01:00
Benjamin Eberlei c648981f28 DDC-1461 - Verified deferred explicit works 2011-11-13 23:14:31 +01:00
Benjamin Eberlei c87d5af243 Specialize build status on versions 2011-11-13 22:40:27 +01:00
Benjamin Eberlei 077d4a0e15 Fix travis configuration files 2011-11-13 22:04:48 +01:00
Benjamin Eberlei 0fdffb9dbc Fix postgresql travis phpunit configuration file 2011-11-13 17:57:54 +01:00
Benjamin Eberlei c2bb281e80 Merge travis support from @pborreli - thanks! 2011-11-13 17:44:37 +01:00
Benjamin Eberlei 6b0cd7b604 Merge branch 'master' of github.com:doctrine/doctrine2 2011-11-13 17:17:06 +01:00
Benjamin Eberlei bb853722dc Merge branch 'thiagofesta-master' 2011-11-13 17:16:51 +01:00
Benjamin Eberlei 4571e498b4 DDC-1477 - Adjust patch to really fix bug in Proxy generation 2011-11-13 17:16:43 +01:00
Benjamin Eberlei 4e10a95dca Merge branch 'master' of https://github.com/thiagofesta/doctrine2 into thiagofesta-master 2011-11-13 17:05:23 +01:00
Benjamin Eberlei e9068a1552 Merge pull request #175 from lsmith77/get_class_name
added EntityRepository::getClassName()
2011-11-13 07:57:58 -08:00
Benjamin Eberlei 64b649ef61 Merge pull request #160 from goetas/generation
Allow to unset one-to-one relation with generated class
2011-11-13 07:53:58 -08:00
Benjamin Eberlei 70f0136c8a Merge branch 'everzet-PreFlush-event' 2011-11-13 16:51:40 +01:00
Benjamin Eberlei 6520211df3 Merge everzet/PreFlush-event 2011-11-13 16:51:23 +01:00
Benjamin Eberlei 056b34d847 Merge branch 'DDC-1491' 2011-11-13 15:45:15 +01:00
Benjamin Eberlei f7c46c7b33 DDC-1491 - Fix Schema Validator bug 2011-11-13 15:45:06 +01:00
Benjamin Eberlei 146f8f81f7 Merge branch 'DDC-1490' 2011-11-13 15:37:04 +01:00
Benjamin Eberlei 5aeabcb445 DDC-1490 - Fix id generation of sequence and identity to cast values to int 2011-11-13 15:36:48 +01:00
Benjamin Eberlei 01697fee3d Fix failing PostgreSQL tests 2011-11-12 22:16:39 +01:00
Benjamin Eberlei 450d92872a Forward compatibility with DBAL master 2011-11-12 12:56:44 +01:00
Benjamin Eberlei a14ba1e561 DDC-1237 - Remove dependency to mbstring 2011-11-12 09:43:37 +01:00
Benjamin Eberlei 4d425317b4 Merge pull request #187 from asm89/DDC-1458
Fix DDC-1458
2011-11-10 07:19:46 -08:00
Alexander 1f55351f19 Cleanup 2011-11-10 16:16:55 +01:00
Alexander 9c9f85ed4b Only refresh the given entity if an entity is specified in the query hints 2011-11-09 22:52:48 +01:00
Alexander 3131103801 Failing test case 2011-11-09 22:15:22 +01:00
Benjamin Eberlei d9ec0a59ec Merge pull request #186 from asm89/fix-tests-phpunit-3.6
Fixed failing tests in PHPUnit 3.6.2 (expecting \Exception was deprecated)
2011-11-09 01:04:38 -08:00
Alexander 2ddfc6af5a Fixed failing tests in PHPUnit 3.6.2 (expecting \Exception was deprecated) 2011-11-09 08:20:35 +01:00
Guilherme Blanco c391287cc4 More optimizations and increased code readability in Id Generators. 2011-11-08 18:36:18 -02:00
Benjamin Eberlei d943e67c65 Merge pull request #185 from asm89/indexby-exception
Remove invalid(?) exception for now
2011-11-08 04:17:01 -08:00
Alexander 39ed719c4c Remove invalid(?) exception for now 2011-11-08 13:16:33 +01:00
Benjamin Eberlei 3914e4a5d0 Merge pull request #184 from asm89/InvalidFetchMode-exception
Throw exception on invalid fetch mode in annotations
2011-11-08 01:28:32 -08:00
Benjamin Eberlei cce3798b4b Merge pull request #183 from asm89/ProxyIdentifier-types
Proxy identifier type casting
2011-11-08 01:27:30 -08:00
Alexander e99b800406 Throw exception on invalid fetch mode in annotations 2011-11-08 10:01:22 +01:00
Alexander 0cc176aae2 Do not cast BigInt to (int) 2011-11-08 09:47:33 +01:00
Alexander 6707129a3e Added type casts to 'non-lazy' identifiers in proxies. 2011-11-08 09:43:06 +01:00
Guilherme Blanco 32b8d77580 Fixed CS issues. More tiny optimizations in UnitOfWork. 2011-11-07 01:27:20 -02:00
Guilherme Blanco 96aa25fb3e Optimized more pieces of code in UnitOfWork. 2011-11-06 02:03:34 -02:00
Guilherme Blanco ea69d9ca0c Fixed wrong optimization. Optimized more pieces of code in UnitOfWork. 2011-11-05 19:21:35 -02:00
Guilherme Blanco c6a3ff4da5 Optimizations in UnitOfWork. 2011-11-05 03:09:14 -02:00
everzet 9c4c06c422 optimized PreFlush (moved into computeChangeSet function) 2011-11-03 16:24:47 +02:00
Benjamin Eberlei 793a1032e6 Merge pull request #182 from asm89/innerjoin-fetch-eager
Eagerly fetched entities should only be inner joined if they are loaded
2011-11-03 03:58:21 -07:00
Alexander ca438fa110 Eagerly fetched entities should only be inner joined if they are loaded
from the owning side.
2011-11-03 09:20:41 +01:00
Guilherme Blanco 305da5b8ff Added missing indexBy. 2011-11-03 02:49:50 -02:00
Guilherme Blanco 3c31d88810 Major optimizations in SqlWalker code, reducing overhead, reducing lookahead checks. 2011-11-03 02:44:50 -02:00
Guilherme Blanco 058242fa27 Fixed missing changes. 2011-11-03 02:37:54 -02:00
Guilherme Blanco d1bfd57fd9 Initial code optimization in Hydrators. 2011-11-02 22:08:24 -02:00
Alexander 53055f1fb2 [DDC-551] Fixed a bug in the sql generation for filters 2011-11-02 15:15:22 +01:00
Alexander 9ccce8ed74 [DDC-551] Add filters to eagerly joined entities in the persisters 2011-11-02 15:15:14 +01:00
Benjamin Eberlei d532de9da3 Fix docblocks ObjectHydratorTest 2011-11-01 17:43:23 +01:00
Benjamin Eberlei afb8d63fcb Fixed some AbstractHydrator docblocks 2011-11-01 16:42:03 +01:00
Benjamin Eberlei 98e3e04477 Add autoload section to composer.json 2011-11-01 15:05:38 +01:00
Benjamin Eberlei 4b316ec54f DDC-1389 - Add validation for empty discriminator map values 2011-10-31 23:35:41 +01:00
Benjamin Eberlei c965d231b1 Rename method and refactor code a bit 2011-10-31 23:21:11 +01:00
Benjamin Eberlei abb129028a Merge branch 'DBAL-1420' 2011-10-31 23:13:33 +01:00
Benjamin Eberlei e31e164896 DBAL-1420 - Use safe mode for schema validation. Dropping stuff isnt necessary here. 2011-10-31 23:12:52 +01:00
Benjamin Eberlei c38d273c1f Merge pull request #151 from doctrine/DDC-1385
DDC-1385
2011-10-31 15:10:54 -07:00
Benjamin Eberlei 88bda9b0d5 Merge pull request #180 from asm89/innerjoin-on-fetch-eager
[DDC-1463] Inner join eagerly loaded entities if possible
2011-10-31 14:24:47 -07:00
Alexander 53386e5247 Merge branch 'master' into innerjoin-on-fetch-eager
Conflicts:
	lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
2011-10-31 22:24:16 +01:00
Benjamin Eberlei 231d84b625 Fix xml fix again 2011-10-31 22:15:08 +01:00
Alexander 22b3b46b61 Removed unnecessary spaces in generated SQL 2011-10-31 22:08:40 +01:00
Alexander 0f938b8c1d Added tests for inner join generation with eager loading 2011-10-31 21:53:46 +01:00
Alexander 3994b80aa4 Fix TODO: Inner join when all join columns are NOT nullable. 2011-10-31 21:36:55 +01:00
Benjamin Eberlei 54217bd4c6 Merge branch 'DDC-1462' 2011-10-31 21:34:31 +01:00
Benjamin Eberlei 1dc5b7fba4 DDC-1462 - Fix bug in slice when calling on a dirty collection that is marked extra lazy 2011-10-31 21:34:22 +01:00
Benjamin Eberlei 3b819b52ca Merge branch 'DDC-1399' 2011-10-31 21:17:09 +01:00
Benjamin Eberlei 95193ab5f8 DDC-1399 - Fix extra lazy collections when inner collection contains values but persistent collection is marked not dirty because of flush() 2011-10-31 21:17:01 +01:00
Benjamin Eberlei 11f82bd41f DDC-1439 - Fix validate mapping some more 2011-10-31 20:49:59 +01:00
Guilherme Blanco d444f0e06b Micro optimization in SqlWalker. 2011-10-30 16:22:45 -02:00
Guilherme Blanco c246c6b28b AssignedGenerator optimization. 2011-10-30 16:07:43 -02:00
Guilherme Blanco 3cfa479c01 Micro optimization in computeChangeSet when using readOnly entities. 2011-10-30 15:46:07 -02:00
Benjamin Eberlei 67497ed834 Merge branch 'DDC-1384' 2011-10-30 16:48:00 +01:00
Benjamin Eberlei 64d405f7dd Merge origin/master into DDC-1384 2011-10-30 12:12:18 +01:00
Benjamin Eberlei 94c288a6a8 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-30 08:26:03 +01:00
Benjamin Eberlei 2c036b3185 Fix glitch in testsuites tearDown() 2011-10-30 08:25:19 +01:00
Benjamin Eberlei 1bbec8dd33 Clarify error message 2011-10-30 00:25:49 +02:00
Benjamin Eberlei 30731e0727 DDC-1384 - Fix all tests on Oracle 2011-10-29 23:58:09 +02:00
Benjamin Eberlei 50e028212d DDC-1384 - Fix a bunch of Oracle test failures 2011-10-29 20:42:44 +02:00
Benjamin Eberlei fb55e8094b DDC-1384 - Made tests case-insenstive to work with latest change regarding column sizes 2011-10-29 18:48:34 +02:00
Guilherme Blanco 96cb3d8004 Merge pull request #178 from adrienbrault/master
Fix Query iterate() doc return type
2011-10-29 06:39:27 -07:00
Adrien BRAULT e39bfced4a Fix iterate method doc return type 2011-10-29 13:40:01 +02:00
Guilherme Blanco 15562d030e Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-29 02:00:55 -02:00
Guilherme Blanco 0ec2cc557f Implemented support to entities with association marked as @Id support in many situations. Fixed DDC-1435. 2011-10-29 02:00:35 -02:00
Benjamin Eberlei 7d921a8220 DDC-1452 - Attach working testcase 2011-10-29 00:22:45 +02:00
Benjamin Eberlei f232e45efe Merge branch 'DDC-1410' 2011-10-28 23:45:38 +02:00
Benjamin Eberlei 7be98f475e DDC-1410 - Remove code-inlining that caused problems 2011-10-28 23:45:23 +02:00
Thiago Festa 66d2b9e0fb The ProxyFactory was redeclaring methods serialize and unserialize on the cache file on some OSs. 2011-10-28 17:54:15 -02:00
Guilherme Blanco 3745e948c6 Made SimpleSelectExpression (Literal) be included as a scalar result. More general SQL Walker optimizations. 2011-10-28 14:25:12 -02:00
Guilherme Blanco 1f06e9fca5 Fixed issue with SimpleSelectExpression containing Literals. This issue is related to a previously fixed ticket DDC-1079. 2011-10-28 12:56:14 -02:00
Guilherme Blanco 7841ccb7c0 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-28 12:49:21 -02:00
Guilherme Blanco 1579c43433 Code beautification and docblocks enhancements. 2011-10-28 12:49:01 -02:00
Benjamin Eberlei fbfd59afa0 Merge branch 'DDC-1454' 2011-10-28 00:50:30 +02:00
Benjamin Eberlei f34eb83a7c DDC-1454 - Fix exists() for Joined table inheritance 2011-10-28 00:50:10 +02:00
Benjamin Eberlei 8db1a09001 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-28 00:26:54 +02:00
Benjamin Eberlei 4a0227e5f2 Revert Expr\Base patch 2011-10-28 00:24:41 +02:00
Benjamin Eberlei a98c7df2f1 Merge branch 'DDC-217' 2011-10-27 22:36:25 +02:00
Benjamin Eberlei 5918058d86 Merge origin/master 2011-10-27 22:36:06 +02:00
Guilherme Blanco c5ef21864f Fixed bug with fetch=EAGER associations that have already been hydrated during querying. 2011-10-26 15:04:49 -02:00
Asmir Mustafic d09285e9d3 Collapse cascade all test (YAML too) 2011-10-26 10:59:15 +02:00
Asmir Mustafic 035ca8e500 Collapse cascade all test 2011-10-26 10:14:59 +02:00
Lukas Kahwe Smith 0a5a23628f added EntityRepository::getClassName() to fullfill the ObjectRepository interface
see https://github.com/doctrine/common/pull/70
2011-10-25 23:21:39 +02:00
Benjamin Eberlei cfe7ab46f2 Merge branch 'master' of git://github.com/doctrine/doctrine2 2011-10-25 22:55:08 +02:00
Benjamin Eberlei 3b9312e291 Bump DBAL version and make TestUtil more lenient 2011-10-25 22:54:20 +02:00
Benjamin Eberlei a02b0c9269 Merge pull request #165 from armetiz/patch-3
Update lib/Doctrine/ORM/Query/Expr/Base.php
2011-10-24 03:42:04 -07:00
Benjamin Eberlei 0cdf1e042c Merge pull request #173 from jaikdean/master
Fixed a couple of typos of 'discriminator'
2011-10-24 03:41:19 -07:00
Project 1873302ee9 Merge branch 'generation' of https://github.com/goetas/doctrine2 into generation 2011-10-24 12:15:01 +02:00
Asmir Mustafic 7efd615b8c Coding standards 2011-10-24 12:00:11 +02:00
Jaik Dean cdb452b27b Fixed typos of 'discriminator' 2011-10-24 10:01:27 +01:00
Asmir Mustafic f5330741ac Coding standards 2011-10-24 10:59:50 +02:00
Asmir Mustafic 5f80b57554 Improoved coding standards 2011-10-24 10:19:01 +02:00
Asmir Mustafic cb76222e63 Collapse cascade persist, remove, refresh, detach, merge into
cascade-all (implemented currently only for XML annotation)
2011-10-24 09:54:31 +02:00
Asmir Mustafic 1b83fcc46d Coding standards 2011-10-24 09:20:24 +02:00
Benjamin Eberlei a8052dec37 Added note about result cache changes 2011-10-23 23:35:04 +02:00
Benjamin Eberlei adc4840cce DDC-217 - Add support for QueryCacheProfiles and remove the old result caching code from ORM. Deprecate a bunch of methods in favor of using the AbstractQuery#getQueryCacheProfile method. 2011-10-23 23:28:23 +02:00
Benjamin Eberlei 993d6f5ac8 Merge pull request #171 from asm89/fix-mysql-tests
Fix mysql testsuite
2011-10-23 13:12:09 -07:00
Alexander 80c9690926 Fix mysql testsuite 2011-10-23 22:06:03 +02:00
Benjamin Eberlei d9740e2028 Merge pull request #170 from asm89/fix-tests
Fix testsuite
2011-10-23 12:39:00 -07:00
Alexander f1df4ffca4 Fix testsuite 2011-10-23 21:37:29 +02:00
everzet 91d8829c43 removed non-used code 2011-10-23 18:50:24 +03:00
everzet 20ed8869e4 added test for PreFlush lifetime event 2011-10-23 18:41:41 +03:00
everzet 66e2a9260e added PreFlush lifetime event and lifecycle callback 2011-10-23 18:39:16 +03:00
Benjamin Eberlei 9b8d2d512b Merge pull request #168 from dfreudenberger/master
postFlush event implementation
2011-10-23 01:12:27 -07:00
Benjamin Eberlei fd00f2d371 Merge pull request #166 from doctrine/DDC-720
DDC-720 - Add support to flush only one entity through EntityManager#flush()
2011-10-23 01:07:14 -07:00
Benjamin Eberlei 5d3298e706 DDC-720 - Correct mentioned issues by @asm89 2011-10-23 10:05:46 +02:00
Daniel Freudenberger fa8000fa5c dispatch the event after the snapshot was taken 2011-10-23 01:27:09 +02:00
Daniel Freudenberger 5e28273548 fixed typo in docblock 2011-10-22 18:57:48 +02:00
Daniel Freudenberger 46a3fecb4f added the postFlush event 2011-10-22 18:38:51 +02:00
Alexander 079e2b1302 [DDC-1384] Fix for generating sql with aliases not longer than MaxIdentifierLength 2011-10-22 16:27:56 +02:00
Benjamin Eberlei b910a487c5 DDC-720 - Wait, we should really test it only changes the passed entity. 2011-10-22 14:31:23 +02:00
Benjamin Eberlei f569a2a389 DDC-720 - Add support to flush only one entity (within cascade rules) through EntityManager#flush() 2011-10-22 13:44:33 +02:00
Benjamin Eberlei 719e05e53e Extract more messages into ORMInvalidArgumentException 2011-10-22 12:57:55 +02:00
Benjamin Eberlei a8906ce572 Stringify entity in all UnitOfWork exceptions 2011-10-22 12:49:33 +02:00
Benjamin Eberlei 5392737de4 Improved and extracted UnitOfWork error messages 2011-10-22 12:40:12 +02:00
Benjamin Eberlei 3aea203b9c Throw exception if target entity is not found. 2011-10-22 11:28:07 +02:00
Benjamin Eberlei dba8360166 Merge master into ImproveErrorMessages 2011-10-22 11:06:51 +02:00
Benjamin Eberlei 23560038b4 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-22 10:37:32 +02:00
Asmir Mustafic d4059b88ca Nullable relations, fixing join condition 2011-10-21 15:30:21 +02:00
armetiz baef4f735f Update lib/Doctrine/ORM/Query/Expr/Base.php 2011-10-21 16:30:06 +03:00
Benjamin Eberlei 01f1924a89 Merge pull request #163 from armetiz/patch-2
Update lib/Doctrine/ORM/Query/Expr.php
2011-10-21 05:18:01 -07:00
Alexander 07ce4092cd Merge branch 'master' into DDC-551 2011-10-21 12:04:29 +02:00
armetiz 4a50eb4fa7 Update lib/Doctrine/ORM/Query/Expr.php 2011-10-21 11:55:54 +03:00
Asmir Mustafic fe84a61d0b Better code generation when association is nullable 2011-10-21 09:38:37 +02:00
Asmir Mustafic 596ba3d5b1 Collection inteface instead of ArrayCollection 2011-10-19 15:04:16 +02:00
Benjamin Eberlei ca01065c6a Bugfix in short identifier shortcut with association ids 2011-10-19 11:58:59 +02:00
Asmir Mustafic be3adfb35e With TO_MANY relations, class filed is instanceof ArrayCollection,
instead of targetEntity class type.
2011-10-19 09:25:40 +02:00
Asmir Mustafic 8f092812c4 Spaces 2011-10-19 09:17:30 +02:00
Asmir Mustafic 9c1202a766 Added <variableDefault> on generated class.
This allow to unset many-to-one and one-to-one relations


Example: $user->setGroup(null);
2011-10-19 09:15:41 +02:00
Asmir Mustafic e19fd756cb Better indentation for generated class 2011-10-19 09:07:18 +02:00
Benjamin Eberlei 7345c795ac Merge pull request #154 from Partugal/master
Fix isTransient call on uninitialized ClassMetadataFactory
2011-10-19 00:04:14 -07:00
Benjamin Eberlei 753f75cfb9 Merge pull request #156 from goetas/xmlassoc
Set association-key attribute in xml mapping
2011-10-19 00:03:55 -07:00
Asmir Mustafic 97321a1ff2 Collapsed cascade elements, if cascade-all.
(better readability for generated xml)
2011-10-18 16:18:25 +02:00
Asmir Mustafic 0d57ffbc3b Set association-key attribute in xml mapping 2011-10-18 15:48:56 +02:00
Sergey Linnik c3ec6e383c Fix isTransient call on uninitialized ClassMetadataFactory 2011-10-18 01:14:07 +04:00
Benjamin Eberlei 0b1f6e3539 Merge pull request #153 from asm89/shesek-patch-1
Support NULL in EntityRepository's magic findBy and findOneBy methods
2011-10-17 12:05:07 -07:00
Alexander b8af241504 Added a testcase for findBy(.. => null) and renamed 'old' testcase 2011-10-17 20:53:04 +02:00
Alexander 91bc9c0329 Adjusted test to verify that findBy*(null) is now supported 2011-10-17 18:56:06 +02:00
Alexander fea855004c Merge remote-tracking branch 'doctrine/master' into shesek-patch-1 2011-10-17 18:55:48 +02:00
Guilherme Blanco 83a8ed01e7 Merge pull request #94 from kwiateusz/findByOnePatch
Now findByOne really retrieve only one entity adding limit to query.
2011-10-17 06:24:37 -07:00
Benjamin Eberlei 2b663ff2bc Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-16 22:47:28 +02:00
Benjamin Eberlei 1a602a8cb3 Merge branch 'DDC-1278' 2011-10-16 22:45:50 +02:00
Benjamin Eberlei 939fbf9c24 DDC-1278 - Clean up event handling of new clear functionality. 2011-10-16 22:45:06 +02:00
Benjamin Eberlei 22a04fd6de Merge dominikl/DDC-1278 into doctrine/DDC-1278 2011-10-16 22:41:16 +02:00
Benjamin Eberlei 8466060797 DDC-1385 - Add INDEX BY scalar variables on the top-level 2011-10-16 19:23:20 +02:00
Benjamin Eberlei ba5e73213b Merge pull request #150 from stof/initialize_object
Added the initializeObject method in the EntityManager
2011-10-16 08:04:46 -07:00
Christophe Coevoet a8e6131e3b Added the initializeObject method in the EntityManager 2011-10-16 17:00:33 +02:00
Benjamin Eberlei ee924ffaba DDC-1385 - Fix scalar handling for array hydrator 2011-10-16 16:27:50 +02:00
Benjamin Eberlei 2730f64d90 DDC-1385 - Refactor ObjectHydrator 2011-10-16 16:13:59 +02:00
Benjamin Eberlei cb0e5dbff3 DDC-1385 - Fixed Mixed result hydration using INDEX BY to work on the top-level indexes, not some weird result. This is a BC break to those that actually use this crazy logic, sorry for that :-) 2011-10-16 12:46:17 +02:00
Benjamin Eberlei fc738455b6 Merge branch 'DDC-1358' 2011-10-16 11:17:04 +02:00
Benjamin Eberlei 0252d55c67 DDC-1358 - Fix bug where multiple NULL root entity combined with scalar results will break the object and array hydrator.
This case likeli only occurs when doing native queries. A guard clause that prevents hydration from breaking
when RIGHT JOIN queries with null root entities appear has been added aswell.
2011-10-16 11:15:45 +02:00
Guilherme Blanco eeba947ea7 Code optimizations. Fixed unused argument in OrmTestCase as referred in DDC-766. 2011-10-16 02:10:59 -02:00
Guilherme Blanco 33bcf7ad6f Added coverage to DDC-1161. 2011-10-16 01:42:36 -02:00
Alexander 58b381bf24 [DDC-551] use isClean to check the filterCollection state.. 2011-10-15 22:31:20 +02:00
Benjamin Eberlei 4474d305cb DDC-1210 - Optimize UnitOfWork collection handling internally. 2011-10-15 21:47:16 +02:00
Benjamin Eberlei 7c244abc1c Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-15 21:09:36 +02:00
Benjamin Eberlei 5c78ecaca1 Fix tests in EntityGenerator due to Annotation prefixes 2011-10-15 20:44:25 +02:00
Benjamin Eberlei 7b71b3284d Fix failing test due to EntityGenerator assuming beginning with 2.2 the AnnotationReader is always used. There is still the simple reader though. 2011-10-15 20:41:07 +02:00
Benjamin Eberlei 7e571212a7 Merge pull request #109 from alOneh/patch-1
Remove trailing spaces
2011-10-15 11:39:56 -07:00
Benjamin Eberlei 75e1d17d18 Merge branch 'ValidateJoinColumnsMatching' 2011-10-15 20:33:46 +02:00
Benjamin Eberlei a82bffbfc9 Make SchemaValidator catch errors such as very invalid schema using only part of the primary key for join columns 2011-10-15 20:31:56 +02:00
Guilherme Blanco ba38f3e1e9 Merge pull request #148 from asm89/ProxyIdentifer
Do not load entity on retrieving identifier from a proxy
2011-10-15 11:23:06 -07:00
Benjamin Eberlei 46541755ca Merge pull request #128 from alanbem/xml-schema-on-delete-fix
fixed wrong on-delete XML Schema mapping
2011-10-15 11:09:55 -07:00
Benjamin Eberlei 18fd29613c Merge pull request #137 from docteurklein/fluent_query_expr
added fluent pattern to Query\Expr\Base::add* methods
2011-10-15 11:09:37 -07:00
Benjamin Eberlei 1f59001ff7 Merge pull request #130 from bmichotte/master
Fluent entity (master)
2011-10-15 11:01:19 -07:00
lenar 3dc30dee11 use the correct targetEntity 2011-10-15 20:00:02 +02:00
lenar cab154b873 identifier referencing foreign entity can be defined in parent class too 2011-10-15 19:59:50 +02:00
Benjamin Eberlei 7f5844c209 Merge pull request #147 from asm89/assignid
Goetas: Better error handling on missing assigned id
2011-10-15 10:41:27 -07:00
Alexander c5e51e6fa9 Merge branch 'master' into assignid 2011-10-15 19:33:42 +02:00
Alexander fdb9fb1c2b AssignedGenerator can always tell what field is missing an id 2011-10-15 19:33:29 +02:00
Benjamin Eberlei b6c49863e8 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-15 19:14:53 +02:00
Benjamin Eberlei d0383f93d0 Merge branch 'DDC-1383' 2011-10-15 19:14:40 +02:00
Benjamin Eberlei 08716d9f72 DDC-1383 - Proxy Generation in merge was flawed with inheritance 2011-10-15 19:14:30 +02:00
Benjamin Eberlei 73101be422 Merge pull request #143 from craue/patch-2
added missing type hint
2011-10-15 10:05:53 -07:00
Benjamin Eberlei 6f3667201c Add @ignore and @internal to UnitOfWork#computeChangeSet 2011-10-15 18:11:14 +02:00
Alexander d46352da01 Fixed tests + added dedicated tests for proxy loading and identifiers 2011-10-15 17:58:00 +02:00
Benjamin Eberlei 30149e48f9 Merge branch 'DDC-1411' 2011-10-15 17:53:11 +02:00
Benjamin Eberlei 52cea01563 DDC-1411 - Fixed onDelete handling in EntityGenerator 2011-10-15 17:53:04 +02:00
Benjamin Eberlei f54cdf625e Merge branch 'DDC-1414' 2011-10-15 17:47:17 +02:00
Benjamin Eberlei cb21f3c5ff DDC-1414 - Missing push to $newNodes 2011-10-15 17:47:09 +02:00
Benjamin Eberlei cb28bfd484 Improve Error Messages in ClassMetadata and UnitOfWork 2011-10-15 17:38:55 +02:00
Alexander 8d1b852aa2 Added tests for not loading the entity + fixed a test 2011-10-15 17:31:09 +02:00
Alexander f47e1feac6 Merge branch 'master' of git://github.com/doctrine/doctrine2 into ProxyIdentifer
Conflicts:
	lib/Doctrine/ORM/Proxy/ProxyFactory.php
2011-10-15 17:24:13 +02:00
Benjamin Eberlei 84dbb08502 Merge branch 'DDC-1421' 2011-10-15 16:58:05 +02:00
Benjamin Eberlei e38076c19a DDC-1421 - Fix potential bug and code-smells 2011-10-15 16:57:57 +02:00
Benjamin Eberlei 3b46df68ea Adjust README.markdown 2011-10-15 16:36:20 +02:00
Benjamin Eberlei dd6f6cb097 Fix notice 2011-10-15 16:03:50 +02:00
Benjamin Eberlei 640facd26a Remove unncessary line 2011-10-15 15:51:11 +02:00
Benjamin Eberlei 291d2fd624 UPGRADE_TO_2_2 2011-10-15 15:49:41 +02:00
Benjamin Eberlei 9ece0fe3c9 Merge branch 'DDC-1386' 2011-10-15 15:45:59 +02:00
Benjamin Eberlei 3801e0c230 Add way to keep track of read only objects in the UnitOfWork which are never updated during flush.
Changed the behavior of EntityManager#getPartialReference to be read-only. No changes are ever
done to this entities. Changed UnitOfWork#computeChangeSet to never create a changeset for
fields that are partially omitted from a DQL or NativeQuery.

To check if an entity is read only use the new API:

    if ($entityManager->getUnitOfWork()->isReadOnly($entity))
2011-10-15 15:42:02 +02:00
Benjamin Eberlei 2166a21511 Merge branch 'master' of github.com:doctrine/doctrine2 2011-10-15 11:36:53 +02:00
Benjamin Eberlei 894bbb020c DDC-1394 - Enhance test to verify 2011-10-15 09:57:35 +02:00
Guilherme Blanco 772b413579 Fixed bug with boolean values being converted to string. 2011-10-15 00:23:55 -03:00
Guilherme Blanco 2518f0687c Removed invalid default argument. 2011-10-15 00:21:11 -03:00
Guilherme Blanco f86e1ba66c Added tests for DDC-1389. Everything is working in 2.2-DEV. 2011-10-15 00:18:57 -03:00
Alexander 097d573d26 Merge branch 'master' into DDC-551
Conflicts:
	lib/Doctrine/ORM/Configuration.php
	lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
	lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
2011-10-14 12:33:39 +02:00
Benjamin Eberlei 4a920d0aad Merge branch 'DDC-1418' 2011-10-13 23:40:11 +02:00
Fabien Potencier 6a72ba5f97 DDC-1418 - Add simplified XML and YAML drivers ported from the Symfony project, thanks Fabien 2011-10-13 23:39:11 +02:00
Benjamin Eberlei 92b16455c8 Merge branch 'DDC-1415' 2011-10-13 22:58:58 +02:00
Benjamin Eberlei a36a1624fb [DDC-1415] Add EntityEventDelegatee, allowing to restrict emitting events to certain entity classes only. 2011-10-13 22:58:22 +02:00
Benjamin Eberlei 97a6caf059 Update Common to latest to have the current Persistence Interface 2011-10-11 13:22:26 +02:00
Guilherme Blanco 509e5fb12f Merge pull request #145 from stof/EntityGenerator_versionCheck
Fixed the version check in the entity generator
2011-10-10 12:34:01 -07:00
Christophe Coevoet c7c875a063 Fixed the version check in the entity generator
The 3.0.x branch of Common has been merged to become the incoming
2.2 release.
2011-10-10 19:20:01 +02:00
Benjamin Eberlei 45308d5f79 Merge branch 'DDC-1402' 2011-10-10 17:52:47 +02:00
Benjamin Eberlei 9058bc3f5c Fix DDC-1402 - No caching for SingleTablePersister::_getSelectColumnList 2011-10-10 17:52:37 +02:00
Benjamin Eberlei 89470787d8 Add composer.json 2011-10-10 16:54:57 +02:00
Benjamin Eberlei de98f3fb30 Added composer.json 2011-10-10 16:30:49 +02:00
Guilherme Blanco 15877e1443 Merge pull request #144 from craue/patch-3
switched 2nd and 3rd argument for SelectExpression's constructor, making the 3rd one optional to keep its signature compatible to previous versions
2011-10-10 05:21:41 -07:00
Christian Raue 1681d8a893 switched 2nd and 3rd argument for SelectExpression's constructor, making the 3rd one optional to keep its signature compatible to previous versions 2011-10-10 14:04:55 +02:00
Guilherme Blanco f3b6ed03f3 Merge pull request #142 from craue/patch-1
fixed typo
2011-10-10 03:31:34 -07:00
Christian Raue 689aaef4dc added missing type hint 2011-10-10 09:44:17 +03:00
Christian Raue bf44be86a9 fixed typo 2011-10-10 03:02:55 +03:00
Guilherme Blanco 24042863ac BasicEntityPersister::exists() was not supporting identifiers that are associations. Fixes DDC-1382. 2011-10-03 02:21:14 -03:00
Guilherme Blanco ebe933810e Implemented HIDDEN support in DQL. Fixes DDC-1363. 2011-10-03 02:07:07 -03:00
Guilherme Blanco 8efae0b232 Fixes DDC-1396. 2011-10-03 01:30:20 -03:00
Guilherme Blanco cd28051370 Fixes DDC-1395 2011-10-03 01:26:43 -03:00
Asmir Mustafic d24f288149 Better error handling on missing assigned id 2011-09-29 09:31:06 +02:00
docteurklein b28af2e527 added fluent pattern to Query\Expr\Base::add* methods 2011-09-27 10:36:32 +02:00
Guilherme Blanco 80284a273d Merge pull request #133 from FabioBatSilva/DDC-1335
Fixes DDC-1335.

Patch looks perfect to me. @beberlei please merge into 2.1 =)
2011-09-25 14:52:56 -07:00
Benjamin Eberlei d2cd6560c5 DDC-1337 - Adjust MultiTableUpdateExecutor and MultiTableDeleteExecutor to use AbstractPlatform 2011-09-25 19:01:37 +02:00
Benjamin Eberlei 919f5e5ebc Merge branch 'DDC-1392' 2011-09-25 18:08:50 +02:00
Benjamin Eberlei 9f96d4a31a DDC-1392 - Fix bug with merging unitialized proxies 2011-09-25 18:08:41 +02:00
Fabio B. Silva 5fe996baf9 change tests for DDC-1135 2011-09-25 12:20:48 -03:00
Benjamin Eberlei 43c25ea36d Merge branch 'DDC-1367' 2011-09-25 16:39:50 +02:00
Benjamin Eberlei cd7029d266 DDC-1367 - Bugfix 2011-09-25 16:39:41 +02:00
Benjamin Eberlei c02920762b Adjust ClassMetadataFactory to forthcoming interface change 2011-09-25 14:41:56 +02:00
Fabio B. Silva 728724bed5 fix DDC-1135 2011-09-24 16:16:25 -03:00
Fabio B. Silva e94b902a9b tests for DDC-1335 2011-09-24 16:10:10 -03:00
Fabio B. Silva f4c5c4ba01 branch for DDC-1335 2011-09-23 18:10:58 -03:00
Guilherme Blanco 9795cb1f0d Subqueries should never add items to ResultSetMapping. Fixing possible broken inclusion. 2011-09-21 17:35:38 -03:00
Guilherme Blanco a86038b484 Fixed issue with CaseExpression not working in Subselects. 2011-09-21 17:30:45 -03:00
Benjamin 01d900d5d7 tab <-> spaces 2011-09-20 15:50:32 +02:00
Benjamin 944f802d79 Correct indentation 2011-09-20 15:35:16 +02:00
Benjamin 2b334977f5 Add "return $this" to generated methods to get a fluent Enttity class 2011-09-20 14:59:32 +02:00
Alan Bem 90725fa529 fixed wrong on-delete XML Schema mapping 2011-09-20 11:10:59 +02:00
Guilherme Blanco 2ae3bb6e3a Fixed bug in Result cache cleaner. 2011-09-19 01:40:30 -03:00
Guilherme Blanco 1fb213760b Refactored Cache cleaners commands to sync with new Common Cache Providers. 2011-09-15 17:46:13 -03:00
Alexander 63a3fb5ad8 [DDC-551] Moved SQLFilter logic to a separate FilterCollection class 2011-09-15 21:38:47 +02:00
Guilherme Blanco 00321e8f70 Imported DBAL-164 fix to ORM. 2011-09-13 02:03:08 -03:00
Guilherme Blanco 918e2d2018 Fixed remaining Doctrine packages upgrade. 2011-09-13 01:14:36 -03:00
Guilherme Blanco 3bb803fd69 Cherry picked FabioBatSilva upgrade of Common lib. 2011-09-13 00:59:24 -03:00
Guilherme Blanco f8811c4d21 Merge pull request #121 from FabioBatSilva/DDC-753
DDC-753
2011-09-08 14:30:54 -07:00
Fabio B. Silva 3707b34cbb Change repository type for EntityRepository 2011-09-08 17:21:06 -03:00
Fabio B. Silva 43ccd9ead6 tests for DDC-753 2011-09-08 15:54:49 -03:00
Fabio B. Silva ee80ec4851 Merge remote-tracking branch 'upstream/master' into DDC-753 2011-09-08 14:36:38 -03:00
Fabio B. Silva 84cd22d7f7 new branch for DDC-753 2011-09-08 14:36:13 -03:00
Guilherme Blanco 7ebfc67d5a Merge pull request #120 from FabioBatSilva/DDC-869
Fixed DDC-869
2011-09-08 10:15:24 -07:00
Fabio B. Silva 19d0887bb0 check if parent class is a mapped superclass 2011-09-08 13:41:16 -03:00
Fabio B. Silva 7f0275155d php mapping 2011-09-08 13:17:53 -03:00
Fabio B. Silva 6a89de51e5 change tests 2011-09-08 12:55:55 -03:00
Fabio B. Silva 54a53b1d03 tests for DDC-869 2011-09-08 11:56:05 -03:00
Fabio B. Silva f6d34bbb9d Merge remote-tracking branch 'upstream/master' into DDC-869 2011-09-08 11:54:04 -03:00
Guilherme Blanco 2b3bee1fa4 Merge pull request #119 from alOneh/patch-2
Fix documentation for metadata driver
2011-09-08 07:29:55 -07:00
Alain Hippolyte 01c9a4ac1c Fix documentation for metadata driver 2011-09-08 11:41:09 +03:00
Guilherme Blanco a7f3af8328 Added IDENTITY DQL Function. Fixes DDC-1339. 2011-09-08 02:10:48 -03:00
Fabio B. Silva b2d98495b1 mapping files 2011-09-07 18:29:43 -03:00
Fabio B. Silva 25ecd45fd1 Merge remote-tracking branch 'upstream/master' into DDC-869 2011-09-07 17:27:59 -03:00
Fabio B. Silva 82f7d6cad2 starts work with mapped superclass repository 2011-09-07 17:27:05 -03:00
Guilherme Blanco bd5393a318 Added coverage for orphanRemoval in OneToOne when unlinking an entity. 2011-09-07 13:12:02 -03:00
Guilherme Blanco e3d133af04 Added getQuotedTableName() in missing places of Doctrine ORM. Fixes DDC-1365. 2011-09-07 01:48:19 -03:00
Guilherme Blanco 6ec2ae249b Merge branch 'master' of github.com:doctrine/doctrine2 2011-09-06 01:58:34 -03:00
Guilherme Blanco 2cfc61db84 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-06 01:58:16 -03:00
Guilherme Blanco c30e129390 Merge pull request #118 from bauffman/patch-1
Fixed typo
2011-09-05 06:48:28 -07:00
Davy Hellemans b333ff95fb Fixed typo 2011-09-05 09:42:09 +03:00
Guilherme Blanco 6bbf2d9da3 Added support for ResultVariable referencing in ArithmeticPrimary. Fixes DDC-1346. 2011-09-05 03:16:01 -03:00
Guilherme Blanco ddfdb37a58 Merge branch 'master' of github.com:doctrine/doctrine2 2011-09-05 02:27:26 -03:00
Guilherme Blanco 666691f84f Small changes for code readability. Added type binding in JoinedSubclassPersister, which was missing. Fixes DDC-1316. 2011-09-05 02:27:06 -03:00
Benjamin Eberlei b6a7520c64 Merge branch 'DDC-659' 2011-09-04 14:13:45 +02:00
Benjamin Eberlei 09ac3a9eb2 DDC-659 - Add ClassMetadataBuilder for PHP based metadata management 2011-09-04 14:13:20 +02:00
Benjamin Eberlei 342c3ba941 Initial work on ClassMetdataBuilder 2011-09-04 10:08:33 +02:00
Benjamin Eberlei 88574a0de2 Add note about Common Annotation changes 2011-09-04 01:11:19 +02:00
Benjamin Eberlei f6f6edbd59 Merge branch 'master' of github.com:doctrine/doctrine2 2011-09-04 01:10:37 +02:00
Guilherme Blanco f29c907f41 Optimized and refactored code for getParameterValue in Doctrine\ORM\Query. 2011-09-02 13:53:53 -03:00
Guilherme Blanco 3b3186ee98 Added support to user provide an array of Entities as a DQL parameter. Fixes DDC-1356. 2011-09-01 19:11:57 -03:00
Guilherme Blanco ecc556f687 Fixes DDC-1354. 2011-09-01 03:00:53 -03:00
Benjamin Eberlei 53a153bc15 Merge pull request #111 from Gregwar/yaml_entity_repository
[Tools] Added entityRepository support in yaml exporter
2011-08-30 11:43:25 -07:00
Benjamin Eberlei 800628e3cd Merge branch 'DDC-1350' 2011-08-30 20:40:38 +02:00
Benjamin Eberlei 8b38e68e23 DDC-1350 - Bugfixes in Doctrine\ORM\Tools\Setup 2011-08-30 20:40:26 +02:00
Benjamin Eberlei 7ba656f815 Bump DBAL dependency to 2.1.2 2011-08-29 23:01:05 +02:00
Grégoire Passault 240f0ea34c [Tools] Added entityRepository support in yaml exporter 2011-08-29 17:40:54 +02:00
Guilherme Blanco 12f46e936c Merge branch 'master' of github.com:doctrine/doctrine2 2011-08-28 13:48:24 -03:00
Guilherme Blanco e7f471ef3e Fixed issue with CTI during DQL update that was incorrectly setting parameter types during multi table execution. Fixes DDC-1341. 2011-08-28 13:48:15 -03:00
Benjamin Eberlei 0a6709acba Fix tests with regard to repositoryClass handling and applying the default namespace 2011-08-28 16:00:21 +02:00
Benjamin Eberlei c948ad852e Merge branch 'FixPostgresFailures' 2011-08-28 15:58:27 +02:00
Benjamin Eberlei b145f061c9 DDC-1348 - Fix bug with UnitOfWork::getEntityState() 2011-08-28 15:58:08 +02:00
Benjamin Eberlei e6a73803a4 Merge branch 'DDC-1306' 2011-08-27 20:44:15 +02:00
Benjamin Eberlei 3b4b38e184 DDC-1306, DDC-1113 - Fix issues with inheritance and commit order 2011-08-27 20:41:52 +02:00
Benjamin Eberlei 7da9beed36 Merge branch 'master' of github.com:doctrine/doctrine2 2011-08-27 17:59:11 +02:00
Benjamin Eberlei 3bee695913 Update dependencies to 2.1.1 respectively 2011-08-27 14:49:49 +02:00
Benjamin Eberlei d3b27dcb1a DDC-1344 - Fix path displaying to not use realpath()ed variables 2011-08-27 13:36:18 +02:00
Benjamin Eberlei 4f22bbbc76 Add support to distribute the XSD to a given directory during build process 2011-08-27 13:23:17 +02:00
Nadav 2e389e00d4 Removed blank line, used empty() instead of the count() check 2011-08-26 08:15:28 +03:00
Nadav 5fc6277d3f Oops, shouldn't have removed the condition completely... checking a parameter is provided 2011-08-26 07:51:29 +03:00
Nadav d314386060 we can (now) transform it into IS NULL 2011-08-26 07:42:16 +03:00
Benjamin Eberlei e69e0fcc71 Merge remote-tracking branch 'origin/master' 2011-08-24 20:45:32 +02:00
Benjamin Eberlei b560551b1d Merge branch 'DDC-1333' 2011-08-21 15:06:21 +02:00
Benjamin Eberlei b83945d486 DDC-1333 - Fix bug in xsd 2011-08-21 15:06:14 +02:00
Benjamin Eberlei 3c82b49cd3 Merge branch 'DDC-1340' 2011-08-21 15:02:05 +02:00
Benjamin Eberlei 8c2db89f2b DDC-1340 - Fix bug with merge() and optimistic lock exception 2011-08-21 15:01:57 +02:00
Alain Hippolyte 06d56156dd Remove trailing spaces 2011-08-19 06:11:58 +03:00
Guilherme Blanco 736443f6c2 Merge pull request #108 from lenar/patch-1
short classname support for custom repository class
2011-08-18 11:03:43 -07:00
Lenar Lõhmus d7fbd2cd14 short classname support for custom repository class 2011-08-19 04:44:24 +03:00
Alexander ed0fb4ece7 Merge branch 'master' into DDC-551
Conflicts:
	lib/Doctrine/ORM/Persisters/OneToManyPersister.php
2011-08-16 16:59:48 +02:00
Guilherme Blanco 7433148f17 Fixed bug in XMLDriver where relation indexes are treathed as elements but documented as attributes. 2011-08-16 11:36:41 -03:00
Alexander 3800581947 [DDC-551] Altered persisters to make filters work with EXTRA_LAZY associations 2011-08-16 16:24:50 +02:00
Alexander 2653d735e2 [DDC-551] Added state of the complete filter collection to the EM
Previously it was sufficient to use the old parser result for a Query if
the DQL didn't change (Query::STATE_CLEAN), but now there must also be
no changes to the filter collection of the EntityManager.

In the old situation each Query object would create a hash of all the
filter objects on it's own. That was not very efficient.

This commit adds the state of the current filter collection to the
EntityManager. The state will be set to FILTERS_STATE_DIRTY as a filter
is enabled, removed or a parameter is set on a filter. The hash is also
computed by the EntityManager, but only if the filter collection is
dirty. This will prevent recalculation of the hash with each query.
2011-08-16 13:34:42 +02:00
Alexander 3b1ddb0346 [DDC-551] Added filters to SQLWalker 2011-08-16 12:21:43 +02:00
Guilherme Blanco 6857134f36 Fixed issue with duplicated commas if Entity has no fields. 2011-08-15 12:47:17 -03:00
Guilherme Blanco f148912a28 [DDC-934][DDC-1100][DDC-1331] Implemented support to multi-values in INSTANCE OF expression. 2011-08-15 01:53:56 -03:00
Guilherme Blanco b9a24b5487 Merge pull request #93 from kwiateusz/UnitTestsUpdate
Last change from assertTrue($a instanceof $b) to assertInstanceOf
2011-08-14 21:05:15 -07:00
Benjamin Eberlei 2ee3cdeb0c Merge pull request #106 from FabioBatSilva/master
[DDC-1325] @Target annotation
2011-08-14 10:22:13 -07:00
Benjamin Eberlei 7782780cda Merge branch 'master' of github.com:doctrine/doctrine2 2011-08-14 19:20:30 +02:00
Dominik Liebler 6e47d7b16d DDC-1278 - EntityManager::clear($entity) support
added test case and modified test data CmsUser to cascade detach address and articles (testing collections and single entites)
2011-08-14 16:12:12 +02:00
Guilherme Blanco a0ca506db7 Added support to SingleValuePathExpression in ORDER BY. 2011-08-14 00:46:02 -03:00
Guilherme Blanco 63a2f02f4d [DDC-408][DDC-1150][DDC-1277] Implemented support to parameter expanding on associations. 2011-08-13 21:28:54 -03:00
Fabio B. Silva a04d2933fa @Target annotation and support to common 2.2-DEV 2011-08-13 16:28:05 -03:00
Dominik Liebler 25f5ff0ca1 DDC-1278 - EntityManager::clear($entity) support
cascade detach operation only on entity name entities
2011-08-13 20:22:23 +02:00
Dominik Liebler 745535d269 fixed typo 2011-08-12 20:15:32 +02:00
Dominik Liebler 05fb0b913a DDC-1278 - EntityManager::clear($entity) support
added new parameter $entityName for UnitOfWork::clear()
removed not implemented exception in EntityManager:clear()
2011-08-11 23:03:26 +02:00
Guilherme Blanco e13720c33d Merge pull request #103 from rdohms/patch-1
Add getReader to AnnotationDriver
2011-08-10 11:11:41 -07:00
Rafael Dohms 07e1c1e2e1 Added method to retrieve currently used Reader. This allows projects that use Doctrine to recycle the reader to use with other annotation-driven packages, like DMS\Filter and Symfony\Validator 2011-08-10 15:10:09 -03:00
Guilherme Blanco 816ce41f63 Added support to CaseExpression. Added support to nest AndX and OrX QueryBuilder composite expressions, since they do not mess with generated queries. 2011-08-08 02:09:25 -03:00
Benjamin Eberlei 1666d59da4 Merge branch 'DDC-1300' 2011-08-06 20:25:52 +02:00
Benjamin Eberlei bcc7bb1c9c DDC-1300 - Fix bug in fetch join hydration of entities with foreign key identifier 2011-08-06 20:25:45 +02:00
Benjamin Eberlei 15c877b8e8 Merge branch 'master' of github.com:doctrine/doctrine2 2011-08-06 18:15:00 +02:00
Guilherme Blanco 19682bf87a Merge pull request #102 from schmittjoh/configUpdate
updated configuration
2011-08-05 07:56:31 -07:00
Johannes Schmitt 7e47a601b0 updated configuration 2011-08-05 16:48:05 +02:00
Benjamin Eberlei c85de03b66 Add phar packaging target and distribute phar into download folder 2011-08-01 23:09:03 +02:00
Benjamin Eberlei d3beb7e23e Merge branch 'DDC-1313' 2011-08-01 21:45:39 +02:00
Benjamin Eberlei ba882be76b DDC-1313 - Optimize behavior of DriverChain::getAllClassNames() 2011-08-01 21:45:21 +02:00
Benjamin Eberlei e12a5fb328 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-31 11:41:30 +02:00
Benjamin Eberlei d583b149ac Merge pull request #98 from asm89/master
[DDC-1301] Fixed tests teardown for mysql suite
2011-07-31 02:41:19 -07:00
Benjamin Eberlei 4675f65bea Merge branch 'DDC-1302' 2011-07-31 11:34:27 +02:00
Benjamin Eberlei 816039f23f DDC-1302 - Fix bug in XmlDriver not handling orphan removal 2011-07-31 11:32:57 +02:00
Alexander 953a0f6572 [DDC-1301] Fixed tests teardown for mysql suite 2011-07-29 09:35:59 +02:00
Benjamin Eberlei c34612b8e9 [DDC-1298] DDC117Link file got lost from 2.1.x to master somehow 2011-07-28 23:44:11 +02:00
Benjamin Eberlei f8558d7740 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-28 23:26:24 +02:00
Benjamin Eberlei 5c47c07794 Merge pull request #97 from asm89/DDC-1301
[DDC-1301] Fixed count() for fetch="EXTRA_LAZY" on OneToMany association
2011-07-28 14:26:15 -07:00
Benjamin Eberlei 3d788a10cf Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-28 23:19:44 +02:00
Benjamin Eberlei 8f589e5876 Merge pull request #92 from mridgway/DDC-1275
DDC-1275: Added join columns to result set mapping
2011-07-28 14:18:55 -07:00
Michael Ridgway 1250cd7a5a F[DDC-1275] ixed check for owning side of a toOne relationship 2011-07-28 10:50:22 -04:00
Alexander d439f67df5 [DDC-1301] Prefixed all Legacy models properties with _ 2011-07-28 12:25:23 +02:00
Alexander d7dbde8f3e [DDC-1301] Fixed count() for fetch="EXTRA_LAZY" on OneToMany association 2011-07-28 11:01:52 +02:00
Alexander b2951691e2 [DDC-1301] Added tests for fetch="EXTRA_LAZY" count() on a "legacy" database 2011-07-28 11:01:28 +02:00
Benjamin Eberlei 656beb635c Merge branch 'DDC-1298' 2011-07-27 23:26:06 +02:00
Benjamin Eberlei 196632978c DDC-1298 - Fix bug in SQLWalker with derived entities that have no fields of their own. 2011-07-27 23:22:20 +02:00
kwiateusz d1e9bc6401 Now findByOne really retrieve only one entity adding limit to query. 2011-07-27 15:43:27 +02:00
kwiateusz a47af43bc1 Last change from assertTrue($a instanceof $b) to assertInstanceOf 2011-07-27 08:54:06 +02:00
Michael Ridgway 7f20a32db3 Removing debug comment 2011-07-26 17:39:57 -04:00
Michael Ridgway 154fd60d85 DDC-1275: Added join columns to result set mapping 2011-07-26 17:35:06 -04:00
Benjamin Eberlei a0b7c3e76d Add UPGRADE_TO_2_2 file 2011-07-26 23:16:38 +02:00
Benjamin Eberlei 7584ef6ba1 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-26 23:14:57 +02:00
Benjamin Eberlei 57cfcfd20e Merge pull request #79 from mridgway/DDC-725
[DDC-725] Removed onUpdate property on join columns
2011-07-26 14:14:30 -07:00
Benjamin Eberlei e73605e177 Merge pull request #90 from mweimerskirch/patch-2
Corrected typo
2011-07-26 14:12:19 -07:00
Benjamin Eberlei 6abe8e412c Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-26 23:03:30 +02:00
Benjamin Eberlei 79d99b11ad Merge pull request #91 from kwiateusz/UnitTestsUpdate
Removed deprecated assertType (thanks @kwiateusz)
2011-07-26 14:03:04 -07:00
Benjamin Eberlei 41a9e9689b Merge branch 'DDC-1215' 2011-07-26 23:00:11 +02:00
Benjamin Eberlei 598ab36968 [DDC-1215] Fix EntityGenerator inheritance regenerating properties and methods 2011-07-26 22:59:55 +02:00
Benjamin Eberlei 2e3d2398d9 Merge branch 'DDC-1280' 2011-07-26 22:30:27 +02:00
Benjamin Eberlei 93d2e1bd0a [DDC-1280] Only generate linefeeds in proxies for consistency. 2011-07-26 22:30:20 +02:00
Benjamin Eberlei cbf210605a [DDC-1290] Allow smallint and bigint for version fields 2011-07-26 22:24:16 +02:00
Benjamin Eberlei 2a59da1f03 Merge branch 'DDC-1276' 2011-07-26 22:15:37 +02:00
Benjamin Eberlei a99ffc126f 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:15:27 +02:00
Benjamin Eberlei 423651e45e Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-26 20:37:37 +02:00
Alexander 6cf7bdc2b7 Merge branch 'master' into DDC-551 2011-07-26 17:26:00 +02:00
Guilherme Blanco 1d9016e48f Merge pull request #88 from asm89/DDC-1294
[DDC-1294] Add discriminator information to subselects
2011-07-26 08:14:36 -07:00
Alexander 97a4dbf2cd [DDC-1294] Added more tests for subselects in subselects 2011-07-26 17:15:21 +02:00
kwiateusz 7261060905 Few more converts from assertTrue($a instance of $b) to assertInstanceOf 2011-07-26 15:22:57 +02:00
kwiateusz 1ea3e543ab Correted indentation and variable name 2011-07-26 12:10:30 +02:00
kwiateusz 49c735109c Change from assertType to assertInstanceOf.
Now PHPUnit doesn't show warning about deprecation of assertType.
Also some refractoring from assertTrue($a instanceof $b) to assertInstanceOf.
Leading \ in namespaces is not required so I removed it from few assertions.
2011-07-26 11:38:09 +02:00
Michel Weimerskirch 6ef4ac62d7 Missed another typo 2011-07-26 11:03:23 +03:00
Michel Weimerskirch b58f573b31 Corrected typo 2011-07-26 10:59:21 +03:00
Alexander 65f7e897b5 [DDC-1294] Add discriminator information to subselects 2011-07-26 00:19:26 +02:00
Alexander e3dcfa8702 [DDC-551] Added filters to query hash + tests for hash 2011-07-22 17:01:18 +02:00
Guilherme Blanco 4b85d7a683 Reverted PR #86, which broke our suite. 2011-07-22 11:38:20 -03:00
Alexander 6163d9d932 [DDC-551] Added enabled filters to Query hash 2011-07-22 15:26:03 +02:00
Alexander afd7a540a7 [DDC-551] Removed 'use ..DBAL\..\Type', causing full testsuite to fail 2011-07-22 15:10:31 +02:00
Alexander 4266ab77b2 [DDC-551] Added __toString() method to SQLFilter 2011-07-22 14:55:00 +02:00
Alexander 4cf63a4e83 [DDC-551] Fixed the escaping of filter parameters 2011-07-22 14:51:30 +02:00
Alexander d1908f7207 [DDC-551] Keep filter parameters and enabled filters sorted for hashing 2011-07-22 14:36:14 +02:00
Alexander 277fc751b6 [DDC-551] Added tests for SQLFilter 2011-07-22 13:51:26 +02:00
Alexander b867744f15 [DDC-551] Added tests for SQLFilter functionality + small fixes 2011-07-22 13:08:49 +02:00
Alexander a85902b08d [DDC-551] Initial code for filter functionality 2011-07-22 12:01:33 +02:00
Guilherme Blanco 4be7c3dac0 Merge pull request #85 from FabienPennequin/fix_ClassMetadataFactory
Fixed php notice in ClassMetadataFactory
2011-07-21 10:02:15 -07:00
Guilherme Blanco 01d6ec35c4 Merge pull request #86 from kwiateusz/findByOne-patch
Now findByOne really retrieve only one entity adding limit to query
2011-07-21 10:01:21 -07:00
kwiateusz 570799b48d Restoring the missing comment 2011-07-21 04:13:15 -07:00
kwiateusz 0e6121e8f5 Now findByOne really retrieve only one entity adding limit to query 2011-07-21 12:40:43 +02:00
Fabien Pennequin 99bdf65c10 Fixed php notice in ClassMetadataFactory 2011-07-17 19:39:55 +02:00
Benjamin Eberlei 180dbbad8b Merge branch 'EntityGenerator' 2011-07-12 23:46:13 +02:00
Benjamin Eberlei d9b1dbbb09 DDC-1244 - Fix bug with entities without namespace 2011-07-12 23:43:24 +02:00
Benjamin Eberlei c87dedbec5 DDC-1254 - Dont throw exception about missing id in disconnected metadata factory 2011-07-12 23:39:56 +02:00
Benjamin Eberlei 4796452b07 DDC-1268 - Singular add*() method name through using targetEntity shortname 2011-07-12 23:25:15 +02:00
Benjamin Eberlei fb11268255 Merge branch 'DDC-1240' 2011-07-12 22:50:31 +02:00
Benjamin Eberlei 98fabd98be DDC-1240 - Fix optimistic lock exception loosing the message 2011-07-12 22:50:21 +02:00
Benjamin Eberlei 5733574867 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-12 22:47:33 +02:00
Benjamin Eberlei 409c16b898 Merge branch 'DDC-1250' 2011-07-09 22:12:15 +02:00
Benjamin Eberlei c261315ea7 DDC-1250 - Fix bug with inverse one to one loading and ambigious column names in certain scenarios 2011-07-09 22:11:49 +02:00
Benjamin Eberlei 8b92dc5265 Merge branch 'DDC-1257' 2011-07-09 15:14:31 +02:00
Benjamin Eberlei 442a2b3a51 DDC-1257 - Fix bug where validation callbacks are added multiple times in EntityGenerator 2011-07-09 15:11:16 +02:00
Benjamin Eberlei 305e0345ef Merge branch 'DDC-1251' 2011-07-09 14:53:39 +02:00
Benjamin Eberlei a8048af65d DDC-1251 - Fix bug in token parsing of EntityGenerator 2011-07-09 14:53:25 +02:00
Benjamin Eberlei d7da292f60 Merge remote branch 'origin/master' 2011-07-09 14:43:04 +02:00
Benjamin Eberlei 689eaf3172 Merge branch 'DDC-1022' 2011-07-09 12:12:56 +02:00
Benjamin Eberlei 2b207106a3 DDC-1022 - Call __wakeup() with the same semantics then ClassMetadata::newInstance() does inside UnitOfWork 2011-07-09 12:12:44 +02:00
Guilherme Blanco 9d1a647753 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-08 16:27:20 -03:00
Guilherme Blanco b6bd46dbed General fix for end point as file extension on Annotation driver. 2011-07-08 16:26:54 -03:00
Benjamin Eberlei 9a68074878 Clarify possible problem 2011-07-08 14:42:15 +02:00
Benjamin Eberlei ac76dafe62 Add doccomments, refactor into listener and dump method to allow re-use 2011-07-08 14:32:12 +02:00
Benjamin Eberlei ef663c83f3 DDC-1258 - Add Debug UnitOfWork Listener 2011-07-08 14:27:59 +02:00
Benjamin Eberlei 024b7b7cb6 Bump Dev Version to 2.2.0-DEV 2011-07-04 21:34:59 +00:00
Benjamin Eberlei 5c2a4c0339 Merge branch 'DDC-1238' 2011-07-04 23:19:26 +02:00
Benjamin Eberlei 2858b8290f 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-04 23:19:08 +02:00
Benjamin Eberlei a638154046 Update tests 2011-07-04 20:59:46 +02:00
Benjamin Eberlei a947e8a4b0 DDC-1238 - Reproducible case, its correct through 2011-07-04 20:59:46 +02:00
Benjamin Eberlei 8e7c156451 Started trying to reproduce this issue 2011-07-04 20:59:46 +02:00
Benjamin Eberlei 0529efc843 Merge branch 'master' of github.com:doctrine/doctrine2 2011-07-04 19:52:35 +02:00
Michael Ridgway c19d7fe2eb Missed one 2011-06-28 15:55:43 -04:00
Michael Ridgway 9ae30421dd Removed onUpdate property on join columns 2011-06-28 15:50:14 -04:00
Benjamin Eberlei bc4e14a99f Prototype for a proxy extension that avoids loads when calling for a getter that is named after an identifier. 2011-05-20 20:50:03 +02:00
467 changed files with 21217 additions and 6709 deletions
+3
View File
@@ -6,3 +6,6 @@ download/
lib/api/
lib/Doctrine/Common
lib/Doctrine/DBAL
/.settings/
.buildpath
.project
+1 -1
View File
@@ -16,4 +16,4 @@ before_script:
- 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
script: phpunit --configuration tests/travis/$DB.travis.xml
+7 -3
View File
@@ -1,14 +1,18 @@
# Doctrine 2 ORM
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.0+ that provides transparent persistence
Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2)
2.1.x: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
without requiring unnecessary code duplication.
More resources:
## More resources:
* [Website](http://www.doctrine-project.org)
* [Documentation](http://www.doctrine-project.org/projects/orm/2.0/docs/reference/introduction/en)
* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DDC)
* [Downloads](http://github.com/doctrine/doctrine2/downloads)
* [Downloads](http://github.com/doctrine/doctrine2/downloads)
+1
View File
@@ -9,6 +9,7 @@ The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepo
The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way:
// new call to the AnnotationRegistry
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
+76
View File
@@ -0,0 +1,76 @@
# 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.
+2 -2
View File
@@ -2,8 +2,8 @@
project.name=DoctrineORM
# Dependency minimum versions
dependencies.common=2.1.0
dependencies.dbal=2.1.0
dependencies.common=2.2.0beta1
dependencies.dbal=2.2.0beta1
dependencies.sfconsole=2.0.0
# Version class and file
+16
View File
@@ -0,0 +1,16 @@
version=2.0.0BETA2
dependencies.common=2.0.0BETA4
dependencies.dbal=2.0.0BETA4
stability=beta
build.dir=build
dist.dir=dist
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
test.pdepend_exec=
test.phpmd_exec=
+2 -2
View File
@@ -92,8 +92,8 @@
<dependencies>
<php minimum_version="5.3.0" />
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" maximum_version="2.1.99" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" maximum_version="2.1.99" />
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" maximum_version="2.2.99" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" maximum_version="2.2.99" />
<package name="Console" channel="pear.symfony.com" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.com" minimum_version="2.0.0" />
</dependencies>
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "doctrine/orm",
"type": "library","version":"2.1.6",
"type": "library","version":"2.2.0",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",
@@ -14,8 +14,8 @@
"require": {
"php": ">=5.3.2",
"ext-pdo": "*",
"doctrine/common": "2.1.*",
"doctrine/dbal": "2.1.*"
"doctrine/common": ">=2.2.0,<2.2.99",
"doctrine/dbal": ">=2.2.1,<2.2.99"
},
"autoload": {
"psr-0": { "Doctrine\\ORM": "lib/" }
+1 -1
View File
@@ -150,7 +150,7 @@
<xs:restriction base="xs:token">
<xs:enumeration value="CASCADE"/>
<xs:enumeration value="RESTRICT"/>
<xs:enumeration value="SET_NULL"/>
<xs:enumeration value="SET NULL"/>
</xs:restriction>
</xs:simpleType>
+91 -124
View File
@@ -20,7 +20,8 @@
namespace Doctrine\ORM;
use Doctrine\DBAL\Types\Type,
Doctrine\ORM\Query\QueryException;
Doctrine\ORM\Query\QueryException,
Doctrine\DBAL\Cache\QueryCacheProfile;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -91,34 +92,15 @@ abstract class AbstractQuery
protected $_hydrationMode = self::HYDRATE_OBJECT;
/**
* The locally set cache driver used for caching result sets of this query.
*
* @var CacheDriver
* @param \Doctrine\DBAL\Cache\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;
protected $_queryCacheProfile;
/**
* @var boolean Boolean value that indicates whether or not expire the result cache.
*/
protected $_expireResultCache = false;
/**
* @var int Result Cache lifetime.
*/
protected $_resultCacheTTL;
/**
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
@@ -162,7 +144,7 @@ abstract class AbstractQuery
{
return $this->_params;
}
/**
* Get all defined parameter types.
*
@@ -181,7 +163,11 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
return isset($this->_params[$key]) ? $this->_params[$key] : null;
if (isset($this->_params[$key])) {
return $this->_params[$key];
}
return null;
}
/**
@@ -192,7 +178,11 @@ abstract class AbstractQuery
*/
public function getParameterType($key)
{
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
if (isset($this->_paramTypes[$key])) {
return $this->_paramTypes[$key];
}
return null;
}
/**
@@ -216,13 +206,15 @@ abstract class AbstractQuery
*/
public function setParameter($key, $value, $type = null)
{
$key = trim($key, ':');
if ($type === null) {
$type = Query\ParameterTypeInferer::inferType($value);
}
$this->_paramTypes[$key] = $type;
$this->_params[$key] = $value;
return $this;
}
@@ -236,12 +228,9 @@ abstract class AbstractQuery
public function setParameters(array $params, array $types = array())
{
foreach ($params as $key => $value) {
if (isset($types[$key])) {
$this->setParameter($key, $value, $types[$key]);
} else {
$this->setParameter($key, $value);
}
$this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
}
return $this;
}
@@ -254,11 +243,12 @@ abstract class AbstractQuery
public function setResultSetMapping(Query\ResultSetMapping $rsm)
{
$this->_resultSetMapping = $rsm;
return $this;
}
/**
* Defines a cache driver to be used for caching result sets.
* 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
@@ -268,25 +258,27 @@ abstract class AbstractQuery
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
throw ORMException::invalidResultCacheDriver();
}
$this->_resultCacheDriver = $resultCacheDriver;
if ($resultCacheDriver) {
$this->_useResultCache = true;
}
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
: new QueryCacheProfile(0, null, $resultCacheDriver);
return $this;
}
/**
* Returns the cache driver used for caching result sets.
*
* @deprecated
* @return \Doctrine\Common\Cache\Cache Cache driver
*/
public function getResultCacheDriver()
{
if ($this->_resultCacheDriver) {
return $this->_resultCacheDriver;
} else {
return $this->_em->getConfiguration()->getResultCacheImpl();
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
return $this->_queryCacheProfile->getResultCacheDriver();
}
return $this->_em->getConfiguration()->getResultCacheImpl();
}
/**
@@ -294,46 +286,50 @@ abstract class AbstractQuery
* how long and which ID to use for the cache entry.
*
* @param boolean $bool
* @param integer $timeToLive
* @param integer $lifetime
* @param string $resultCacheId
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function useResultCache($bool, $timeToLive = null, $resultCacheId = null)
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
{
$this->_useResultCache = $bool;
if ($timeToLive) {
$this->setResultCacheLifetime($timeToLive);
}
if ($resultCacheId) {
$this->_resultCacheId = $resultCacheId;
if ($bool) {
$this->setResultCacheLifetime($lifetime);
$this->setResultCacheId($resultCacheId);
return $this;
}
$this->_queryCacheProfile = null;
return $this;
}
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $timeToLive How long the cache entry is valid.
* @param integer $lifetime How long the cache entry is valid.
* @return \Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheLifetime($timeToLive)
public function setResultCacheLifetime($lifetime)
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setLifetime($lifetime)
: new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl());
$this->_resultCacheTTL = $timeToLive;
return $this;
}
/**
* Retrieves the lifetime of resultset cache.
*
* @deprecated
* @return integer
*/
public function getResultCacheLifetime()
{
return $this->_resultCacheTTL;
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0;
}
/**
@@ -345,6 +341,7 @@ abstract class AbstractQuery
public function expireResultCache($expire = true)
{
$this->_expireResultCache = $expire;
return $this;
}
@@ -358,6 +355,14 @@ 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.
*
@@ -375,6 +380,7 @@ abstract class AbstractQuery
}
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
return $this;
}
@@ -388,6 +394,7 @@ abstract class AbstractQuery
public function setHydrationMode($hydrationMode)
{
$this->_hydrationMode = $hydrationMode;
return $this;
}
@@ -452,14 +459,15 @@ abstract class AbstractQuery
return null;
}
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
if ( ! is_array($result)) {
return $result;
}
return $result;
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
/**
@@ -483,14 +491,15 @@ abstract class AbstractQuery
throw new NoResultException;
}
if (is_array($result)) {
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
if ( ! is_array($result)) {
return $result;
}
return $result;
if (count($result) > 1) {
throw new NonUniqueResultException;
}
return array_shift($result);
}
/**
@@ -516,6 +525,7 @@ abstract class AbstractQuery
public function setHint($name, $value)
{
$this->_hints[$name] = $value;
return $this;
}
@@ -532,7 +542,7 @@ abstract class AbstractQuery
/**
* Return the key value map of query hints that are currently set.
*
*
* @return array
*/
public function getHints()
@@ -546,7 +556,7 @@ abstract class AbstractQuery
*
* @param array $params The query parameters.
* @param integer $hydrationMode The hydration mode to use.
* @return IterableResult
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
*/
public function iterate(array $params = array(), $hydrationMode = null)
{
@@ -582,28 +592,6 @@ abstract class AbstractQuery
$this->setParameters($params);
}
// Check result cache
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
list($key, $hash) = $this->getResultCacheId();
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($hash);
if ($cached === false || !isset($cached[$key])) {
// Cache miss.
$stmt = $this->_doExecute();
$result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL);
return $result;
} else {
// Cache hit.
return $cached[$key];
}
}
$stmt = $this->_doExecute();
if (is_numeric($stmt)) {
@@ -611,8 +599,8 @@ abstract class AbstractQuery
}
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
);
$stmt, $this->_resultSetMapping, $this->_hints
);
}
/**
@@ -625,43 +613,22 @@ abstract class AbstractQuery
*/
public function setResultCacheId($id)
{
$this->_resultCacheId = $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.
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
* Get the result cache id to use to store the result set cache entry if set.
*
* @return array ($key, $hash)
* @deprecated
* @return string
*/
protected function getResultCacheId()
public function getResultCacheId()
{
if ($this->_resultCacheId) {
return array($this->_resultCacheId, $this->_resultCacheId);
} else {
$params = $this->_params;
foreach ($params AS $key => $value) {
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
} else {
$class = $this->_em->getClassMetadata(get_class($value));
$idValues = $class->getIdentifierValues($value);
}
$params[$key] = $idValues;
} else {
$params[$key] = $value;
}
}
$sql = $this->getSql();
ksort($this->_hints);
$key = implode(";", (array)$sql) . var_export($params, true) .
var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode;
return array($key, md5($key));
}
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null;
}
/**
+55 -24
View File
@@ -23,7 +23,6 @@ use Doctrine\Common\Cache\Cache,
Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationRegistry,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\Common\Annotations\SimpleAnnotationReader,
Doctrine\ORM\Mapping\Driver\Driver,
Doctrine\ORM\Mapping\Driver\AnnotationDriver;
@@ -129,7 +128,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
// Register the ORM Annotations in the AnnotationRegistry
AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php');
$reader = new SimpleAnnotationReader();
$reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
} else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0-DEV', '>=')) {
@@ -210,27 +209,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['metadataDriverImpl'] : null;
}
/**
* Gets the cache driver implementation that is used for query result caching.
*
* @return \Doctrine\Common\Cache\Cache
*/
public function getResultCacheImpl()
{
return isset($this->_attributes['resultCacheImpl']) ?
$this->_attributes['resultCacheImpl'] : null;
}
/**
* Sets the cache driver implementation that is used for query result caching.
*
* @param \Doctrine\Common\Cache\Cache $cacheImpl
*/
public function setResultCacheImpl(Cache $cacheImpl)
{
$this->_attributes['resultCacheImpl'] = $cacheImpl;
}
/**
* Gets the cache driver implementation that is used for the query cache (SQL cache).
*
@@ -517,4 +495,57 @@ class Configuration extends \Doctrine\DBAL\Configuration
}
return $this->_attributes['classMetadataFactoryName'];
}
}
/**
* Add a filter to the list of possible filters.
*
* @param string $name The name of the filter.
* @param string $className The class name of the filter.
*/
public function addFilter($name, $className)
{
$this->_attributes['filters'][$name] = $className;
}
/**
* Gets the class name for a given filter name.
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null of it is not
* defined.
*/
public function getFilterClassName($name)
{
return isset($this->_attributes['filters'][$name]) ?
$this->_attributes['filters'][$name] : null;
}
/**
* Set default repository class.
*
* @since 2.2
* @param string $className
* @throws ORMException If not is a \Doctrine\ORM\EntityRepository
*/
public function setDefaultRepositoryClassName($className)
{
if ($className != "Doctrine\ORM\EntityRepository" &&
!is_subclass_of($className, 'Doctrine\ORM\EntityRepository')){
throw ORMException::invalidEntityRepository($className);
}
$this->_attributes['defaultRepositoryClassName'] = $className;
}
/**
* Get default repository class.
*
* @since 2.2
* @return string
*/
public function getDefaultRepositoryClassName()
{
return isset($this->_attributes['defaultRepositoryClassName']) ?
$this->_attributes['defaultRepositoryClassName'] : 'Doctrine\ORM\EntityRepository';
}
}
+141 -58
View File
@@ -27,7 +27,8 @@ use Closure, Exception,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Query\ResultSetMapping,
Doctrine\ORM\Proxy\ProxyFactory;
Doctrine\ORM\Proxy\ProxyFactory,
Doctrine\ORM\Query\FilterCollection;
/**
* The EntityManager is the central access point to ORM functionality.
@@ -110,6 +111,13 @@ class EntityManager implements ObjectManager
*/
private $closed = false;
/**
* Collection of query filters.
*
* @var Doctrine\ORM\Query\FilterCollection
*/
private $filterCollection;
/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
@@ -130,10 +138,12 @@ class EntityManager implements ObjectManager
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
$this->unitOfWork = new UnitOfWork($this);
$this->proxyFactory = new ProxyFactory($this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses());
$this->proxyFactory = new ProxyFactory(
$this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses()
);
}
/**
@@ -175,6 +185,7 @@ class EntityManager implements ObjectManager
if ($this->expressionBuilder === null) {
$this->expressionBuilder = new Query\Expr;
}
return $this->expressionBuilder;
}
@@ -199,6 +210,7 @@ class EntityManager implements ObjectManager
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
*
* @param Closure $func The function to execute transactionally.
* @return mixed Returns the non-empty value returned from the closure or true instead
*/
public function transactional(Closure $func)
{
@@ -266,9 +278,11 @@ class EntityManager implements ObjectManager
public function createQuery($dql = "")
{
$query = new Query($this);
if ( ! empty($dql)) {
$query->setDql($dql);
}
return $query;
}
@@ -295,6 +309,7 @@ class EntityManager implements ObjectManager
$query = new NativeQuery($this);
$query->setSql($sql);
$query->setResultSetMapping($rsm);
return $query;
}
@@ -307,6 +322,7 @@ class EntityManager implements ObjectManager
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@@ -325,13 +341,18 @@ 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
* makes use of optimistic locking fails.
*/
public function flush()
public function flush($entity = null)
{
$this->errorIfClosed();
$this->unitOfWork->commit();
$this->unitOfWork->commit($entity);
}
/**
@@ -355,27 +376,39 @@ 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 $identifier The entity identifier.
* @param mixed $id The entity identifier.
* @return object The entity reference.
*/
public function getReference($entityName, $identifier)
public function getReference($entityName, $id)
{
$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($identifier, $class->rootEntityName)) {
if ($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ($class->subClasses) {
$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());
return $this->find($entityName, $sortedId);
}
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;
}
@@ -406,6 +439,7 @@ class EntityManager implements ObjectManager
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return ($entity instanceof $class->name) ? $entity : null;
}
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
@@ -422,16 +456,11 @@ class EntityManager implements ObjectManager
* Clears the EntityManager. All entities that are currently managed
* by this EntityManager become detached.
*
* @param string $entityName
* @param string $entityName if given, only entities of this type will get detached
*/
public function clear($entityName = null)
{
if ($entityName === null) {
$this->unitOfWork->clear();
} else {
//TODO
throw new ORMException("EntityManager#clear(\$entityName) not yet implemented.");
}
$this->unitOfWork->clear($entityName);
}
/**
@@ -461,7 +490,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->persist($entity);
}
@@ -478,7 +509,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->remove($entity);
}
@@ -493,7 +526,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
$this->unitOfWork->refresh($entity);
}
@@ -511,6 +546,7 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->unitOfWork->detach($entity);
}
@@ -527,7 +563,9 @@ class EntityManager implements ObjectManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->errorIfClosed();
return $this->unitOfWork->merge($entity);
}
@@ -567,19 +605,20 @@ class EntityManager implements ObjectManager
public function getRepository($entityName)
{
$entityName = ltrim($entityName, '\\');
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customRepositoryClassName = $metadata->customRepositoryClassName;
$repositoryClassName = $metadata->customRepositoryClassName;
if ($customRepositoryClassName !== null) {
$repository = new $customRepositoryClassName($this, $metadata);
} else {
$repository = new EntityRepository($this, $metadata);
if ($repositoryClassName === null) {
$repositoryClassName = $this->config->getDefaultRepositoryClassName();
}
$repository = new $repositoryClassName($this, $metadata);
$this->repositories[$entityName] = $repository;
return $repository;
@@ -593,9 +632,9 @@ 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);
}
/**
@@ -678,29 +717,27 @@ class EntityManager implements ObjectManager
{
switch ($hydrationMode) {
case Query::HYDRATE_OBJECT:
$hydrator = new Internal\Hydration\ObjectHydrator($this);
break;
return new Internal\Hydration\ObjectHydrator($this);
case Query::HYDRATE_ARRAY:
$hydrator = new Internal\Hydration\ArrayHydrator($this);
break;
return new Internal\Hydration\ArrayHydrator($this);
case Query::HYDRATE_SCALAR:
$hydrator = new Internal\Hydration\ScalarHydrator($this);
break;
return new Internal\Hydration\ScalarHydrator($this);
case Query::HYDRATE_SINGLE_SCALAR:
$hydrator = new Internal\Hydration\SingleScalarHydrator($this);
break;
return new Internal\Hydration\SingleScalarHydrator($this);
case Query::HYDRATE_SIMPLEOBJECT:
$hydrator = new Internal\Hydration\SimpleObjectHydrator($this);
break;
return new Internal\Hydration\SimpleObjectHydrator($this);
default:
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
$hydrator = new $class($this);
break;
return new $class($this);
}
throw ORMException::invalidHydrationMode($hydrationMode);
}
return $hydrator;
throw ORMException::invalidHydrationMode($hydrationMode);
}
/**
@@ -714,11 +751,15 @@ class EntityManager implements ObjectManager
}
/**
* {@inheritDoc}
* 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($entity)
public function initializeObject($obj)
{
$this->unitOfWork->initializeObject($entity);
$this->unitOfWork->initializeObject($obj);
}
/**
@@ -732,20 +773,62 @@ class EntityManager implements ObjectManager
*/
public static function create($conn, Configuration $config, EventManager $eventManager = null)
{
if (!$config->getMetadataDriverImpl()) {
if ( ! $config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
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);
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);
}
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;
}
}
+60 -39
View File
@@ -107,42 +107,51 @@ class EntityRepository implements ObjectRepository
*/
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
if ( ! is_array($id)) {
$id = array($this->_class->identifier[0] => $id);
}
$sortedId = array();
foreach ($this->_class->identifier as $identifier) {
if (!isset($id[$identifier])) {
throw ORMException::missingIdentifierField($this->_class->name, $identifier);
}
$sortedId[$identifier] = $id[$identifier];
}
// Check identity map first
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
if (!($entity instanceof $this->_class->name)) {
if ($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) {
if ( ! ($entity instanceof $this->_class->name)) {
return null;
}
if ($lockMode != LockMode::NONE) {
if ($lockMode !== LockMode::NONE) {
$this->_em->lock($entity, $lockMode, $lockVersion);
}
return $entity; // Hit!
}
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);
}
switch ($lockMode) {
case LockMode::NONE:
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
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);
case LockMode::OPTIMISTIC:
if ( ! $this->_class->isVersioned) {
throw OptimisticLockException::notVersioned($this->_entityName);
}
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
return $entity;
} else {
if (!$this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
return $entity;
default:
if ( ! $this->_em->getConnection()->isTransactionActive()) {
throw TransactionRequiredException::transactionRequired();
}
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId, null, null, array(), $lockMode);
}
}
@@ -178,7 +187,7 @@ class EntityRepository implements ObjectRepository
*/
public function findOneBy(array $criteria)
{
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria);
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria, null, null, array(), 0, 1);
}
/**
@@ -191,31 +200,35 @@ class EntityRepository implements ObjectRepository
*/
public function __call($method, $arguments)
{
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!"
);
switch (true) {
case (substr($method, 0, 6) == 'findBy'):
$by = substr($method, 6, strlen($method));
$method = 'findBy';
break;
case (substr($method, 0, 9) == 'findOneBy'):
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
break;
default:
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
}
if ( !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);
if (empty($arguments)) {
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
return $this->$method(array($fieldName => $arguments[0]));
} else {
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/**
@@ -226,6 +239,14 @@ class EntityRepository implements ObjectRepository
return $this->_entityName;
}
/**
* @return string
*/
public function getClassName()
{
return $this->getEntityName();
}
/**
* @return EntityManager
*/
+33 -16
View File
@@ -19,42 +19,59 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\EntityManager;
/**
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
* of entities.
*
* @since 2.0
* @link www.doctrine-project.org
* @since 2.0
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
class LifecycleEventArgs extends EventArgs
{
/**
* @var EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $_em;
private $em;
/**
* @var object
*/
private $_entity;
public function __construct($entity, $em)
private $entity;
/**
* Constructor
*
* @param object $entity
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct($entity, EntityManager $em)
{
$this->_entity = $entity;
$this->_em = $em;
}
public function getEntity()
{
return $this->_entity;
$this->entity = $entity;
$this->em = $em;
}
/**
* @return EntityManager
* Retireve associated Entity.
*
* @return object
*/
public function getEntity()
{
return $this->entity;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->_em;
return $this->em;
}
}
@@ -1,9 +1,25 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\EntityManager;
@@ -11,32 +27,36 @@ 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 ClassMetadata
* @var \Doctrine\ORM\Mapping\ClassMetadata
*/
private $classMetadata;
/**
* @var EntityManager
* @var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* @param ClassMetadataInfo $classMetadata
* @param EntityManager $em
* Constructor.
*
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
{
$this->classMetadata = $classMetadata;
$this->em = $em;
$this->em = $em;
}
/**
* @return ClassMetadataInfo
* Retrieve associated ClassMetadata.
*
* @return \Doctrine\ORM\Mapping\ClassMetadataInfo
*/
public function getClassMetadata()
{
@@ -44,7 +64,9 @@ class LoadClassMetadataEventArgs extends EventArgs
}
/**
* @return EntityManager
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
+36 -6
View File
@@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
*/
namespace Doctrine\ORM\Event;
@@ -23,9 +23,8 @@ 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.com
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
@@ -37,18 +36,49 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
private $em;
/**
* @param \Doctrine\ORM\EntityManager $em
* @var string
*/
public function __construct($em)
private $entityClass;
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
* @param string $entityClass Optional entity class
*/
public function __construct($em, $entityClass = null)
{
$this->em = $em;
$this->em = $em;
$this->entityClass = $entityClass;
}
/**
* 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);
}
}
+27 -19
View File
@@ -21,55 +21,63 @@
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.com
* @link www.doctrine-project.org
* @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 EntityManager
* @var Doctirne\ORM\EntityManager
*/
private $_em;
//private $_entitiesToPersist = array();
//private $_entitiesToRemove = array();
public function __construct($em)
private $em;
//private $entitiesToPersist = array();
//private $entitiesToRemove = array();
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->em = $em;
}
/**
* @return EntityManager
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\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;
@@ -0,0 +1,61 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\EventArgs;
/**
* Provides event arguments for the postFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Daniel Freudenberger <df@rebuy.de>
*/
class PostFlushEventArgs extends EventArgs
{
/**
* @var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* Constructor.
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* Retrieve associated EntityManager.
*
* @return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->em;
}
}
@@ -0,0 +1,53 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
/**
* Provides event arguments for the preFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class PreFlushEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var EntityManager
*/
private $_em;
public function __construct($em)
{
$this->_em = $em;
}
/**
* @return EntityManager
*/
public function getEntityManager()
{
return $this->_em;
}
}
+59 -26
View File
@@ -1,4 +1,23 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event;
@@ -8,55 +27,63 @@ 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 EntityManager $em
* @param \Doctrine\ORM\EntityManager $em
* @param array $changeSet
*/
public function __construct($entity, $em, array &$changeSet)
public function __construct($entity, EntityManager $em, array &$changeSet)
{
parent::__construct($entity, $em);
$this->_entityChangeSet = &$changeSet;
}
public function getEntityChangeSet()
{
return $this->_entityChangeSet;
$this->entityChangeSet = &$changeSet;
}
/**
* Field has a changeset?
* Retrieve entity changeset.
*
* @return bool
* @return array
*/
public function getEntityChangeSet()
{
return $this->entityChangeSet;
}
/**
* Check if field has a changeset.
*
* @return boolean
*/
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];
}
/**
@@ -67,31 +94,37 @@ 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;
}
private function _assertValidField($field)
/**
* Assert the field exists in changeset.
*
* @param string $field
*/
private function assertValidField($field)
{
if (!isset($this->_entityChangeSet[$field])) {
throw new \InvalidArgumentException(
"Field '".$field."' is not a valid field of the entity ".
"'".get_class($this->getEntity())."' in PreInsertUpdateEventArgs."
);
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())
));
}
}
}
+42 -24
View File
@@ -35,55 +35,55 @@ final class Events
/**
* The preRemove event occurs for a given entity before the respective
* EntityManager remove operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preRemove = 'preRemove';
/**
* The postRemove event occurs for an entity after the entity has
* The postRemove event occurs for an entity after the entity has
* been deleted. It will be invoked after the database delete operations.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postRemove = 'postRemove';
/**
* The prePersist event occurs for a given entity before the respective
* EntityManager persist operation for that entity is executed.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const prePersist = 'prePersist';
/**
* The postPersist event occurs for an entity after the entity has
* The postPersist event occurs for an entity after the entity has
* been made persistent. It will be invoked after the database insert operations.
* Generated primary key values are available in the postPersist event.
*
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postPersist = 'postPersist';
/**
* The preUpdate event occurs before the database update operations to
* entity data.
*
* The preUpdate event occurs before the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const preUpdate = 'preUpdate';
/**
* The postUpdate event occurs after the database update operations to
* entity data.
*
* The postUpdate event occurs after the database update operations to
* entity data.
*
* This is an entity lifecycle event.
*
*
* @var string
*/
const postUpdate = 'postUpdate';
@@ -91,35 +91,53 @@ 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.
+1 -1
View File
@@ -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.
*
+21 -37
View File
@@ -20,6 +20,7 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException;
/**
@@ -42,46 +43,29 @@ class AssignedGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
$class = $em->getClassMetadata(get_class($entity));
$class = $em->getClassMetadata(get_class($entity));
$idFields = $class->getIdentifierFieldNames();
$identifier = array();
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);
}
}
} else {
$idField = $class->identifier[0];
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);
if ( ! isset($value)) {
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
}
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.
$value = current($em->getUnitOfWork()->getEntityIdentifier($value));
}
$identifier[$idField] = $value;
}
return $identifier;
}
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
return $em->getConnection()->lastInsertId($this->_seqName);
return (int)$em->getConnection()->lastInsertId($this->_seqName);
}
/**
+8 -5
View File
@@ -46,7 +46,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
$this->_sequenceName = $sequenceName;
$this->_allocationSize = $allocationSize;
}
/**
* Generates an ID for the given entity.
*
@@ -59,10 +59,12 @@ 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 = $conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = (int)$conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
}
return $this->_nextValue++;
}
@@ -90,13 +92,14 @@ 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'];
}
+5 -3
View File
@@ -50,11 +50,12 @@ 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;
@@ -62,7 +63,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
}
@@ -74,6 +75,7 @@ class TableGenerator extends AbstractIdGenerator
// or do we want to work with table locks exclusively?
}
}
return $this->_nextValue++;
}
}
@@ -23,20 +23,21 @@ 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>
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
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.
*
@@ -47,10 +48,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.
*
@@ -60,17 +61,16 @@ class CommitOrderCalculator
{
// Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount = count($this->_classes);
if ($nodeCount == 0) {
return array();
} else if ($nodeCount == 1) {
return array_values($this->_classes);
if ($nodeCount <= 1) {
return ($nodeCount == 1) ? array_values($this->_classes) : array();
}
// Init
foreach ($this->_classes as $node) {
$this->_nodeStates[$node->name] = self::NOT_VISITED;
}
// Go
foreach ($this->_classes as $node) {
if ($this->_nodeStates[$node->name] == self::NOT_VISITED) {
@@ -100,17 +100,17 @@ class CommitOrderCalculator
$this->_nodeStates[$node->name] = self::VISITED;
$this->_sorted[] = $node;
}
public function addDependency($fromClass, $toClass)
{
$this->_relatedClasses[$fromClass->name][] = $toClass;
}
public function hasClass($className)
{
return isset($this->_classes[$className]);
}
public function addClass($class)
{
$this->_classes[$class->name] = $class;
@@ -22,15 +22,17 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager;
Doctrine\ORM\EntityManager,
Doctrine\ORM\Mapping\ClassMetadata;
/**
* 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>
* @since 2.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*/
abstract class AbstractHydrator
{
@@ -62,9 +64,9 @@ abstract class AbstractHydrator
*/
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->_em = $em;
$this->_platform = $em->getConnection()->getDatabasePlatform();
$this->_uow = $em->getUnitOfWork();
$this->_uow = $em->getUnitOfWork();
}
/**
@@ -72,14 +74,17 @@ abstract class AbstractHydrator
*
* @param object $stmt
* @param object $resultSetMapping
*
* @return IterableResult
*/
public function iterate($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->_prepare();
$this->prepare();
return new IterableResult($this);
}
@@ -92,12 +97,16 @@ abstract class AbstractHydrator
*/
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->_prepare();
$result = $this->_hydrateAll();
$this->_cleanup();
$this->prepare();
$result = $this->hydrateAllData();
$this->cleanup();
return $result;
}
@@ -110,12 +119,17 @@ abstract class AbstractHydrator
public function hydrateRow()
{
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
if ( ! $row) {
$this->_cleanup();
$this->cleanup();
return false;
}
$result = array();
$this->_hydrateRow($row, $this->_cache, $result);
$this->hydrateRowData($row, $this->_cache, $result);
return $result;
}
@@ -123,16 +137,17 @@ 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;
}
@@ -146,23 +161,24 @@ abstract class AbstractHydrator
* @param array $cache The cache to use.
* @param mixed $result The result to fill.
*/
protected function _hydrateRow(array $data, array &$cache, array &$result)
protected function hydrateRowData(array $data, array &$cache, array &$result)
{
throw new HydrationException("_hydrateRow() not implemented by this hydrator.");
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
}
/**
* Hydrates all rows from the current statement instance at once.
*/
abstract protected function _hydrateAll();
abstract protected function hydrateAllData();
/**
* 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 class
* Puts the elements of a result row into a new array, grouped by the dql alias
* 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.
* 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
@@ -172,40 +188,54 @@ abstract class AbstractHydrator
* @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])) {
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]);
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($cache[$key]['isScalar'])) {
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
continue;
}
@@ -222,10 +252,11 @@ abstract class AbstractHydrator
$nonemptyComponents[$dqlAlias] = true;
}
}
continue;
}
// in an inheritance hierachy the same field could be defined several times.
// in an inheritance hierarchy 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) {
@@ -244,6 +275,7 @@ 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
@@ -251,52 +283,77 @@ 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])) {
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];
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;
}
}
$fieldName = $cache[$key]['fieldName'];
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);
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;
}
}
return $rowData;
}
protected function registerManaged($class, $entity, $data)
/**
* 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)
{
if ($class->isIdentifierComposite) {
$id = array();
@@ -314,6 +371,7 @@ abstract class AbstractHydrator
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
}
}
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
}
@@ -25,8 +25,9 @@ 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>
* @since 1.0
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*/
class ArrayHydrator extends AbstractHydrator
{
@@ -38,45 +39,55 @@ class ArrayHydrator extends AbstractHydrator
private $_idTemplate = array();
private $_resultCounter = 0;
/** @override */
protected function _prepare()
/**
* {@inheritdoc}
*/
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] = '';
}
}
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result);
$this->hydrateRowData($data, $cache, $result);
}
return $result;
}
/** @override */
protected function _hydrateRow(array $data, array &$cache, array &$result)
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $row, array &$cache, array &$result)
{
// 1) Initialize
$id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array();
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
$rowData = $this->gatherRowData($row, $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;
}
@@ -90,7 +101,7 @@ class ArrayHydrator extends AbstractHydrator
// It's a joined result
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
$path = $parent . '.' . $dqlAlias;
$path = $parent . '.' . $dqlAlias;
// missing parent data, skipping as RIGHT JOIN hydration is not supported.
if ( ! isset($nonemptyComponents[$parent]) ) {
@@ -109,39 +120,41 @@ 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])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
$baseElement[$relationAlias][$element[$field]] = $element;
$baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $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])) {
@@ -157,43 +170,42 @@ 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(0 => null);
$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 (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
if ($this->_rsm->isMixed) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_rsm->isMixed) {
$result[] = array($element);
++$this->_resultCounter;
} else {
$result[] = $element;
}
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
end($result);
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
$result[$resultKey] = $element;
} else {
$resultKey = $this->_resultCounter;
$result[] = $element;
++$this->_resultCounter;
}
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
} else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] =& $result[$index];
++$this->_resultCounter;
@@ -205,8 +217,17 @@ 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[$this->_resultCounter - 1][$name] = $value;
$result[$resultKey][$name] = $value;
}
}
}
@@ -224,28 +245,45 @@ 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;
}
private function _getClassMetadata($className)
/**
* Retrieve ClassMetadata associated to entity class name.
*
* @param string $className
*
* @return \Doctrine\ORM\Mapping\ClassMetadata
*/
private function getClassMetadata($className)
{
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
}
@@ -8,10 +8,19 @@ 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."
);
}
}
@@ -23,6 +23,8 @@ 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;
@@ -30,8 +32,10 @@ use PDO,
/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @internal Highly performance-sensitive code.
*/
class ObjectHydrator extends AbstractHydrator
@@ -54,51 +58,63 @@ class ObjectHydrator extends AbstractHydrator
/** @override */
protected function _prepare()
protected function prepare()
{
$this->_identifierMap =
$this->_resultPointers =
$this->_idTemplate = array();
$this->_resultCounter = 0;
if (!isset($this->_hints['deferEagerLoad'])) {
if ( ! isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true;
}
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$class = $this->_em->getClassMetadata($className);
$this->_idTemplate[$dqlAlias] = '';
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $class;
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
// 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])) {
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) {
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]);
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;
}
$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) {
// Mark any non-collection opposite sides as fetched, too.
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true;
} else {
if ($assoc['inversedBy']) {
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
$this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
}
}
}
}
$this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true;
}
}
}
@@ -106,11 +122,12 @@ 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 =
@@ -124,13 +141,13 @@ class ObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function _hydrateAll()
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result);
$this->hydrateRowData($row, $cache, $result);
}
// Take snapshots from all newly initialized collections
@@ -145,35 +162,40 @@ class ObjectHydrator extends AbstractHydrator
* Initializes a related collection.
*
* @param object $entity The entity to which the collection belongs.
* @param ClassMetadata $class
* @param string $name The name of the field on the entity that holds the collection.
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
*/
private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
{
$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'][$parentDqlAlias][$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!
@@ -193,25 +215,46 @@ class ObjectHydrator extends AbstractHydrator
private function _getEntity(array $data, $dqlAlias)
{
$className = $this->_rsm->aliasMap[$dqlAlias];
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
$discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]];
if ($data[$discrColumn] === "") {
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
}
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
unset($data[$discrColumn]);
}
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
$class = $this->_ce[$className];
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
$this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
$this->_hints['fetchAlias'] = $dqlAlias;
return $this->_uow->createEntity($className, $data, $this->_hints);
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($this->_ce[$className]->lifecycleCallbacks[Events::postLoad])) {
$this->_ce[$className]->invokeLifecycleCallbacks(Events::postLoad, $entity);
}
$evm = $this->_em->getEventManager();
if ($evm->hasListeners(Events::postLoad)) {
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
}
return $entity;
}
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 = '';
@@ -243,6 +286,7 @@ class ObjectHydrator extends AbstractHydrator
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
@@ -267,18 +311,20 @@ class ObjectHydrator extends AbstractHydrator
* @param array $cache The cache to use.
* @param array $result The result array to fill.
*/
protected function _hydrateRow(array $data, array &$cache, array &$result)
protected function hydrateRowData(array $row, 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($data, $cache, $id, $nonemptyComponents);
$rowData = $this->gatherRowData($row, $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;
}
@@ -347,8 +393,7 @@ class ObjectHydrator extends AbstractHydrator
$element = $this->_getEntity($data, $dqlAlias);
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
$indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
$reflFieldValue->hydrateSet($indexValue, $element);
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
} else {
@@ -380,6 +425,7 @@ class ObjectHydrator extends AbstractHydrator
$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
@@ -412,14 +458,16 @@ 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(0 => null);
$result[] = array($entityKey => null);
} else {
$result[] = null;
}
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
continue;
}
@@ -427,35 +475,31 @@ class ObjectHydrator extends AbstractHydrator
// 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])) {
$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;
}
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateSet($key, $element);
$this->_hints['collection']->hydrateSet($resultKey, $element);
}
$result[$resultKey] = $element;
} else {
if ($this->_rsm->isMixed) {
$element = array(0 => $element);
}
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
$resultKey = $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;
@@ -463,6 +507,7 @@ 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;
@@ -473,8 +518,16 @@ 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[$this->_resultCounter - 1][$name] = $value;
$result[$resultKey][$name] = $value;
}
}
}
@@ -26,25 +26,32 @@ use Doctrine\DBAL\Connection;
* The created result is almost the same as a regular SQL result set, except
* that column names are mapped to field names and data type conversions take place.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class ScalarHydrator extends AbstractHydrator
{
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $this->_gatherScalarRowData($data, $cache);
$this->hydrateRowData($data, $cache, $result);
}
return $result;
}
/** @override */
protected function _hydrateRow(array $data, array &$cache, array &$result)
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$cache, array &$result)
{
$result[] = $this->_gatherScalarRowData($data, $cache);
$result[] = $this->gatherScalarRowData($data, $cache);
}
}
@@ -17,13 +17,14 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Internal\Hydration;
use \PDO;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query;
use \PDO,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Events,
Doctrine\ORM\Query;
class SimpleObjectHydrator extends AbstractHydrator
{
@@ -32,15 +33,21 @@ class SimpleObjectHydrator extends AbstractHydrator
*/
private $class;
/**
* @var array
*/
private $declaringClasses = array();
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result);
$this->hydrateRowData($row, $cache, $result);
}
$this->_em->getUnitOfWork()->triggerEagerLoads();
@@ -48,77 +55,71 @@ class SimpleObjectHydrator extends AbstractHydrator
return $result;
}
protected function _prepare()
/**
* {@inheritdoc}
*/
protected function prepare()
{
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 (count($this->_rsm->aliasMap) !== 1) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than 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);
}
}
protected function _hydrateRow(array $sqlResult, array &$cache, array &$result)
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$cache, array &$result)
{
$data = array();
if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) {
foreach ($sqlResult as $column => $value) {
$entityName = $this->class->name;
$data = array();
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];
}
}
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 {
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
if ($sqlResult[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
foreach ($sqlResult as $column => $value) {
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];
}
}
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]['class'])) {
$value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type'])
->convertToPHPValue($value, $this->_platform);
}
$cache[$column] = $info;
}
// 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;
}
// 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)) {
$data[$cache[$column]['name']] = $value;
}
}
@@ -126,6 +127,68 @@ class SimpleObjectHydrator extends AbstractHydrator
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
$uow = $this->_em->getUnitOfWork();
$entity = $uow->createEntity($entityName, $data, $this->_hints);
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($this->class->lifecycleCallbacks[Events::postLoad])) {
$this->class->invokeLifecycleCallbacks(Events::postLoad, $entity);
}
$evm = $this->_em->getEventManager();
if ($evm->hasListeners(Events::postLoad)) {
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
}
$result[] = $entity;
}
/**
* Retrieve column information form ResultSetMapping.
*
* @param string $entityName
* @param string $column
*
* @return array
*/
protected function hydrateColumnInfo($entityName, $column)
{
switch (true) {
case (isset($this->_rsm->fieldMappings[$column])):
$class = isset($this->declaringClasses[$column])
? $this->declaringClasses[$column]
: $this->class;
// If class is not part of the inheritance, ignore
if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) {
return null;
}
return array(
'class' => $class,
'name' => $this->_rsm->fieldMappings[$column],
'field' => true,
);
case (isset($this->_rsm->relationMap[$column])):
$class = isset($this->_rsm->relationMap[$column])
? $this->_rsm->relationMap[$column]
: $this->class;
// If class is not self referencing, ignore
if ( ! ($class === $entityName || is_subclass_of($entityName, $class))) {
return null;
}
// TODO: Decide what to do with associations. It seems original code is incomplete.
// One solution is to load the association, but it might require extra efforts.
return array('name' => $column);
default:
return array(
'name' => $this->_rsm->metaMappings[$column]
);
}
}
}
@@ -19,31 +19,38 @@
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Connection,
Doctrine\ORM\NoResultException,
Doctrine\ORM\NonUniqueResultException;
/**
* Hydrator that hydrates a single scalar value from the result set.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class SingleScalarHydrator extends AbstractHydrator
{
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$cache = array();
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$num = count($result);
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$numRows = count($data);
if ($num == 0) {
throw new \Doctrine\ORM\NoResultException;
} else if ($num > 1 || count($result[key($result)]) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
if ($numRows === 0) {
throw new NoResultException();
}
$result = $this->_gatherScalarRowData($result[key($result)], $cache);
if ($numRows > 1 || count($data[key($data)]) > 1) {
throw new NonUniqueResultException();
}
$cache = array();
$result = $this->gatherScalarRowData($data[key($data)], $cache);
return array_shift($result);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
interface Annotation
{
}
@@ -0,0 +1,167 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
use Doctrine\ORM\Mapping\ClassMetadata;
class AssociationBuilder
{
/**
* @var ClassMetadataBuilder
*/
protected $builder;
/**
* @var array
*/
protected $mapping;
/**
* @var array
*/
protected $joinColumns;
/**
*
* @var int
*/
protected $type;
/**
* @param ClassMetadataBuilder $builder
* @param array $mapping
*/
public function __construct(ClassMetadataBuilder $builder, array $mapping, $type)
{
$this->builder = $builder;
$this->mapping = $mapping;
$this->type = $type;
}
public function mappedBy($fieldName)
{
$this->mapping['mappedBy'] = $fieldName;
return $this;
}
public function inversedBy($fieldName)
{
$this->mapping['inversedBy'] = $fieldName;
return $this;
}
public function cascadeAll()
{
$this->mapping['cascade'] = array("ALL");
return $this;
}
public function cascadePersist()
{
$this->mapping['cascade'][] = "persist";
return $this;
}
public function cascadeRemove()
{
$this->mapping['cascade'][] = "remove";
return $this;
}
public function cascadeMerge()
{
$this->mapping['cascade'][] = "merge";
return $this;
}
public function cascadeDetach()
{
$this->mapping['cascade'][] = "detach";
return $this;
}
public function cascadeRefresh()
{
$this->mapping['cascade'][] = "refresh";
return $this;
}
public function fetchExtraLazy()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY;
return $this;
}
public function fetchEager()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_EAGER;
return $this;
}
public function fetchLazy()
{
$this->mapping['fetch'] = ClassMetadata::FETCH_LAZY;
return $this;
}
/**
* Add Join Columns
*
* @param string $columnName
* @param string $referencedColumnName
* @param bool $nullable
* @param bool $unique
* @param string $onDelete
* @param string $columnDef
*/
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
$this->joinColumns[] = array(
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'nullable' => $nullable,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
);
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
if ($this->joinColumns) {
$mapping['joinColumns'] = $this->joinColumns;
}
$cm = $this->builder->getClassMetadata();
if ($this->type == ClassMetadata::MANY_TO_ONE) {
$cm->mapManyToOne($mapping);
} else if ($this->type == ClassMetadata::ONE_TO_ONE) {
$cm->mapOneToOne($mapping);
} else {
throw new \InvalidArgumentException("Type should be a ToOne Assocation here");
}
return $this->builder;
}
}
@@ -0,0 +1,470 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* Builder Object for ClassMetadata
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class ClassMetadataBuilder
{
/**
* @var \Doctrine\ORM\Mapping\ClassMetadataInfo
*/
private $cm;
/**
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm
*/
public function __construct(ClassMetadataInfo $cm)
{
$this->cm = $cm;
}
/**
* @return ClassMetadata
*/
public function getClassMetadata()
{
return $this->cm;
}
/**
* Mark the class as mapped superclass.
*
* @return ClassMetadataBuilder
*/
public function setMappedSuperClass()
{
$this->cm->isMappedSuperclass = true;
return $this;
}
/**
* Set custom Repository class name
*
* @param string $repositoryClassName
* @return ClassMetadataBuilder
*/
public function setCustomRepositoryClass($repositoryClassName)
{
$this->cm->setCustomRepositoryClass($repositoryClassName);
return $this;
}
/**
* Mark class read only
*
* @return ClassMetadataBuilder
*/
public function setReadOnly()
{
$this->cm->markReadOnly();
return $this;
}
/**
* Set the table name
*
* @param string $name
* @return ClassMetadataBuilder
*/
public function setTable($name)
{
$this->cm->setPrimaryTable(array('name' => $name));
return $this;
}
/**
* Add Index
*
* @param array $columns
* @param string $name
* @return ClassMetadataBuilder
*/
public function addIndex(array $columns, $name)
{
if (!isset($this->cm->table['indexes'])) {
$this->cm->table['indexes'] = array();
}
$this->cm->table['indexes'][$name] = array('columns' => $columns);
return $this;
}
/**
* Add Unique Constraint
*
* @param array $columns
* @param string $name
* @return ClassMetadataBuilder
*/
public function addUniqueConstraint(array $columns, $name)
{
if ( ! isset($this->cm->table['uniqueConstraints'])) {
$this->cm->table['uniqueConstraints'] = array();
}
$this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns);
return $this;
}
/**
* Add named query
*
* @param string $name
* @param string $dqlQuery
* @return ClassMetadataBuilder
*/
public function addNamedQuery($name, $dqlQuery)
{
$this->cm->addNamedQuery(array(
'name' => $name,
'query' => $dqlQuery,
));
return $this;
}
/**
* Set class as root of a joined table inheritance hierachy.
*
* @return ClassMetadataBuilder
*/
public function setJoinedTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED);
return $this;
}
/**
* Set class as root of a single table inheritance hierachy.
*
* @return ClassMetadataBuilder
*/
public function setSingleTableInheritance()
{
$this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
return $this;
}
/**
* Set the discriminator column details.
*
* @param string $name
* @param string $type
*/
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
{
$this->cm->setDiscriminatorColumn(array(
'name' => $name,
'type' => $type,
'length' => $length,
));
return $this;
}
/**
* Add a subclass to this inheritance hierachy.
*
* @param string $name
* @param string $class
* @return ClassMetadataBuilder
*/
public function addDiscriminatorMapClass($name, $class)
{
$this->cm->addDiscriminatorMapClass($name, $class);
return $this;
}
/**
* Set deferred explicit change tracking policy.
*
* @return ClassMetadataBuilder
*/
public function setChangeTrackingPolicyDeferredExplicit()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT);
return $this;
}
/**
* Set notify change tracking policy.
*
* @return ClassMetadataBuilder
*/
public function setChangeTrackingPolicyNotify()
{
$this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY);
return $this;
}
/**
* Add lifecycle event
*
* @param string $methodName
* @param string $event
* @return ClassMetadataBuilder
*/
public function addLifecycleEvent($methodName, $event)
{
$this->cm->addLifecycleCallback($methodName, $event);
return $this;
}
/**
* Add Field
*
* @param string $name
* @param string $type
* @param array $mapping
*/
public function addField($name, $type, array $mapping = array())
{
$mapping['fieldName'] = $name;
$mapping['type'] = $type;
$this->cm->mapField($mapping);
return $this;
}
/**
* Create a field builder.
*
* @param string $name
* @param string $type
* @return FieldBuilder
*/
public function createField($name, $type)
{
return new FieldBuilder(
$this,
array(
'fieldName' => $name,
'type' => $type
)
);
}
/**
* Add a simple many to one association, optionally with the inversed by field.
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
* @return ClassMetadataBuilder
*/
public function addManyToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToOne($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Create a ManyToOne Assocation Builder.
*
* Note: This method does not add the association, you have to call build() on the AssociationBuilder.
*
* @param string $name
* @param string $targetEntity
* @return AssociationBuilder
*/
public function createManyToOne($name, $targetEntity)
{
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_ONE
);
}
/**
* Create OneToOne Assocation Builder
*
* @param string $name
* @param string $targetEntity
* @return AssociationBuilder
*/
public function createOneToOne($name, $targetEntity)
{
return new AssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_ONE
);
}
/**
* Add simple inverse one-to-one assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addInverseOneToOne($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToOne($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
/**
* Add simple owning one-to-one assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $inversedBy
* @return ClassMetadataBuilder
*/
public function addOwningOneToOne($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createOneToOne($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Create ManyToMany Assocation Builder
*
* @param string $name
* @param string $targetEntity
* @return ManyToManyAssociationBuilder
*/
public function createManyToMany($name, $targetEntity)
{
return new ManyToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::MANY_TO_MANY
);
}
/**
* Add a simple owning many to many assocation.
*
* @param string $name
* @param string $targetEntity
* @param string|null $inversedBy
* @return ClassMetadataBuilder
*/
public function addOwningManyToMany($name, $targetEntity, $inversedBy = null)
{
$builder = $this->createManyToMany($name, $targetEntity);
if ($inversedBy) {
$builder->inversedBy($inversedBy);
}
return $builder->build();
}
/**
* Add a simple inverse many to many assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addInverseManyToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createManyToMany($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
/**
* Create a one to many assocation builder
*
* @param string $name
* @param string $targetEntity
* @return OneToManyAssociationBuilder
*/
public function createOneToMany($name, $targetEntity)
{
return new OneToManyAssociationBuilder(
$this,
array(
'fieldName' => $name,
'targetEntity' => $targetEntity
),
ClassMetadata::ONE_TO_MANY
);
}
/**
* Add simple OneToMany assocation.
*
* @param string $name
* @param string $targetEntity
* @param string $mappedBy
* @return ClassMetadataBuilder
*/
public function addOneToMany($name, $targetEntity, $mappedBy)
{
$builder = $this->createOneToMany($name, $targetEntity);
$builder->mappedBy($mappedBy);
return $builder->build();
}
}
@@ -0,0 +1,223 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* Field Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class FieldBuilder
{
/**
* @var ClassMetadataBuilder
*/
private $builder;
/**
* @var array
*/
private $mapping;
/**
* @var bool
*/
private $version;
/**
* @var string
*/
private $generatedValue;
/**
* @var array
*/
private $sequenceDef;
/**
*
* @param ClassMetadataBuilder $builder
* @param array $mapping
*/
public function __construct(ClassMetadataBuilder $builder, array $mapping)
{
$this->builder = $builder;
$this->mapping = $mapping;
}
/**
* Set length.
*
* @param int $length
* @return FieldBuilder
*/
public function length($length)
{
$this->mapping['length'] = $length;
return $this;
}
/**
* Set nullable
*
* @param bool
* @return FieldBuilder
*/
public function nullable($flag = true)
{
$this->mapping['nullable'] = (bool)$flag;
return $this;
}
/**
* Set Unique
*
* @param bool
* @return FieldBuilder
*/
public function unique($flag = true)
{
$this->mapping['unique'] = (bool)$flag;
return $this;
}
/**
* Set column name
*
* @param string $name
* @return FieldBuilder
*/
public function columnName($name)
{
$this->mapping['columnName'] = $name;
return $this;
}
/**
* Set Precision
*
* @param int $p
* @return FieldBuilder
*/
public function precision($p)
{
$this->mapping['precision'] = $p;
return $this;
}
/**
* Set scale.
*
* @param int $s
* @return FieldBuilder
*/
public function scale($s)
{
$this->mapping['scale'] = $s;
return $this;
}
/**
* Set field as primary key.
*
* @return FieldBuilder
*/
public function isPrimaryKey()
{
$this->mapping['id'] = true;
return $this;
}
/**
* @param int $strategy
* @return FieldBuilder
*/
public function generatedValue($strategy = 'AUTO')
{
$this->generatedValue = $strategy;
return $this;
}
/**
* Set field versioned
*
* @return FieldBuilder
*/
public function isVersionField()
{
$this->version = true;
return $this;
}
/**
* Set Sequence Generator
*
* @param string $sequenceName
* @param int $allocationSize
* @param int $initialValue
* @return FieldBuilder
*/
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
{
$this->sequenceDef = array(
'sequenceName' => $sequenceName,
'allocationSize' => $allocationSize,
'initialValue' => $initialValue,
);
return $this;
}
/**
* Set column definition.
*
* @param string $def
* @return FieldBuilder
*/
public function columnDefinition($def)
{
$this->mapping['columnDefinition'] = $def;
return $this;
}
/**
* Finalize this field and attach it to the ClassMetadata.
*
* Without this call a FieldBuilder has no effect on the ClassMetadata.
*
* @return ClassMetadataBuilder
*/
public function build()
{
$cm = $this->builder->getClassMetadata();
if ($this->generatedValue) {
$cm->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $this->generatedValue));
}
if ($this->version) {
$cm->setVersionMapping($this->mapping);
}
$cm->mapField($this->mapping);
if ($this->sequenceDef) {
$cm->setSequenceGeneratorDefinition($this->sequenceDef);
}
return $this->builder;
}
}
@@ -0,0 +1,86 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* ManyToMany Association Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
{
private $joinTableName;
private $inverseJoinColumns = array();
public function setJoinTable($name)
{
$this->joinTableName = $name;
return $this;
}
/**
* Add Inverse Join Columns
*
* @param string $columnName
* @param string $referencedColumnName
* @param bool $nullable
* @param bool $unique
* @param string $onDelete
* @param string $columnDef
*/
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
$this->inverseJoinColumns[] = array(
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'nullable' => $nullable,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
);
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
$mapping['joinTable'] = array();
if ($this->joinColumns) {
$mapping['joinTable']['joinColumns'] = $this->joinColumns;
}
if ($this->inverseJoinColumns) {
$mapping['joinTable']['inverseJoinColumns'] = $this->inverseJoinColumns;
}
if ($this->joinTableName) {
$mapping['joinTable']['name'] = $this->joinTableName;
}
$cm = $this->builder->getClassMetadata();
$cm->mapManyToMany($mapping);
return $this->builder;
}
}
@@ -0,0 +1,62 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Builder;
/**
* OneToMany Association Builder
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class OneToManyAssociationBuilder extends AssociationBuilder
{
/**
* @param array $fieldNames
* @return OneToManyAssociationBuilder
*/
public function setOrderBy(array $fieldNames)
{
$this->mapping['orderBy'] = $fieldNames;
return $this;
}
public function setIndexBy($fieldName)
{
$this->mapping['indexBy'] = $fieldName;
return $this;
}
/**
* @return ClassMetadataBuilder
*/
public function build()
{
$mapping = $this->mapping;
if ($this->joinColumns) {
$mapping['joinColumns'] = $this->joinColumns;
}
$cm = $this->builder->getClassMetadata();
$cm->mapOneToMany($mapping);
return $this->builder;
}
}
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class ChangeTrackingPolicy implements Annotation
{
/** @var string */
public $value;
}
+1 -303
View File
@@ -24,7 +24,7 @@ use ReflectionClass, ReflectionProperty;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
* of an entity and it's associations.
*
*
* Once populated, ClassMetadata instances are usually cached in a serialized form.
*
* <b>IMPORTANT NOTE:</b>
@@ -41,306 +41,4 @@ use ReflectionClass, ReflectionProperty;
*/
class ClassMetadata extends ClassMetadataInfo
{
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param string $entityName The name of the entity class the new instance is used for.
*/
public function __construct($entityName)
{
$this->reflClass = new ReflectionClass($entityName);
$this->namespace = $this->reflClass->getNamespaceName();
$this->table['name'] = $this->reflClass->getShortName();
parent::__construct($this->reflClass->getName()); // do not use $entityName, possible case-problems
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validated & complete.
* @return array The validated and completed field mapping.
*
* @throws MappingException
*/
protected function _validateAndCompleteFieldMapping(array &$mapping)
{
parent::_validateAndCompleteFieldMapping($mapping);
// Store ReflectionProperty of mapped field
$refProp = $this->reflClass->getProperty($mapping['fieldName']);
$refProp->setAccessible(true);
$this->reflFields[$mapping['fieldName']] = $refProp;
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
} else {
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Stores the association mapping.
*
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
parent::_storeAssociationMapping($assocMapping);
// Store ReflectionProperty of mapped field
$sourceFieldName = $assocMapping['fieldName'];
$refProp = $this->reflClass->getProperty($sourceFieldName);
$refProp->setAccessible(true);
$this->reflFields[$sourceFieldName] = $refProp;
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @return void
*/
public function __wakeup()
{
// Restore ReflectionClass and properties
$this->reflClass = new ReflectionClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
foreach ($this->associationMappings as $field => $mapping) {
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
}
@@ -24,6 +24,8 @@ use ReflectionException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events,
Doctrine\Common\Persistence\Mapping\RuntimeReflectionService,
Doctrine\Common\Persistence\Mapping\ReflectionService,
Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface;
/**
@@ -50,7 +52,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
private $targetPlatform;
/**
* @var Driver\Driver
* @var \Doctrine\ORM\Mapping\Driver\Driver
*/
private $driver;
@@ -74,6 +76,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
private $initialized = false;
/**
* @var ReflectionService
*/
private $reflectionService;
/**
* @param EntityManager $$em
*/
@@ -165,6 +172,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->wakeupReflection($cached, $this->getReflectionService());
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
@@ -220,7 +228,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
foreach (array_reverse(class_parents($name)) as $parentClass) {
foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
if ( ! $this->driver->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
@@ -261,6 +269,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
$class = $this->newClassMetadataInstance($className);
$this->initializeReflection($class, $this->getReflectionService());
if ($parent) {
$class->setInheritanceType($parent->inheritanceType);
@@ -274,6 +283,9 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class->setDiscriminatorMap($parent->discriminatorMap);
$class->setLifecycleCallbacks($parent->lifecycleCallbacks);
$class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
if ($parent->isMappedSuperclass) {
$class->setCustomRepositoryClass($parent->customRepositoryClassName);
}
}
// Invoke driver
@@ -310,12 +322,17 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class->containsForeignIdentifier = true;
}
if ($parent && !empty ($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
$class->setParentClasses($visited);
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
}
$this->wakeupReflection($class, $this->getReflectionService());
$this->validateRuntimeMetadata($class, $parent);
@@ -342,11 +359,15 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
protected function validateRuntimeMetadata($class, $parent)
{
// Verify & complete identifier mapping
if ( ! $class->identifier && ! $class->isMappedSuperclass) {
throw MappingException::identifierRequired($class->name);
if ( ! $class->reflClass ) {
// only validate if there is a reflection class instance
return;
}
$class->validateIdentifier();
$class->validateAssocations();
$class->validateLifecycleCallbacks($this->getReflectionService());
// verify inheritance
if (!$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
if (!$parent) {
@@ -426,6 +447,25 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
}
/**
* Adds inherited named queries to the subclass mapping.
*
* @since 2.2
* @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->namedQueries as $name => $query) {
if (!isset ($subClass->namedQueries[$name])) {
$subClass->addNamedQuery(array(
'name' => $query['name'],
'query' => $query['query']
));
}
}
}
/**
* Completes the ID generator mapping. If "auto" is specified we choose the generator
* most appropriate for the targeted database platform.
@@ -452,7 +492,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
// <table>_<column>_seq in PostgreSQL for SERIAL columns.
// Not pretty but necessary and the simplest solution that currently works.
$seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ?
$class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
$class->getTableName() . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
null;
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName));
break;
@@ -484,20 +524,70 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
/**
* {@inheritDoc}
* Check if this class is mapped by this EntityManager + ClassMetadata configuration
*
* @param $class
* @return bool
*/
public function isTransient($class)
{
if ( ! $this->initialized) {
$this->initialize();
}
// Check for namespace alias
if (strpos($class, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $class);
$class = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
return $this->driver->isTransient($class);
}
/**
* Get reflectionService.
*
* @return \Doctrine\Common\Persistence\Mapping\ReflectionService
*/
public function getReflectionService()
{
if ($this->reflectionService === null) {
$this->reflectionService = new RuntimeReflectionService();
}
return $this->reflectionService;
}
/**
* Set reflectionService.
*
* @param reflectionService the value to set.
*/
public function setReflectionService(ReflectionService $reflectionService)
{
$this->reflectionService = $reflectionService;
}
/**
* Wakeup reflection after ClassMetadata gets unserialized from cache.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function wakeupReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->wakeupReflection($reflService);
}
/**
* Initialize Reflection after ClassMetadata was constructed.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function initializeReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->initializeReflection($reflService);
}
}
+405 -52
View File
@@ -19,8 +19,9 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\DBAL\Types\Type;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@@ -136,10 +137,6 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-one association.
*/
const MANY_TO_ONE = 2;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Identifies a one-to-many association.
*/
@@ -148,6 +145,10 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-many association.
*/
const MANY_TO_MANY = 8;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Combined bitmask for to-many (collection-valued) associations.
*/
@@ -318,7 +319,7 @@ class ClassMetadataInfo implements ClassMetadata
public $discriminatorMap = array();
/**
* READ-ONLY: The definition of the descriminator column used in JOINED and SINGLE_TABLE
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
* inheritance mappings.
*
* @var array
@@ -494,6 +495,20 @@ class ClassMetadataInfo implements ClassMetadata
*/
public $isReadOnly = false;
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
@@ -506,6 +521,308 @@ class ClassMetadataInfo implements ClassMetadata
$this->rootEntityName = $entityName;
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
}
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @param ReflectionService $reflService
* @return void
*/
public function wakeupReflection($reflService)
{
// Restore ReflectionClass and properties
$this->reflClass = $reflService->getClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
foreach ($this->associationMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
}
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param string $entityName The name of the entity class the new instance is used for.
*/
public function initializeReflection($reflService)
{
$this->reflClass = $reflService->getClass($this->name);
$this->namespace = $reflService->getClassNamespace($this->name);
$this->table['name'] = $reflService->getClassShortName($this->name);
if ($this->reflClass) {
$this->name = $this->rootEntityName = $this->reflClass->getName();
}
}
/**
* Validate Identifier
*
* @return void
*/
public function validateIdentifier()
{
// Verify & complete identifier mapping
if ( ! $this->identifier && ! $this->isMappedSuperclass) {
throw MappingException::identifierRequired($this->name);
}
if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
}
}
/**
* Validate association targets actually exist.
*
* @return void
*/
public function validateAssocations()
{
foreach ($this->associationMappings as $field => $mapping) {
if ( ! \Doctrine\Common\ClassLoader::classExists($mapping['targetEntity']) ) {
throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
}
}
}
/**
* Validate lifecycle callbacks
*
* @param ReflectionService $reflService
* @return void
*/
public function validateLifecycleCallbacks($reflService)
{
foreach ($this->lifecycleCallbacks as $event => $callbacks) {
foreach ($callbacks as $callbackFuncName) {
if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
}
}
}
}
/**
* Gets the ReflectionClass instance of the mapped class.
*
@@ -513,9 +830,6 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getReflectionClass()
{
if ( ! $this->reflClass) {
$this->reflClass = new ReflectionClass($this->name);
}
return $this->reflClass;
}
@@ -685,7 +999,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($this->namedQueries[$queryName])) {
throw MappingException::queryNotFound($this->name, $queryName);
}
return $this->namedQueries[$queryName];
return $this->namedQueries[$queryName]['dql'];
}
/**
@@ -746,6 +1060,14 @@ class ClassMetadataInfo implements ClassMetadata
$this->isIdentifierComposite = true;
}
}
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
if (isset($mapping['id']) && $mapping['id'] === true) {
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
}
$mapping['requireSQLConversion'] = true;
}
}
/**
@@ -783,6 +1105,13 @@ class ClassMetadataInfo implements ClassMetadata
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
}
if ( ($mapping['type'] & (self::MANY_TO_ONE|self::MANY_TO_MANY)) > 0 &&
isset($mapping['orphanRemoval']) &&
$mapping['orphanRemoval'] == true) {
throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
}
// Complete id mapping
if (isset($mapping['id']) && $mapping['id'] === true) {
if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
@@ -837,15 +1166,11 @@ class ClassMetadataInfo implements ClassMetadata
// Cascades
$cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
if (in_array('all', $cascades)) {
$cascades = array(
'remove',
'persist',
'refresh',
'merge',
'detach'
);
$cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
}
$mapping['cascade'] = $cascades;
$mapping['isCascadeRemove'] = in_array('remove', $cascades);
$mapping['isCascadePersist'] = in_array('persist', $cascades);
@@ -1274,7 +1599,7 @@ class ClassMetadataInfo implements ClassMetadata
public function getTemporaryIdTableName()
{
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
return str_replace('.', '_', $this->table['name'] . '_id_tmp');
return str_replace('.', '_', $this->getTableName() . '_id_tmp');
}
/**
@@ -1367,15 +1692,17 @@ class ClassMetadataInfo implements ClassMetadata
{
if (isset($table['name'])) {
if ($table['name'][0] == '`') {
$this->table['name'] = trim($table['name'], '`');
$this->table['name'] = str_replace("`", "", $table['name']);
$this->table['quoted'] = true;
} else {
$this->table['name'] = $table['name'];
}
}
if (isset($table['indexes'])) {
$this->table['indexes'] = $table['indexes'];
}
if (isset($table['uniqueConstraints'])) {
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
}
@@ -1450,8 +1777,15 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($this->namedQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
}
$query = str_replace('__CLASS__', $this->name, $queryMapping['query']);
$this->namedQueries[$queryMapping['name']] = $query;
$name = $queryMapping['name'];
$query = $queryMapping['query'];
$dql = str_replace('__CLASS__', $this->name, $query);
$this->namedQueries[$name] = array(
'name' => $name,
'query' => $query,
'dql' => $dql
);
}
/**
@@ -1506,14 +1840,16 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Stores the association mapping.
*
* @param AssociationMapping $assocMapping
* @param array $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping['fieldName'];
if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
}
$this->associationMappings[$sourceFieldName] = $assocMapping;
}
@@ -1524,6 +1860,10 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function setCustomRepositoryClass($repositoryClassName)
{
if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
&& strlen($this->namespace) > 0) {
$repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
}
$this->customRepositoryClassName = $repositoryClassName;
}
@@ -1566,9 +1906,6 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Adds a lifecycle callback for entities of this class.
*
* Note: If the same callback is registered more than once, the old one
* will be overridden.
*
* @param string $callback
* @param string $event
*/
@@ -1627,22 +1964,33 @@ class ClassMetadataInfo implements ClassMetadata
public function setDiscriminatorMap(array $map)
{
foreach ($map as $value => $className) {
if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
$className = $this->namespace . '\\' . $className;
$this->addDiscriminatorMapClass($value, $className);
}
}
/**
* Add one entry of the discriminator map with a new class and corresponding name.
*
* @param string $name
* @param string $className
*/
public function addDiscriminatorMapClass($name, $className)
{
if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) {
$className = $this->namespace . '\\' . $className;
}
$className = ltrim($className, '\\');
$this->discriminatorMap[$name] = $className;
if ($this->name == $className) {
$this->discriminatorValue = $name;
} else {
if ( ! class_exists($className)) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
}
$className = ltrim($className, '\\');
$this->discriminatorMap[$value] = $className;
if ($this->name == $className) {
$this->discriminatorValue = $value;
} else {
if ( ! class_exists($className)) {
throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
}
if (is_subclass_of($className, $this->name)) {
$this->subClasses[] = $className;
}
if (is_subclass_of($className, $this->name)) {
$this->subClasses[] = $className;
}
}
}
@@ -1804,7 +2152,7 @@ class ClassMetadataInfo implements ClassMetadata
$this->versionField = $mapping['fieldName'];
if ( ! isset($mapping['default'])) {
if ($mapping['type'] == 'integer') {
if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) {
$mapping['default'] = 1;
} else if ($mapping['type'] == 'datetime') {
$mapping['default'] = 'CURRENT_TIMESTAMP';
@@ -1877,9 +2225,10 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getAssociationTargetClass($assocName)
{
if (!isset($this->associationMappings[$assocName])) {
if ( ! isset($this->associationMappings[$assocName])) {
throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
}
return $this->associationMappings[$assocName]['targetEntity'];
}
@@ -1939,9 +2288,9 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getQuotedColumnName($field, $platform)
{
return isset($this->fieldMappings[$field]['quoted']) ?
$platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) :
$this->fieldMappings[$field]['columnName'];
return isset($this->fieldMappings[$field]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
: $this->fieldMappings[$field]['columnName'];
}
/**
@@ -1953,9 +2302,7 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getQuotedTableName($platform)
{
return isset($this->table['quoted']) ?
$platform->quoteIdentifier($this->table['name']) :
$this->table['name'];
return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name'];
}
/**
@@ -1966,16 +2313,22 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function getQuotedJoinTableName(array $assoc, $platform)
{
return isset($assoc['joinTable']['quoted'])
? $platform->quoteIdentifier($assoc['joinTable']['name'])
: $assoc['joinTable']['name'];
return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
}
/**
* @param string $fieldName
* @return bool
*/
public function isAssociationInverseSide($fieldName)
{
return isset($this->associationMappings[$fieldName]) && !$this->associationMappings[$fieldName]['isOwningSide'];
return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide'];
}
/**
* @param string $fieldName
* @return string
*/
public function getAssociationMappedByTargetField($fieldName)
{
return $this->associationMappings[$fieldName]['mappedBy'];
+46
View File
@@ -0,0 +1,46 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Column implements Annotation
{
/** @var string */
public $name;
/** @var mixed */
public $type = 'string';
/** @var integer */
public $length;
/** @var integer */
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
/** @var integer */
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
/** @var boolean */
public $unique = false;
/** @var boolean */
public $nullable = false;
/** @var array */
public $options = array();
/** @var string */
public $columnDefinition;
}
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorColumn implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $type;
/** @var integer */
public $length;
/** @var mixed */
public $fieldName; // field name used in non-object hydration (array/scalar)
}
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class DiscriminatorMap implements Annotation
{
/** @var array<string> */
public $value;
}
@@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping\MappingException;
/**
* Base driver for file-based metadata drivers.
*
*
* A file driver operates in a mode where it loads the mapping files of individual
* classes on demand. This requires the user to adhere to the convention of 1 mapping
* file per class and the file names of the mapping files must correspond to the full
@@ -56,16 +56,16 @@ abstract class AbstractFileDriver implements Driver
*/
protected $_fileExtension;
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
/**
* Initializes a new FileDriver that looks in the given path(s) for mapping
* documents and operates in the specified operating mode.
*
* @param string|array $paths One or multiple paths where mapping documents can be found.
*/
public function __construct($paths)
{
$this->addPaths((array) $paths);
}
}
/**
* Append lookup paths to metadata driver.
@@ -117,7 +117,10 @@ abstract class AbstractFileDriver implements Driver
public function getElement($className)
{
$result = $this->_loadMappingFile($this->_findMappingFile($className));
if(!isset($result[$className])){
throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->_fileExtension);
}
return $result[$className];
}
@@ -145,7 +148,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
public function getAllClassNames()
@@ -157,23 +160,23 @@ abstract class AbstractFileDriver implements Driver
if ( ! is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) {
continue;
}
// NOTE: All files found here means classes are not transient!
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
return $classes;
}
@@ -188,7 +191,7 @@ abstract class AbstractFileDriver implements Driver
protected function _findMappingFile($className)
{
$fileName = str_replace('\\', '.', $className) . $this->_fileExtension;
// Check whether file exists
foreach ((array) $this->_paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) {
@@ -202,7 +205,7 @@ abstract class AbstractFileDriver implements Driver
/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding elements.
*
*
* @param string $file The mapping file to load.
* @return array
*/
@@ -97,6 +97,16 @@ class AnnotationDriver implements Driver
return $this->_paths;
}
/**
* Retrieve the current annotation reader
*
* @return AnnotationReader
*/
public function getReader()
{
return $this->_reader;
}
/**
* Get the file extension used to look for mapping files under
*
@@ -124,6 +134,11 @@ class AnnotationDriver implements Driver
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
$class = $metadata->getReflectionClass();
if (!$class) {
// this happens when running annotation driver in combination with
// static reflection services. This is not the nicest fix
$class = new \ReflectionClass($metadata->name);
}
$classAnnotations = $this->_reader->getClassAnnotations($class);
@@ -137,12 +152,15 @@ class AnnotationDriver implements Driver
// Evaluate Entity annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
$entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
if ($entityAnnot->repositoryClass !== null) {
$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);
@@ -179,7 +197,14 @@ class AnnotationDriver implements Driver
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
$namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
if (!is_array($namedQueriesAnnot->value)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
foreach ($namedQueriesAnnot->value as $namedQuery) {
if (!($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
}
$metadata->addNamedQuery(array(
'name' => $namedQuery->name,
'query' => $namedQuery->query
@@ -243,7 +268,6 @@ class AnnotationDriver implements Driver
'unique' => $joinColumnAnnot->unique,
'nullable' => $joinColumnAnnot->nullable,
'onDelete' => $joinColumnAnnot->onDelete,
'onUpdate' => $joinColumnAnnot->onUpdate,
'columnDefinition' => $joinColumnAnnot->columnDefinition,
);
} else if ($joinColumnsAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
@@ -254,7 +278,6 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -320,7 +343,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
@@ -328,7 +351,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
@@ -344,7 +367,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
@@ -362,7 +385,6 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -374,7 +396,6 @@ class AnnotationDriver implements Driver
'unique' => $joinColumn->unique,
'nullable' => $joinColumn->nullable,
'onDelete' => $joinColumn->onDelete,
'onUpdate' => $joinColumn->onUpdate,
'columnDefinition' => $joinColumn->columnDefinition,
);
}
@@ -386,7 +407,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
@@ -437,6 +458,10 @@ class AnnotationDriver implements Driver
if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad);
}
if (isset($annotations['Doctrine\ORM\Mapping\PreFlush'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preFlush);
}
}
}
}
@@ -499,15 +524,15 @@ class AnnotationDriver implements Driver
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::LEAVES_ONLY
),
'/^.+\\' . $this->_fileExtension . '$/i',
'/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i',
\RecursiveRegexIterator::GET_MATCH
);
foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);
require_once $sourceFile;
$includedFiles[] = $sourceFile;
}
}
@@ -527,6 +552,22 @@ class AnnotationDriver implements Driver
return $classes;
}
/**
* Attempts to resolve the fetch mode.
*
* @param string $className The class name
* @param string $fetchMode The fetch mode
* @return integer The fetch mode as defined in ClassMetadata
* @throws MappingException If the fetch mode is not valid
*/
private function getFetchMode($className, $fetchMode)
{
if(!defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
throw MappingException::invalidFetchMode($className, $fetchMode);
}
return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
}
/**
* Factory method for the Annotation Driver
*
@@ -76,7 +76,7 @@ class DatabaseDriver implements Driver
/**
* Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
* docblock annotations.
*
*
* @param AnnotationReader $reader The AnnotationReader to use.
*/
public function __construct(AbstractSchemaManager $schemaManager)
@@ -111,7 +111,7 @@ class DatabaseDriver implements Driver
}
$tables = array();
foreach ($this->_sm->listTableNames() as $tableName) {
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
}
@@ -129,7 +129,7 @@ class DatabaseDriver implements Driver
foreach ($foreignKeys AS $foreignKey) {
$allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
}
$pkColumns = $table->getPrimaryKey()->getColumns();
sort($pkColumns);
sort($allForeignKeyColumns);
@@ -145,7 +145,7 @@ class DatabaseDriver implements Driver
}
}
}
/**
* {@inheritdoc}
*/
@@ -169,7 +169,7 @@ class DatabaseDriver implements Driver
} catch(SchemaException $e) {
$primaryKeyColumns = array();
}
if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
} else {
@@ -17,190 +17,38 @@
* <http://www.doctrine-project.org>.
*/
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 {}
require_once __DIR__.'/../Annotation.php';
require_once __DIR__.'/../Entity.php';
require_once __DIR__.'/../MappedSuperclass.php';
require_once __DIR__.'/../InheritanceType.php';
require_once __DIR__.'/../DiscriminatorColumn.php';
require_once __DIR__.'/../DiscriminatorMap.php';
require_once __DIR__.'/../Id.php';
require_once __DIR__.'/../GeneratedValue.php';
require_once __DIR__.'/../Version.php';
require_once __DIR__.'/../JoinColumn.php';
require_once __DIR__.'/../JoinColumns.php';
require_once __DIR__.'/../Column.php';
require_once __DIR__.'/../OneToOne.php';
require_once __DIR__.'/../OneToMany.php';
require_once __DIR__.'/../ManyToOne.php';
require_once __DIR__.'/../ManyToMany.php';
require_once __DIR__.'/../ElementCollection.php';
require_once __DIR__.'/../Table.php';
require_once __DIR__.'/../UniqueConstraint.php';
require_once __DIR__.'/../Index.php';
require_once __DIR__.'/../JoinTable.php';
require_once __DIR__.'/../SequenceGenerator.php';
require_once __DIR__.'/../ChangeTrackingPolicy.php';
require_once __DIR__.'/../OrderBy.php';
require_once __DIR__.'/../NamedQueries.php';
require_once __DIR__.'/../NamedQuery.php';
require_once __DIR__.'/../HasLifecycleCallbacks.php';
require_once __DIR__.'/../PrePersist.php';
require_once __DIR__.'/../PostPersist.php';
require_once __DIR__.'/../PreUpdate.php';
require_once __DIR__.'/../PostUpdate.php';
require_once __DIR__.'/../PreRemove.php';
require_once __DIR__.'/../PostRemove.php';
require_once __DIR__.'/../PostLoad.php';
require_once __DIR__.'/../PreFlush.php';
+4 -4
View File
@@ -34,18 +34,18 @@ interface Driver
{
/**
* Loads the metadata for the specified class into the provided container.
*
*
* @param string $className
* @param ClassMetadataInfo $metadata
*/
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
/**
* Gets the names of all mapped classes known to this driver.
*
*
* @return array The names of all mapped classes known to this driver.
*/
function getAllClassNames();
function getAllClassNames();
/**
* Whether the class with the specified name should have its metadata loaded.
@@ -94,7 +94,7 @@ class DriverChain implements Driver
if (!isset($driverClasses[$oid])) {
$driverClasses[$oid] = $driver->getAllClassNames();
}
foreach ($driverClasses[$oid] AS $className) {
if (strpos($className, $namespace) === 0) {
$classNames[$className] = true;
@@ -0,0 +1,176 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\MappingException;
/**
* XmlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @license MIT
*/
class SimplifiedXmlDriver extends XmlDriver
{
protected $_prefixes = array();
protected $_globalBasename;
protected $_classCache;
protected $_fileExtension = '.orm.xml';
public function __construct($prefixes)
{
$this->addNamespacePrefixes($prefixes);
}
public function setGlobalBasename($file)
{
$this->_globalBasename = $file;
}
public function getGlobalBasename()
{
return $this->_globalBasename;
}
public function addNamespacePrefixes($prefixes)
{
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
$this->addPaths(array_flip($prefixes));
}
public function getNamespacePrefixes()
{
return $this->_prefixes;
}
public function isTransient($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
// The mapping is defined in the global mapping file
if (isset($this->_classCache[$className])) {
return false;
}
try {
$this->_findMappingFile($className);
return false;
} catch (MappingException $e) {
return true;
}
}
public function getAllClassNames()
{
if (null === $this->_classCache) {
$this->initialize();
}
$classes = array();
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if (!is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$fileName = $file->getBasename($this->_fileExtension);
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
continue;
}
// NOTE: All files found here means classes are not transient!
if (isset($this->_prefixes[$path])) {
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
} else {
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
}
return array_merge($classes, array_keys($this->_classCache));
}
public function getElement($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
if (!isset($this->_classCache[$className])) {
$this->_classCache[$className] = parent::getElement($className);
}
return $this->_classCache[$className];
}
protected function initialize()
{
$this->_classCache = array();
if (null !== $this->_globalBasename) {
foreach ($this->_paths as $path) {
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
}
}
}
}
protected function _findMappingFile($className)
{
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
foreach ($this->_paths as $path) {
if (!isset($this->_prefixes[$path])) {
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
}
continue;
}
$prefix = $this->_prefixes[$path];
if (0 !== strpos($className, $prefix.'\\')) {
continue;
}
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
if (is_file($filename)) {
return $filename;
}
throw MappingException::mappingFileNotFound($className, $filename);
}
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
}
}
@@ -0,0 +1,181 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\MappingException;
/**
* YamlDriver that additionally looks for mapping information in a global file.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @license MIT
*/
class SimplifiedYamlDriver extends YamlDriver
{
protected $_prefixes = array();
protected $_globalBasename;
protected $_classCache;
protected $_fileExtension = '.orm.yml';
public function __construct($prefixes)
{
$this->addNamespacePrefixes($prefixes);
}
public function setGlobalBasename($file)
{
$this->_globalBasename = $file;
}
public function getGlobalBasename()
{
return $this->_globalBasename;
}
public function addNamespacePrefixes($prefixes)
{
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
$this->addPaths(array_flip($prefixes));
}
public function addNamespacePrefix($prefix, $path)
{
$this->_prefixes[$path] = $prefix;
}
public function getNamespacePrefixes()
{
return $this->_prefixes;
}
public function isTransient($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
// The mapping is defined in the global mapping file
if (isset($this->_classCache[$className])) {
return false;
}
try {
$this->_findMappingFile($className);
return false;
} catch (MappingException $e) {
return true;
}
}
public function getAllClassNames()
{
if (null === $this->_classCache) {
$this->initialize();
}
$classes = array();
if ($this->_paths) {
foreach ((array) $this->_paths as $path) {
if (!is_dir($path)) {
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path),
\RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
$fileName = $file->getBasename($this->_fileExtension);
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
continue;
}
// NOTE: All files found here means classes are not transient!
if (isset($this->_prefixes[$path])) {
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
} else {
$classes[] = str_replace('.', '\\', $fileName);
}
}
}
}
return array_merge($classes, array_keys($this->_classCache));
}
public function getElement($className)
{
if (null === $this->_classCache) {
$this->initialize();
}
if (!isset($this->_classCache[$className])) {
$this->_classCache[$className] = parent::getElement($className);
}
return $this->_classCache[$className];
}
protected function initialize()
{
$this->_classCache = array();
if (null !== $this->_globalBasename) {
foreach ($this->_paths as $path) {
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
}
}
}
}
protected function _findMappingFile($className)
{
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
foreach ($this->_paths as $path) {
if (!isset($this->_prefixes[$path])) {
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
}
continue;
}
$prefix = $this->_prefixes[$path];
if (0 !== strpos($className, $prefix.'\\')) {
continue;
}
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
if (is_file($filename)) {
return $filename;
}
throw MappingException::mappingFileNotFound($className, $filename);
}
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
}
}
@@ -38,21 +38,21 @@ class StaticPHPDriver implements Driver
{
/**
* Paths of entity directories.
*
*
* @var array
*/
private $_paths = array();
/**
* Map of all class names.
*
*
* @var array
*/
private $_classNames;
/**
* The file extension of mapping documents.
*
*
* @var string
*/
private $_fileExtension = '.php';
+19 -18
View File
@@ -52,13 +52,16 @@ class XmlDriver extends AbstractFileDriver
$xmlRoot = $this->getElement($className);
if ($xmlRoot->getName() == 'entity') {
$metadata->setCustomRepositoryClass(
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
);
if (isset($xmlRoot['repository-class'])) {
$metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']);
}
if (isset($xmlRoot['read-only']) && $xmlRoot['read-only'] == "true") {
$metadata->markReadOnly();
}
} else if ($xmlRoot->getName() == 'mapped-superclass') {
$metadata->setCustomRepositoryClass(
isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null
);
$metadata->isMappedSuperclass = true;
} else {
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
@@ -163,9 +166,12 @@ class XmlDriver extends AbstractFileDriver
foreach ($xmlRoot->field as $fieldMapping) {
$mapping = array(
'fieldName' => (string)$fieldMapping['name'],
'type' => (string)$fieldMapping['type']
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$fieldMapping['type'];
}
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string)$fieldMapping['column'];
}
@@ -216,14 +222,21 @@ class XmlDriver extends AbstractFileDriver
$mapping = array(
'id' => true,
'fieldName' => (string)$idElement['name'],
'type' => (string)$idElement['type']
'fieldName' => (string)$idElement['name']
);
if (isset($idElement['type'])) {
$mapping['type'] = (string)$idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = (string)$idElement['column'];
}
if (isset($idElement['column-definition'])) {
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
}
$metadata->mapField($mapping);
if (isset($idElement->generator)) {
@@ -368,10 +381,6 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
}
if (isset($manyToOneElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement->{'orphan-removal'};
}
$metadata->mapManyToOne($mapping);
}
}
@@ -419,10 +428,6 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade);
}
if (isset($manyToManyElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement->{'orphan-removal'};
}
if (isset($manyToManyElement->{'order-by'})) {
$orderBy = array();
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) {
@@ -475,10 +480,6 @@ class XmlDriver extends AbstractFileDriver
$joinColumn['onDelete'] = (string)$joinColumnElement['on-delete'];
}
if (isset($joinColumnElement['on-update'])) {
$joinColumn['onUpdate'] = (string)$joinColumnElement['on-update'];
}
if (isset($joinColumnElement['column-definition'])) {
$joinColumn['columnDefinition'] = (string)$joinColumnElement['column-definition'];
}
+28 -32
View File
@@ -46,13 +46,16 @@ class YamlDriver extends AbstractFileDriver
$element = $this->getElement($className);
if ($element['type'] == 'entity') {
$metadata->setCustomRepositoryClass(
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
);
if (isset($element['repositoryClass'])) {
$metadata->setCustomRepositoryClass($element['repositoryClass']);
}
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);
@@ -162,16 +165,15 @@ class YamlDriver extends AbstractFileDriver
continue;
}
if (!isset($idElement['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$mapping = array(
'id' => true,
'fieldName' => $name,
'type' => $idElement['type']
'fieldName' => $name
);
if (isset($idElement['type'])) {
$mapping['type'] = $idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = $idElement['column'];
}
@@ -180,6 +182,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['length'] = $idElement['length'];
}
if (isset($idElement['columnDefinition'])) {
$mapping['columnDefinition'] = $idElement['columnDefinition'];
}
$metadata->mapField($mapping);
if (isset($idElement['generator'])) {
@@ -198,19 +204,21 @@ class YamlDriver extends AbstractFileDriver
// Evaluate fields
if (isset($element['fields'])) {
foreach ($element['fields'] as $name => $fieldMapping) {
if (!isset($fieldMapping['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
$mapping = array(
'fieldName' => $name
);
if (isset($fieldMapping['type'])) {
$e = explode('(', $fieldMapping['type']);
$fieldMapping['type'] = $e[0];
$mapping['type'] = $fieldMapping['type'];
if (isset($e[1])) {
$fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1);
}
}
$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'])) {
@@ -375,10 +383,6 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $manyToOneElement['cascade'];
}
if (isset($manyToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToOneElement['orphanRemoval'];
}
$metadata->mapManyToOne($mapping);
}
}
@@ -434,10 +438,6 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $manyToManyElement['cascade'];
}
if (isset($manyToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
}
if (isset($manyToManyElement['orderBy'])) {
$mapping['orderBy'] = $manyToManyElement['orderBy'];
}
@@ -490,10 +490,6 @@ class YamlDriver extends AbstractFileDriver
$joinColumn['onDelete'] = $joinColumnElement['onDelete'];
}
if (isset($joinColumnElement['onUpdate'])) {
$joinColumn['onUpdate'] = $joinColumnElement['onUpdate'];
}
if (isset($joinColumnElement['columnDefinition'])) {
$joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
}
@@ -0,0 +1,31 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ALL")
* @todo check available targets
*/
final class ElementCollection implements Annotation
{
/** @var string */
public $tableName;
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Entity implements Annotation
{
/** @var string */
public $repositoryClass;
/** @var boolean */
public $readOnly = false;
}
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class GeneratedValue implements Annotation
{
/** @var string */
public $strategy = 'AUTO';
}
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class HasLifecycleCallbacks implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Id implements Annotation
{
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class Index implements Annotation
{
/** @var string */
public $name;
/** @var array<string> */
public $columns;
}
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class InheritanceType implements Annotation
{
/** @var string */
public $value;
}
+42
View File
@@ -0,0 +1,42 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target({"PROPERTY","ANNOTATION"})
*/
final class JoinColumn implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $referencedColumnName = 'id';
/** @var boolean */
public $unique = false;
/** @var boolean */
public $nullable = true;
/** @var mixed */
public $onDelete;
/** @var string */
public $columnDefinition;
/** @var string */
public $fieldName; // field name used in non-object hydration (array/scalar)
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class JoinColumns implements Annotation
{
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $value;
}
+36
View File
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class JoinTable implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $schema;
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $joinColumns = array();
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
public $inverseJoinColumns = array();
}
+40
View File
@@ -0,0 +1,40 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToMany implements Annotation
{
/** @var string */
public $targetEntity;
/** @var string */
public $mappedBy;
/** @var string */
public $inversedBy;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var string */
public $indexBy;
}
+36
View File
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class ManyToOne implements Annotation
{
/** @var string */
public $targetEntity;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var string */
public $inversedBy;
}
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class MappedSuperclass implements Annotation
{
/** @var string */
public $repositoryClass;
}
+41 -5
View File
@@ -68,6 +68,11 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No mapping file found named '$fileName' for class '$entityName'.");
}
public static function invalidMappingFile($entityName, $fileName)
{
return new self("Invalid mapping file '$fileName' for class '$entityName'.");
}
public static function mappingNotFound($className, $fieldName)
{
return new self("No mapping found for field '$fieldName' on class '$className'.");
@@ -184,7 +189,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!'
@@ -226,6 +231,11 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported.");
}
public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type)
{
return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers.");
}
/**
* @param string $className
* @param string $columnName
@@ -270,6 +280,12 @@ 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'.");
@@ -279,18 +295,38 @@ 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 descriminator map of '" . $rootClassName . "' " .
"Entity '" . $className . "' has to be part of the discriminator 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."'.");
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class NamedQueries implements Annotation
{
/** @var array<\Doctrine\ORM\Mapping\NamedQuery> */
public $value;
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class NamedQuery implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $query;
}
+40
View File
@@ -0,0 +1,40 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToMany implements Annotation
{
/** @var string */
public $mappedBy;
/** @var string */
public $targetEntity;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var boolean */
public $orphanRemoval = false;
/** @var string */
public $indexBy;
}
+40
View File
@@ -0,0 +1,40 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OneToOne implements Annotation
{
/** @var string */
public $targetEntity;
/** @var string */
public $mappedBy;
/** @var string */
public $inversedBy;
/** @var array<string> */
public $cascade;
/** @var string */
public $fetch = 'LAZY';
/** @var boolean */
public $orphanRemoval = false;
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class OrderBy implements Annotation
{
/** @var array<string> */
public $value;
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostLoad implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostPersist implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostRemove implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PostUpdate implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreFlush implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PrePersist implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreRemove implements Annotation
{
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("METHOD")
*/
final class PreUpdate implements Annotation
{
}
@@ -0,0 +1,34 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class SequenceGenerator implements Annotation
{
/** @var string */
public $sequenceName;
/** @var integer */
public $allocationSize = 1;
/** @var integer */
public $initialValue = 1;
}
+36
View File
@@ -0,0 +1,36 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("CLASS")
*/
final class Table implements Annotation
{
/** @var string */
public $name;
/** @var string */
public $schema;
/** @var array<\Doctrine\ORM\Mapping\Index> */
public $indexes;
/** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */
public $uniqueConstraints;
}
@@ -0,0 +1,32 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("ANNOTATION")
*/
final class UniqueConstraint implements Annotation
{
/** @var string */
public $name;
/** @var array<string> */
public $columns;
}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class Version implements Annotation
{
}
+14 -11
View File
@@ -1,4 +1,4 @@
<?php
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -38,6 +38,7 @@ final class NativeQuery extends AbstractQuery
public function setSQL($sql)
{
$this->_sql = $sql;
return $this;
}
@@ -57,17 +58,19 @@ final class NativeQuery extends AbstractQuery
*/
protected function _doExecute()
{
$stmt = $this->_em->getConnection()->prepare($this->_sql);
$params = $this->_params;
foreach ($params as $key => $value) {
if (isset($this->_paramTypes[$key])) {
$stmt->bindValue($key, $value, $this->_paramTypes[$key]);
} else {
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
$types = $this->_paramTypes;
return $stmt;
if ($params && is_int(key($params))) {
ksort($params);
ksort($types);
$params = array_values($params);
$types = array_values($types);
}
return $this->_em->getConnection()->executeQuery(
$this->_sql, $params, $types, $this->_queryCacheProfile
);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly does not return any results.
*
*
* @author robo
* @since 2.0
*/
@@ -21,7 +21,7 @@ namespace Doctrine\ORM;
/**
* Exception thrown when an ORM query unexpectedly returns more than one result.
*
*
* @author robo
* @since 2.0
*/
+17 -7
View File
@@ -34,27 +34,26 @@ class ORMException extends Exception
return new self("It's a requirement to specify a Metadata Driver and pass it ".
"to Doctrine\ORM\Configuration::setMetadataDriverImpl().");
}
public static function entityMissingForeignAssignedId($entity, $relatedEntity)
{
return new self(
"Entity of type " . get_class($entity) . " has identity through a foreign entity " . get_class($relatedEntity) . ", " .
"however this entity has no ientity itself. You have to call EntityManager#persist() on the related entity " .
"and make sure it an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " .
"however this entity has no identity itself. You have to call EntityManager#persist() on the related entity " .
"and make sure that an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " .
"of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call " .
"EntityManager#flush() between both persist operations."
);
}
public static function entityMissingAssignedId($entity)
public static function entityMissingAssignedIdForField($entity, $field)
{
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID. " .
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID for field '" . $field . "'. " .
"The identifier generation strategy for this entity requires the ID field to be populated before ".
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
"you need to adjust the metadata mapping accordingly."
);
}
public static function unrecognizedField($field)
{
return new self("Unrecognized field: $field");
@@ -139,4 +138,15 @@ class ORMException extends Exception
"Unknown Entity namespace alias '$entityNamespaceAlias'."
);
}
public static function invalidEntityRepository($className)
{
return new self("Invalid repository class '".$className."'. ".
"it must be a Doctrine\ORM\EntityRepository.");
}
public static function missingIdentifierField($className, $fieldName)
{
return new self("The identifier $fieldName is missing for a query of " . $className);
}
}
@@ -0,0 +1,107 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
/**
* Contains exception messages for all invalid lifecycle state exceptions inside UnitOfWork
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ORMInvalidArgumentException extends \InvalidArgumentException
{
static public function scheduleInsertForManagedEntity($entity)
{
return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertForRemovedEntity($entity)
{
return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertTwice($entity)
{
return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice.");
}
static public function entityWithoutIdentity($className, $entity)
{
throw new self(
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"id values set. It cannot be added to the identity map."
);
}
static public function readOnlyRequiresManagedEntity($entity)
{
return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not");
}
static public function newEntityFoundThroughRelationship(array $assoc, $entry)
{
return new self("A new entity was found through the relationship '"
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
. " To solve this issue: Either explicitly call EntityManager#persist()"
. " on this unknown entity or configure cascade persist "
. " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). "
. " If you cannot find out which entity causes the problem"
. " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.");
}
static public function detachedEntityFoundThroughRelationship(array $assoc, $entry)
{
throw new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") "
. " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' "
. "during cascading a persist operation.");
}
static public function entityNotManaged($entity)
{
throw new self("Entity " . self::objToStr($entity) . " is not managed. An entity is managed if its fetched " .
"from the database or registered as new through EntityManager#persist");
}
static public function entityHasNoIdentity($entity, $operation)
{
throw new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function entityIsRemoved($entity, $operation)
{
throw new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function detachedEntityCannot($entity, $operation)
{
throw new self("A detached entity was found during " . $operation . " " . self::objToStr($entity));
}
/**
* Helper method to show an object as string.
*
* @param object $obj
* @return string
*/
private static function objToStr($obj)
{
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
}
}
+151 -79
View File
@@ -21,6 +21,7 @@ namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\Common\Collections\Collection,
Doctrine\Common\Collections\ArrayCollection,
Closure;
/**
@@ -114,8 +115,8 @@ final class PersistentCollection implements Collection
*/
public function __construct(EntityManager $em, $class, $coll)
{
$this->coll = $coll;
$this->em = $em;
$this->coll = $coll;
$this->em = $em;
$this->typeClass = $class;
}
@@ -129,8 +130,8 @@ final class PersistentCollection implements Collection
*/
public function setOwner($entity, array $assoc)
{
$this->owner = $entity;
$this->association = $assoc;
$this->owner = $entity;
$this->association = $assoc;
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
}
@@ -160,16 +161,18 @@ final class PersistentCollection implements Collection
public function hydrateAdd($element)
{
$this->coll->add($element);
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
$this->em->getUnitOfWork()->setOriginalEntityProperty(
spl_object_hash($element),
$this->backRefFieldName,
$this->owner);
spl_object_hash($element), $this->backRefFieldName, $this->owner
);
}
}
@@ -183,12 +186,14 @@ final class PersistentCollection implements Collection
public function hydrateSet($key, $element)
{
$this->coll->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
$element, $this->owner
);
}
}
@@ -198,23 +203,31 @@ final class PersistentCollection implements Collection
*/
public function initialize()
{
if ( ! $this->initialized && $this->association) {
if ($this->isDirty) {
// Has NEW objects added through add(). Remember them.
$newObjects = $this->coll->toArray();
}
$this->coll->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if (isset($newObjects)) {
foreach ($newObjects as $obj) {
$this->coll->add($obj);
}
$this->isDirty = true;
}
$this->initialized = true;
if ($this->initialized || ! $this->association) {
return;
}
// Has NEW objects added through add(). Remember them.
$newObjects = array();
if ($this->isDirty) {
$newObjects = $this->coll->toArray();
}
$this->coll->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if ($newObjects) {
foreach ($newObjects as $obj) {
$this->coll->add($obj);
}
$this->isDirty = true;
}
$this->initialized = true;
}
/**
@@ -224,7 +237,7 @@ final class PersistentCollection implements Collection
public function takeSnapshot()
{
$this->snapshot = $this->coll->toArray();
$this->isDirty = false;
$this->isDirty = false;
}
/**
@@ -246,8 +259,11 @@ final class PersistentCollection implements Collection
*/
public function getDeleteDiff()
{
return array_udiff_assoc($this->snapshot, $this->coll->toArray(),
function($a, $b) {return $a === $b ? 0 : 1;});
return array_udiff_assoc(
$this->snapshot,
$this->coll->toArray(),
function($a, $b) { return $a === $b ? 0 : 1; }
);
}
/**
@@ -258,8 +274,11 @@ final class PersistentCollection implements Collection
*/
public function getInsertDiff()
{
return array_udiff_assoc($this->coll->toArray(), $this->snapshot,
function($a, $b) {return $a === $b ? 0 : 1;});
return array_udiff_assoc(
$this->coll->toArray(),
$this->snapshot,
function($a, $b) { return $a === $b ? 0 : 1; }
);
}
/**
@@ -277,12 +296,17 @@ final class PersistentCollection implements Collection
*/
private function changed()
{
if ( ! $this->isDirty) {
$this->isDirty = true;
if ($this->association !== null && $this->association['isOwningSide'] && $this->association['type'] == ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
if ($this->isDirty) {
return;
}
$this->isDirty = true;
if ($this->association !== null &&
$this->association['isOwningSide'] &&
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
}
@@ -331,6 +355,7 @@ final class PersistentCollection implements Collection
public function first()
{
$this->initialize();
return $this->coll->first();
}
@@ -338,6 +363,7 @@ final class PersistentCollection implements Collection
public function last()
{
$this->initialize();
return $this->coll->last();
}
@@ -351,13 +377,19 @@ final class PersistentCollection implements Collection
// not used we can issue a straight SQL delete/update on the
// association (table). Without initializing the collection.
$this->initialize();
$removed = $this->coll->remove($key);
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
if ( ! $removed) {
return $removed;
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
return $removed;
@@ -368,25 +400,36 @@ final class PersistentCollection implements Collection
*/
public function removeElement($element)
{
// TODO: Assuming the identity of entities in a collection is always based
// on their primary key (there is no equals/hashCode in PHP),
// if the collection is not initialized, we could issue a straight
// SQL DELETE/UPDATE on the association (table) without initializing
// the collection.
/*if ( ! $this->initialized) {
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
->deleteRows($this, $element);
}*/
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ($this->coll->contains($element)) {
return $this->coll->removeElement($element);
}
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
if ($persister->removeElement($this, $element)) {
return $element;
}
return null;
}
$this->initialize();
$removed = $this->coll->removeElement($element);
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
if ( ! $removed) {
return $removed;
}
$this->changed();
if ($this->association !== null &&
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
return $removed;
}
@@ -396,6 +439,7 @@ final class PersistentCollection implements Collection
public function containsKey($key)
{
$this->initialize();
return $this->coll->containsKey($key);
}
@@ -404,14 +448,14 @@ final class PersistentCollection implements Collection
*/
public function contains($element)
{
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->coll->contains($element) ||
$this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->contains($this, $element);
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->coll->contains($element) || $persister->contains($this, $element);
}
$this->initialize();
return $this->coll->contains($element);
}
@@ -421,6 +465,7 @@ final class PersistentCollection implements Collection
public function exists(Closure $p)
{
$this->initialize();
return $this->coll->exists($p);
}
@@ -430,6 +475,7 @@ final class PersistentCollection implements Collection
public function indexOf($element)
{
$this->initialize();
return $this->coll->indexOf($element);
}
@@ -439,6 +485,7 @@ final class PersistentCollection implements Collection
public function get($key)
{
$this->initialize();
return $this->coll->get($key);
}
@@ -448,6 +495,7 @@ final class PersistentCollection implements Collection
public function getKeys()
{
$this->initialize();
return $this->coll->getKeys();
}
@@ -457,6 +505,7 @@ final class PersistentCollection implements Collection
public function getValues()
{
$this->initialize();
return $this->coll->getValues();
}
@@ -465,13 +514,14 @@ final class PersistentCollection implements Collection
*/
public function count()
{
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->count($this) + ($this->isDirty ? $this->coll->count() : 0);
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
}
$this->initialize();
return $this->coll->count();
}
@@ -481,7 +531,9 @@ final class PersistentCollection implements Collection
public function set($key, $value)
{
$this->initialize();
$this->coll->set($key, $value);
$this->changed();
}
@@ -491,7 +543,9 @@ final class PersistentCollection implements Collection
public function add($value)
{
$this->coll->add($value);
$this->changed();
return true;
}
@@ -501,6 +555,7 @@ final class PersistentCollection implements Collection
public function isEmpty()
{
$this->initialize();
return $this->coll->isEmpty();
}
@@ -510,6 +565,7 @@ final class PersistentCollection implements Collection
public function getIterator()
{
$this->initialize();
return $this->coll->getIterator();
}
@@ -519,6 +575,7 @@ final class PersistentCollection implements Collection
public function map(Closure $func)
{
$this->initialize();
return $this->coll->map($func);
}
@@ -528,6 +585,7 @@ final class PersistentCollection implements Collection
public function filter(Closure $p)
{
$this->initialize();
return $this->coll->filter($p);
}
@@ -537,6 +595,7 @@ final class PersistentCollection implements Collection
public function forAll(Closure $p)
{
$this->initialize();
return $this->coll->forAll($p);
}
@@ -546,6 +605,7 @@ final class PersistentCollection implements Collection
public function partition(Closure $p)
{
$this->initialize();
return $this->coll->partition($p);
}
@@ -555,6 +615,7 @@ final class PersistentCollection implements Collection
public function toArray()
{
$this->initialize();
return $this->coll->toArray();
}
@@ -566,19 +627,28 @@ final class PersistentCollection implements Collection
if ($this->initialized && $this->isEmpty()) {
return;
}
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
$uow = $this->em->getUnitOfWork();
if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
// hence for event listeners we need the objects in memory.
$this->initialize();
foreach ($this->coll as $element) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
$uow->scheduleOrphanRemoval($element);
}
}
$this->coll->clear();
$this->initialized = true; // direct call, {@link initialize()} is too expensive
if ($this->association['isOwningSide']) {
$this->changed();
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);
$uow->scheduleCollectionDeletion($this);
$this->takeSnapshot();
}
}
@@ -622,6 +692,7 @@ final class PersistentCollection implements Collection
if ( ! isset($offset)) {
return $this->add($value);
}
return $this->set($offset, $value);
}
@@ -656,6 +727,8 @@ final class PersistentCollection implements Collection
/**
* Retrieves the wrapped Collection instance.
*
* @return \Doctrine\Common\Collections\Collection
*/
public function unwrap()
{
@@ -671,20 +744,19 @@ final class PersistentCollection implements Collection
*
* @param int $offset
* @param int $length
*
* @return array
*/
public function slice($offset, $length = null)
{
if ( ! $this->initialized &&
! $this->isDirty &&
$this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->slice($this, $offset, $length);
return $persister->slice($this, $offset, $length);
}
$this->initialize();
return $this->coll->slice($offset, $length);
}
}
@@ -65,11 +65,11 @@ abstract class AbstractCollectionPersister
public function delete(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSQL($coll);
$this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll));
}
@@ -98,34 +98,34 @@ abstract class AbstractCollectionPersister
public function update(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$this->deleteRows($coll);
//$this->updateRows($coll);
$this->insertRows($coll);
}
public function deleteRows(PersistentCollection $coll)
{
{
$deleteDiff = $coll->getDeleteDiff();
$sql = $this->_getDeleteRowSQL($coll);
foreach ($deleteDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
}
}
//public function updateRows(PersistentCollection $coll)
//{}
public function insertRows(PersistentCollection $coll)
{
$insertDiff = $coll->getInsertDiff();
$sql = $this->_getInsertRowSQL($coll);
foreach ($insertDiff as $element) {
$this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element));
}
@@ -151,6 +151,16 @@ abstract class AbstractCollectionPersister
throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister.");
}
public function removeElement(PersistentCollection $coll, $element)
{
throw new \BadMethodCallException("Removing an element is not supported by this CollectionPersister.");
}
public function removeKey(PersistentCollection $coll, $key)
{
throw new \BadMethodCallException("Removing a key is not supported by this CollectionPersister.");
}
public function get(PersistentCollection $coll, $index)
{
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
@@ -158,7 +168,7 @@ abstract class AbstractCollectionPersister
/**
* Gets the SQL statement used for deleting a row from the collection.
*
*
* @param PersistentCollection $coll
*/
abstract protected function _getDeleteRowSQL(PersistentCollection $coll);
@@ -26,7 +26,7 @@ use Doctrine\ORM\Mapping\ClassMetadata,
* Base class for entity persisters that implement a certain inheritance mapping strategy.
* All these persisters are assumed to use a discriminator column to discriminate entity
* types in the hierarchy.
*
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
@@ -39,18 +39,18 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
protected function _prepareInsertData($entity)
{
$data = parent::_prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->_class->discriminatorColumn;
$this->_columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue;
return $data;
}
/**
* Gets the name of the table that contains the discriminator column.
*
*
* @return string The table name.
*/
abstract protected function _getDiscriminatorColumnTableName();
@@ -62,18 +62,22 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$columnAlias = $this->getSQLColumnAlias($columnName);
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
}
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
{
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++;
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
$this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
}
}
}
@@ -26,6 +26,7 @@ use PDO,
Doctrine\ORM\ORMException,
Doctrine\ORM\OptimisticLockException,
Doctrine\ORM\EntityManager,
Doctrine\ORM\UnitOfWork,
Doctrine\ORM\Query,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Mapping\MappingException,
@@ -71,6 +72,7 @@ use PDO,
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
*/
class BasicEntityPersister
@@ -221,14 +223,14 @@ class BasicEntityPersister
$isPostInsertId = $idGen->isPostInsertGenerator();
$stmt = $this->_conn->prepare($this->_getInsertSQL());
$tableName = $this->_class->table['name'];
$tableName = $this->_class->getTableName();
foreach ($this->_queuedInserts as $entity) {
$insertData = $this->_prepareInsertData($entity);
if (isset($insertData[$tableName])) {
$paramIndex = 1;
foreach ($insertData[$tableName] as $column => $value) {
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$column]);
}
@@ -278,11 +280,14 @@ class BasicEntityPersister
protected function fetchVersionValue($versionedClass, $id)
{
$versionField = $versionedClass->versionField;
$identifier = $versionedClass->getIdentifierColumnNames();
$versionFieldColumnName = $versionedClass->getColumnName($versionField);
$identifier = $versionedClass->getIdentifierColumnNames();
$versionFieldColumnName = $versionedClass->getQuotedColumnName($versionField, $this->_platform);
//FIXME: Order with composite keys might not be correct
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $versionedClass->getQuotedTableName($this->_platform)
. " WHERE " . implode(' = ? AND ', $identifier) . " = ?";
$sql = 'SELECT ' . $versionFieldColumnName
. ' FROM ' . $versionedClass->getQuotedTableName($this->_platform)
. ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';
$value = $this->_conn->fetchColumn($sql, array_values((array)$id));
return Type::getType($versionedClass->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->_platform);
@@ -305,7 +310,8 @@ class BasicEntityPersister
public function update($entity)
{
$updateData = $this->_prepareUpdateData($entity);
$tableName = $this->_class->table['name'];
$tableName = $this->_class->getTableName();
if (isset($updateData[$tableName]) && $updateData[$tableName]) {
$this->_updateTable(
$entity, $this->_class->getQuotedTableName($this->_platform),
@@ -333,17 +339,26 @@ class BasicEntityPersister
$set = $params = $types = array();
foreach ($updateData as $columnName => $value) {
$column = $columnName;
$placeholder = '?';
if (isset($this->_class->fieldNames[$columnName])) {
$set[] = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?';
} else {
$set[] = $columnName . ' = ?';
$column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform);
if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) {
$type = Type::getType($this->_columnTypes[$columnName]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);
}
}
$set[] = $column . ' = ' . $placeholder;
$params[] = $value;
$types[] = $this->_columnTypes[$columnName];
}
$where = array();
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
foreach ($this->_class->identifier as $idField) {
if (isset($this->_class->associationMappings[$idField])) {
$targetMapping = $this->_em->getClassMetadata($this->_class->associationMappings[$idField]['targetEntity']);
@@ -361,18 +376,21 @@ class BasicEntityPersister
$versionField = $this->_class->versionField;
$versionFieldType = $this->_class->fieldMappings[$versionField]['type'];
$versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform);
if ($versionFieldType == Type::INTEGER) {
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
} else if ($versionFieldType == Type::DATETIME) {
$set[] = $versionColumn . ' = CURRENT_TIMESTAMP';
}
$where[] = $versionColumn;
$params[] = $this->_class->reflFields[$versionField]->getValue($entity);
$types[] = $this->_class->fieldMappings[$versionField]['type'];
}
$sql = "UPDATE $quotedTableName SET " . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
$sql = 'UPDATE ' . $quotedTableName
. ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
$result = $this->_conn->executeUpdate($sql, $params, $types);
@@ -398,21 +416,29 @@ class BasicEntityPersister
$relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$mapping = $relatedClass->associationMappings[$mapping['mappedBy']];
$keys = array_keys($mapping['relationToTargetKeyColumns']);
if ($selfReferential) {
$otherKeys = array_keys($mapping['relationToSourceKeyColumns']);
}
} else {
$keys = array_keys($mapping['relationToSourceKeyColumns']);
if ($selfReferential) {
$otherKeys = array_keys($mapping['relationToTargetKeyColumns']);
}
}
if ( ! isset($mapping['isOnDeleteCascade'])) {
$this->_conn->delete($mapping['joinTable']['name'], array_combine($keys, $identifier));
$this->_conn->delete(
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
array_combine($keys, $identifier)
);
if ($selfReferential) {
$this->_conn->delete($mapping['joinTable']['name'], array_combine($otherKeys, $identifier));
$this->_conn->delete(
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
array_combine($otherKeys, $identifier)
);
}
}
}
@@ -463,7 +489,7 @@ class BasicEntityPersister
$result = array();
$uow = $this->_em->getUnitOfWork();
if ($versioned = $this->_class->isVersioned) {
if (($versioned = $this->_class->isVersioned) != false) {
$versionField = $this->_class->versionField;
}
@@ -477,6 +503,7 @@ class BasicEntityPersister
if (isset($this->_class->associationMappings[$field])) {
$assoc = $this->_class->associationMappings[$field];
// Only owning side of x-1 associations can have a FK column.
if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
continue;
@@ -484,6 +511,7 @@ class BasicEntityPersister
if ($newVal !== null) {
$oid = spl_object_hash($newVal);
if (isset($this->_queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) {
// The associated entity $newVal is not yet persisted, so we must
// set $newVal = null, in order to insert a null value and schedule an
@@ -510,6 +538,7 @@ class BasicEntityPersister
} else {
$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
}
$this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn);
}
} else {
@@ -518,6 +547,7 @@ class BasicEntityPersister
$result[$this->getOwningTable($field)][$columnName] = $newVal;
}
}
return $result;
}
@@ -548,7 +578,7 @@ class BasicEntityPersister
*/
public function getOwningTable($fieldName)
{
return $this->_class->table['name'];
return $this->_class->getTableName();
}
/**
@@ -560,12 +590,13 @@ class BasicEntityPersister
* @param $assoc The association that connects the entity to load to another entity, if any.
* @param array $hints Hints for entity creation.
* @param int $lockMode
* @param int $limit Limit number of results
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
* @todo Check identity map? loadById method? Try to guess whether $criteria is the id?
*/
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0)
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0, $limit = null)
{
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode);
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode, $limit);
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
@@ -574,12 +605,9 @@ class BasicEntityPersister
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
}
if ($this->_selectJoinSql) {
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
} else {
$hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT);
}
$hydrator = $this->_em->newHydrator($this->_selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
$entities = $hydrator->hydrateAll($stmt, $this->_rsm, $hints);
return $entities ? $entities[0] : null;
}
@@ -596,7 +624,7 @@ class BasicEntityPersister
*/
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array())
{
if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) {
if (($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) != false) {
return $foundEntity;
}
@@ -608,14 +636,11 @@ class BasicEntityPersister
// Mark inverse side as fetched in the hints, otherwise the UoW would
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
$hints = array();
if ($isInverseSingleValued) {
$hints['fetched'][$targetClass->name][$assoc['inversedBy']] = true;
if ($targetClass->subClasses) {
foreach ($targetClass->subClasses as $targetSubclassName) {
$hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true;
}
}
$hints['fetched']["r"][$assoc['inversedBy']] = true;
}
/* cascade read-only status
if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) {
$hints[Query::HINT_READ_ONLY] = true;
@@ -631,19 +656,21 @@ class BasicEntityPersister
} else {
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']);
// TRICKY: since the association is specular source and target are flipped
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
// unset the old value and set the new sql aliased value here. By definition
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
$identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
unset($identifier[$targetKeyColumn]);
} else {
if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) {
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
);
}
// unset the old value and set the new sql aliased value here. By definition
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
$identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
unset($identifier[$targetKeyColumn]);
}
$targetEntity = $this->load($identifier, null, $assoc);
@@ -675,7 +702,9 @@ class BasicEntityPersister
if (isset($this->_class->lifecycleCallbacks[Events::postLoad])) {
$this->_class->invokeLifecycleCallbacks(Events::postLoad, $entity);
}
$evm = $this->_em->getEventManager();
if ($evm->hasListeners(Events::postLoad)) {
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
}
@@ -697,11 +726,8 @@ class BasicEntityPersister
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
if ($this->_selectJoinSql) {
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
} else {
$hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT);
}
$hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true));
}
@@ -717,6 +743,7 @@ class BasicEntityPersister
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
return $this->loadArrayFromStatement($assoc, $stmt);
}
@@ -725,6 +752,7 @@ class BasicEntityPersister
*
* @param array $assoc
* @param \Doctrine\DBAL\Statement $stmt
*
* @return array
*/
private function loadArrayFromStatement($assoc, $stmt)
@@ -739,6 +767,7 @@ class BasicEntityPersister
}
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
return $hydrator->hydrateAll($stmt, $rsm, $hints);
}
@@ -748,6 +777,8 @@ class BasicEntityPersister
* @param array $assoc
* @param \Doctrine\DBAL\Statement $stmt
* @param PersistentCollection $coll
*
* @return array
*/
private function loadCollectionFromStatement($assoc, $stmt, $coll)
{
@@ -761,7 +792,8 @@ class BasicEntityPersister
}
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
$hydrator->hydrateAll($stmt, $rsm, $hints);
return $hydrator->hydrateAll($stmt, $rsm, $hints);
}
/**
@@ -777,6 +809,7 @@ class BasicEntityPersister
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
}
@@ -784,12 +817,15 @@ class BasicEntityPersister
{
$criteria = array();
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
if ($assoc['isOwningSide']) {
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
if (isset($sourceClass->associationMappings[$field])) {
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
@@ -807,15 +843,18 @@ class BasicEntityPersister
} else {
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform);
// TRICKY: since the association is inverted source and target are flipped
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
if (isset($sourceClass->associationMappings[$field])) {
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
}
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
@@ -829,6 +868,7 @@ class BasicEntityPersister
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
list($params, $types) = $this->expandParameters($criteria);
return $this->_conn->executeQuery($sql, $params, $types);
}
@@ -847,24 +887,33 @@ class BasicEntityPersister
*/
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null)
{
$joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
$this->_getSelectManyToManyJoinSQL($assoc) : '';
$joinSql = ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : '';
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
$orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $this->_getSQLTableAlias($this->_class->name)) : '';
$lockSql = '';
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$lockSql = ' ' . $this->_platform->getReadLockSql();
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$lockSql = ' ' . $this->_platform->getWriteLockSql();
}
$alias = $this->_getSQLTableAlias($this->_class->name);
if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) {
if ($conditionSql) {
$conditionSql .= ' AND ';
}
$conditionSql .= $filterSql;
}
return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL()
. $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($this->_class->name), $lockMode)
. $alias, $lockMode)
. $this->_selectJoinSql . $joinSql
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
. $orderBySql, $limit, $offset)
@@ -881,6 +930,7 @@ class BasicEntityPersister
protected final function _getOrderBySQL(array $orderBy, $baseTableAlias)
{
$orderBySql = '';
foreach ($orderBy as $fieldName => $orientation) {
if ( ! isset($this->_class->fieldMappings[$fieldName])) {
throw ORMException::unrecognizedField($fieldName);
@@ -896,6 +946,7 @@ class BasicEntityPersister
: $baseTableAlias;
$columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
$orderBySql .= $orderBySql ? ', ' : ' ORDER BY ';
$orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
}
@@ -928,20 +979,25 @@ class BasicEntityPersister
// Add regular columns to select list
foreach ($this->_class->fieldNames as $field) {
if ($columnList) $columnList .= ', ';
$columnList .= $this->_getSelectColumnSQL($field, $this->_class);
}
$this->_selectJoinSql = '';
$eagerAliasCounter = 0;
foreach ($this->_class->associationMappings as $assocField => $assoc) {
$assocColumnSQL = $this->_getSelectColumnAssociationSQL($assocField, $assoc, $this->_class);
if ($assocColumnSQL) {
if ($columnList) $columnList .= ', ';
$columnList .= $assocColumnSQL;
}
if ($assoc['type'] & ClassMetadata::TO_ONE && ($assoc['fetch'] == ClassMetadata::FETCH_EAGER || !$assoc['isOwningSide'])) {
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) {
continue; // now this is why you shouldn't use inheritance
}
@@ -951,41 +1007,53 @@ class BasicEntityPersister
foreach ($eagerEntity->fieldNames AS $field) {
if ($columnList) $columnList .= ', ';
$columnList .= $this->_getSelectColumnSQL($field, $eagerEntity, $assocAlias);
}
foreach ($eagerEntity->associationMappings as $assoc2Field => $assoc2) {
$assoc2ColumnSQL = $this->_getSelectColumnAssociationSQL($assoc2Field, $assoc2, $eagerEntity, $assocAlias);
if ($assoc2ColumnSQL) {
if ($columnList) $columnList .= ', ';
$columnList .= $assoc2ColumnSQL;
}
}
$this->_selectJoinSql .= ' LEFT JOIN'; // TODO: Inner join when all join columns are NOT nullable.
$first = true;
if ($assoc['isOwningSide']) {
$this->_selectJoinSql .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
if ($assoc['isOwningSide']) {
$this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']);
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
$tableAlias = $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias);
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
if (!$first) {
if ( ! $first) {
$this->_selectJoinSql .= ' AND ';
}
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.'.$sourceCol.' = ' .
$this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.'.$targetCol.' ';
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
. $tableAlias . '.' . $targetCol;
$first = false;
}
// Add filter SQL
if ($filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias)) {
$this->_selectJoinSql .= ' AND ' . $filterSql;
}
} else {
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
$owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
$this->_selectJoinSql .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
$this->_selectJoinSql .= ' LEFT JOIN';
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON ';
foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
if (!$first) {
if ( ! $first) {
$this->_selectJoinSql .= ' AND ';
}
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.'.$sourceCol.' = ' .
$this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' ';
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol;
$first = false;
}
}
@@ -997,20 +1065,31 @@ class BasicEntityPersister
return $this->_selectColumnListSql;
}
/**
* Gets the SQL join fragment used when selecting entities from an association.
*
* @param string $field
* @param array $assoc
* @param ClassMetadata $class
* @param string $alias
*
* @return string
*/
protected function _getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r')
{
$columnList = '';
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList) $columnList .= ', ';
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
$resultColumnName = $this->getSQLColumnAlias($srcColumn);
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
. '.' . $srcColumn . ' AS ' . $resultColumnName;
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
}
}
return $columnList;
}
@@ -1032,23 +1111,22 @@ class BasicEntityPersister
}
$joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform);
$joinSql = '';
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
if ($joinSql != '') $joinSql .= ' AND ';
if ($this->_class->containsForeignIdentifier && !isset($this->_class->fieldNames[$sourceColumn])) {
if ($this->_class->containsForeignIdentifier && ! isset($this->_class->fieldNames[$sourceColumn])) {
$quotedColumn = $sourceColumn; // join columns cannot be quoted
} else {
$quotedColumn = $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform);
}
$joinSql .= $this->_getSQLTableAlias($this->_class->name) .
'.' . $quotedColumn . ' = '
. $joinTableName . '.' . $joinTableColumn;
$joinSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $quotedColumn . ' = '
. $joinTableName . '.' . $joinTableColumn;
}
return " INNER JOIN $joinTableName ON $joinSql";
return ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql;
}
/**
@@ -1061,21 +1139,35 @@ class BasicEntityPersister
if ($this->_insertSql === null) {
$insertSql = '';
$columns = $this->_getInsertColumnList();
if (empty($columns)) {
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
$this->_class->getQuotedTableName($this->_platform),
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
$this->_class->getQuotedTableName($this->_platform),
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
);
} else {
$columns = array_unique($columns);
$values = array_fill(0, count($columns), '?');
$values = array();
foreach ($columns AS $column) {
$placeholder = '?';
if (isset($this->_columnTypes[$column]) &&
isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) {
$type = Type::getType($this->_columnTypes[$column]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);
}
$values[] = $placeholder;
}
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
. ' (' . implode(', ', $columns) . ') '
. 'VALUES (' . implode(', ', $values) . ')';
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')';
}
$this->_insertSql = $insertSql;
}
return $this->_insertSql;
}
@@ -1090,20 +1182,23 @@ class BasicEntityPersister
protected function _getInsertColumnList()
{
$columns = array();
foreach ($this->_class->reflFields as $name => $field) {
if ($this->_class->isVersioned && $this->_class->versionField == $name) {
continue;
}
if (isset($this->_class->associationMappings[$name])) {
$assoc = $this->_class->associationMappings[$name];
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
$columns[] = $sourceCol;
}
}
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY ||
$this->_class->identifier[0] != $name) {
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) {
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
$this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type'];
}
}
@@ -1120,12 +1215,18 @@ class BasicEntityPersister
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
. '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
return "$sql AS $columnAlias";
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
}
/**
@@ -1138,15 +1239,17 @@ class BasicEntityPersister
protected function _getSQLTableAlias($className, $assocName = '')
{
if ($assocName) {
$className .= '#'.$assocName;
$className .= '#' . $assocName;
}
if (isset($this->_sqlTableAliases[$className])) {
return $this->_sqlTableAliases[$className];
}
$tableAlias = 't' . $this->_sqlAliasCounter++;
$this->_sqlTableAliases[$className] = $tableAlias;
return $tableAlias;
}
@@ -1170,7 +1273,9 @@ class BasicEntityPersister
$sql = 'SELECT 1 '
. $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode)
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql;
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
}
@@ -1182,7 +1287,7 @@ class BasicEntityPersister
protected function getLockTablesSql()
{
return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($this->_class->name);
. $this->_getSQLTableAlias($this->_class->name);
}
/**
@@ -1199,28 +1304,33 @@ class BasicEntityPersister
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
{
$conditionSql = '';
foreach ($criteria as $field => $value) {
$conditionSql .= $conditionSql ? ' AND ' : '';
$placeholder = '?';
if (isset($this->_class->columnNames[$field])) {
if (isset($this->_class->fieldMappings[$field]['inherited'])) {
$conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.';
} else {
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
$className = (isset($this->_class->fieldMappings[$field]['inherited']))
? $this->_class->fieldMappings[$field]['inherited']
: $this->_class->name;
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($this->_class->getTypeOfField($field));
$placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform);
}
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
} else if (isset($this->_class->associationMappings[$field])) {
if (!$this->_class->associationMappings[$field]['isOwningSide']) {
if ( ! $this->_class->associationMappings[$field]['isOwningSide']) {
throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
}
if (isset($this->_class->associationMappings[$field]['inherited'])) {
$conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.';
} else {
$conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
}
$className = (isset($this->_class->associationMappings[$field]['inherited']))
? $this->_class->associationMappings[$field]['inherited']
: $this->_class->name;
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
} else if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
// very careless developers could potentially open up this normally hidden api for userland attacks,
// therefore checking for spaces and function calls which are not allowed.
@@ -1230,7 +1340,8 @@ class BasicEntityPersister
} else {
throw ORMException::unrecognizedField($field);
}
$conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ?');
$conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ' . $placeholder);
}
return $conditionSql;
}
@@ -1247,6 +1358,7 @@ class BasicEntityPersister
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
return $this->loadArrayFromStatement($assoc, $stmt);
}
@@ -1262,7 +1374,8 @@ class BasicEntityPersister
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
$this->loadCollectionFromStatement($assoc, $stmt, $coll);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
}
/**
@@ -1280,18 +1393,18 @@ class BasicEntityPersister
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$tableAlias = isset($owningAssoc['inherited']) ?
$this->_getSQLTableAlias($owningAssoc['inherited'])
: $this->_getSQLTableAlias($this->_class->name);
$tableAlias = $this->_getSQLTableAlias(isset($owningAssoc['inherited']) ? $owningAssoc['inherited'] : $this->_class->name);
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
if (isset($sourceClass->associationMappings[$field])) {
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
}
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
} else {
$criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
@@ -1319,19 +1432,98 @@ class BasicEntityPersister
continue; // skip null values.
}
$type = null;
if (is_array($value)) {
$type = Type::getType( $this->_class->fieldMappings[$field]['type'] )->getBindingType();
$type += Connection::ARRAY_PARAM_OFFSET;
} else if (isset($this->_class->fieldMappings[$field])) {
$type = $this->_class->fieldMappings[$field]['type'];
}
$params[] = $value;
$types[] = $type;
$types[] = $this->getType($field, $value);
$params[] = $this->getValue($value);
}
return array($params, $types);
}
/**
* Infer field type to be used by parameter type casting.
*
* @param string $field
* @param mixed $value
* @return integer
*/
private function getType($field, $value)
{
switch (true) {
case (isset($this->_class->fieldMappings[$field])):
$type = $this->_class->fieldMappings[$field]['type'];
break;
case (isset($this->_class->associationMappings[$field])):
$assoc = $this->_class->associationMappings[$field];
if (count($assoc['sourceToTargetKeyColumns']) > 1) {
throw Query\QueryException::associationPathCompositeKeyNotSupported();
}
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
$targetColumn = $assoc['joinColumns'][0]['referencedColumnName'];
$type = null;
if (isset($targetClass->fieldNames[$targetColumn])) {
$type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'];
}
break;
default:
$type = null;
}
if (is_array($value)) {
$type = Type::getType( $type )->getBindingType();
$type += Connection::ARRAY_PARAM_OFFSET;
}
return $type;
}
/**
* Retrieve parameter value
*
* @param mixed $value
* @return mixed
*/
private function getValue($value)
{
if (is_array($value)) {
$newValue = array();
foreach ($value as $itemValue) {
$newValue[] = $this->getIndividualValue($itemValue);
}
return $newValue;
}
return $this->getIndividualValue($value);
}
/**
* Retrieve an invidiual parameter value
*
* @param mixed $value
* @return mixed
*/
private function getIndividualValue($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);
}
$value = $idValues[key($idValues)];
}
return $value;
}
/**
* Checks whether the given managed entity exists in the database.
*
@@ -1341,13 +1533,78 @@ class BasicEntityPersister
public function exists($entity, array $extraConditions = array())
{
$criteria = $this->_class->getIdentifierValues($entity);
if ($extraConditions) {
$criteria = array_merge($criteria, $extraConditions);
}
$sql = 'SELECT 1 ' . $this->getLockTablesSql()
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
$alias = $this->_getSQLTableAlias($this->_class->name);
return (bool) $this->_conn->fetchColumn($sql, array_values($criteria));
$sql = 'SELECT 1 '
. $this->getLockTablesSql()
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) {
$sql .= ' AND ' . $filterSql;
}
list($params, $types) = $this->expandParameters($criteria);
return (bool) $this->_conn->fetchColumn($sql, $params);
}
/**
* Generates the appropriate join SQL for the given join column.
*
* @param array $joinColumns The join columns definition of an association.
* @return string LEFT JOIN if one of the columns is nullable, INNER JOIN otherwise.
*/
protected function getJoinSQLForJoinColumns($joinColumns)
{
// if one of the join columns is nullable, return left join
foreach ($joinColumns as $joinColumn) {
if (!isset($joinColumn['nullable']) || $joinColumn['nullable']) {
return 'LEFT JOIN';
}
}
return 'INNER JOIN';
}
/**
* Gets an SQL column alias for a column name.
*
* @param string $columnName
* @return string
*/
public function getSQLColumnAlias($columnName)
{
// 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.
return $this->_platform->getSQLResultCasing(
substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength())
);
}
/**
* Generates the filter SQL for a given entity and table alias.
*
* @param ClassMetadata $targetEntity Metadata of the target entity.
* @param string $targetTableAlias The table alias of the joined/selected table.
*
* @return string The SQL query part to add to a query.
*/
protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
{
$filterClauses = array();
foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) {
if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
$filterClauses[] = '(' . $filterExpr . ')';
}
}
$sql = implode(' AND ', $filterClauses);
return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL"
}
}
@@ -31,6 +31,7 @@ use Doctrine\ORM\ORMException,
*
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Alexander <iam.asm89@gmail.com>
* @since 2.0
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
*/
@@ -46,7 +47,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
/**
* Map of table to quoted table names.
*
*
* @var array
*/
private $_quotedTableMap = array();
@@ -56,11 +57,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
*/
protected function _getDiscriminatorColumnTableName()
{
if ($this->_class->name == $this->_class->rootEntityName) {
return $this->_class->table['name'];
} else {
return $this->_em->getClassMetadata($this->_class->rootEntityName)->table['name'];
}
$class = ($this->_class->name !== $this->_class->rootEntityName)
? $this->_em->getClassMetadata($this->_class->rootEntityName)
: $this->_class;
return $class->getTableName();
}
/**
@@ -73,8 +74,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
{
if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) {
$definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited'];
return $this->_em->getClassMetadata($definingClassName);
}
return $this->_class;
}
@@ -87,19 +90,24 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
*/
public function getOwningTable($fieldName)
{
if (!isset($this->_owningTableMap[$fieldName])) {
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
$cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']);
} else {
$cm = $this->_class;
}
$this->_owningTableMap[$fieldName] = $cm->table['name'];
$this->_quotedTableMap[$cm->table['name']] = $cm->getQuotedTableName($this->_platform);
if (isset($this->_owningTableMap[$fieldName])) {
return $this->_owningTableMap[$fieldName];
}
return $this->_owningTableMap[$fieldName];
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
$cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']);
} else {
$cm = $this->_class;
}
$tableName = $cm->getTableName();
$this->_owningTableMap[$fieldName] = $tableName;
$this->_quotedTableMap[$tableName] = $cm->getQuotedTableName($this->_platform);
return $tableName;
}
/**
@@ -116,20 +124,22 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$isPostInsertId = $idGen->isPostInsertGenerator();
// Prepare statement for the root table
$rootClass = $this->_class->name == $this->_class->rootEntityName ?
$this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName);
$rootClass = ($this->_class->name !== $this->_class->rootEntityName) ? $this->_em->getClassMetadata($this->_class->rootEntityName) : $this->_class;
$rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name);
$rootTableName = $rootClass->table['name'];
$rootTableName = $rootClass->getTableName();
$rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL());
// Prepare statements for sub tables.
$subTableStmts = array();
if ($rootClass !== $this->_class) {
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->_getInsertSQL());
$subTableStmts[$this->_class->getTableName()] = $this->_conn->prepare($this->_getInsertSQL());
}
foreach ($this->_class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$parentTableName = $parentClass->table['name'];
$parentTableName = $parentClass->getTableName();
if ($parentClass !== $rootClass) {
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL());
@@ -144,11 +154,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Execute insert on root table
$paramIndex = 1;
foreach ($insertData[$rootTableName] as $columnName => $value) {
$rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
}
$rootTableStmt->execute();
if ($isPostInsertId) {
@@ -163,22 +173,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
foreach ($subTableStmts as $tableName => $stmt) {
$data = isset($insertData[$tableName]) ? $insertData[$tableName] : array();
$paramIndex = 1;
foreach ((array) $id as $idName => $idVal) {
$type = isset($this->_columnTypes[$idName]) ? $this->_columnTypes[$idName] : Type::STRING;
$stmt->bindValue($paramIndex++, $idVal, $type);
}
foreach ($data as $columnName => $value) {
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
}
$stmt->execute();
}
}
$rootTableStmt->closeCursor();
foreach ($subTableStmts as $stmt) {
$stmt->closeCursor();
}
@@ -201,14 +212,16 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
if (($isVersioned = $this->_class->isVersioned) != false) {
$versionedClass = $this->_getVersionedClassMetadata();
$versionedTable = $versionedClass->table['name'];
$versionedTable = $versionedClass->getTableName();
}
if ($updateData) {
foreach ($updateData as $tableName => $data) {
$this->_updateTable($entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName);
$this->_updateTable(
$entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName
);
}
// Make sure the table with the version column is updated even if no columns on that
// table were affected.
if ($isVersioned && ! isset($updateData[$versionedTable])) {
@@ -233,14 +246,17 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.
if ($this->_platform->supportsForeignKeyConstraints()) {
$this->_conn->delete($this->_em->getClassMetadata($this->_class->rootEntityName)
->getQuotedTableName($this->_platform), $id);
$this->_conn->delete(
$this->_em->getClassMetadata($this->_class->rootEntityName)->getQuotedTableName($this->_platform), $id
);
} else {
// Delete from all tables individually, starting from this class' table up to the root table.
$this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id);
foreach ($this->_class->parentClasses as $parentClass) {
$this->_conn->delete($this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id);
$this->_conn->delete(
$this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id
);
}
}
}
@@ -255,29 +271,33 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Create the column list fragment only once
if ($this->_selectColumnListSql === null) {
$this->_rsm = new ResultSetMapping();
$this->_rsm->addEntityResult($this->_class->name, 'r');
// Add regular columns
$columnList = '';
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->_getSelectColumnSQL($fieldName,
isset($mapping['inherited']) ?
$this->_em->getClassMetadata($mapping['inherited']) :
$this->_class);
$columnList .= $this->_getSelectColumnSQL(
$fieldName,
isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class
);
}
// Add foreign key columns
foreach ($this->_class->associationMappings as $assoc2) {
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE) {
$tableAlias = isset($assoc2['inherited']) ?
$this->_getSQLTableAlias($assoc2['inherited'])
: $baseTableAlias;
$tableAlias = isset($assoc2['inherited']) ? $this->_getSQLTableAlias($assoc2['inherited']) : $baseTableAlias;
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
$columnList .= $this->getSelectJoinColumnSQL(
$tableAlias,
$srcColumn,
isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name
);
}
@@ -286,27 +306,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult).
$discrColumn = $this->_class->discriminatorColumn['name'];
if ($this->_class->rootEntityName == $this->_class->name) {
$columnList .= ", $baseTableAlias.$discrColumn";
} else {
$columnList .= ', ' . $this->_getSQLTableAlias($this->_class->rootEntityName)
. ".$discrColumn";
}
$tableAlias = ($this->_class->rootEntityName == $this->_class->name) ? $baseTableAlias : $this->_getSQLTableAlias($this->_class->rootEntityName);
$columnList .= ', ' . $tableAlias . '.' . $discrColumn;
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn);
}
// INNER JOIN parent tables
$joinSql = '';
foreach ($this->_class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$tableAlias = $this->_getSQLTableAlias($parentClassName);
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
if ($first) $first = false; else $joinSql .= ' AND ';
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
}
@@ -319,19 +339,20 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
if ($this->_selectColumnListSql === null) {
// Add subclass columns
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
continue;
}
if (isset($mapping['inherited'])) continue;
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
}
// Add join columns (foreign keys)
foreach ($subClass->associationMappings as $assoc2) {
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE
&& ! isset($assoc2['inherited'])) {
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE && ! isset($assoc2['inherited'])) {
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn,
$columnList .= $this->getSelectJoinColumnSQL(
$tableAlias,
$srcColumn,
isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name
);
}
@@ -342,17 +363,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Add LEFT JOIN
$joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
if ($first) $first = false; else $joinSql .= ' AND ';
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
}
$joinSql .= $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
$this->_getSelectManyToManyJoinSQL($assoc) : '';
$joinSql .= ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : '';
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
// If the current class in the root entity, add the filters
if ($filterSql = $this->generateFilterConditionSQL($this->_em->getClassMetadata($this->_class->rootEntityName), $this->_getSQLTableAlias($this->_class->rootEntityName))) {
if ($conditionSql) {
$conditionSql .= ' AND ';
}
$conditionSql .= $filterSql;
}
$orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy;
$orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $baseTableAlias) : '';
@@ -361,6 +392,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
}
$lockSql = '';
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$lockSql = ' ' . $this->_platform->getReadLockSql();
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
@@ -386,26 +418,29 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// INNER JOIN parent tables
$joinSql = '';
foreach ($this->_class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$tableAlias = $this->_getSQLTableAlias($parentClassName);
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
if ($first) $first = false; else $joinSql .= ' AND ';
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
}
return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql;
}
/* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
protected function _getSelectColumnListSQL()
{
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__.".");
}
/** {@inheritdoc} */
protected function _getInsertColumnList()
{
@@ -448,4 +483,5 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$value = $this->fetchVersionValue($this->_getVersionedClassMetadata(), $id);
$this->_class->setFieldValue($entity, $this->_class->versionField, $value);
}
}

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