Compare commits

...

315 Commits

Author SHA1 Message Date
Grégoire Paris 7d84a49980 Setup automated release workflow (#8301) 2020-10-10 19:11:26 +02:00
Claudio Zizza bb64fc953d Move website config to default branch (#8287)
Adds the website config to be compatible with the doctrine/doctrine-website#356 changes
2020-10-02 20:31:00 +02:00
orklah e0eb82a3b1 psalm fixes (#8286) 2020-09-30 22:00:38 +02:00
orklah 79cdcde9ec rename parameters to match parents (#8284) 2020-09-26 20:24:11 +02:00
orklah f4524a8bb0 Fix psalm errors and upgrade strictness (#8209)
* Fixes and improvements

* fix param type
2020-09-25 20:44:07 +02:00
Grégoire Paris d810ea4111 Use inline literals over escaping (#8279)
Escaping underscores does not work as expected.
See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/dql-custom-walkers.html#modify-the-output-walker-to-generate-vendor-specific-sql
2020-09-22 20:10:05 +02:00
Michael Voříšek 107ba93d79 Convert CRLF to LF in test file (#8276)
* Convert CRLF to LF in test file
* fix cs
2020-09-21 22:51:49 +02:00
Guillaume Simon 706670215d Fix OrderByItem parser to proceed with SimpleArithmetic expression before function (#8277)
There is parser bug for OrderByItem(), where a function is detected
before a SimpleArithmeticExpression while it should be the reverse:
simple arithmetic expressions can start with a function too, and thus
they should be matched first if present.

This fix enables the use of expressions in sorting and with window
functions.
2020-09-20 18:56:57 +02:00
Yohann Durand ab2b4987b3 Improve formatting (#8028) 2020-09-08 20:56:51 +02:00
Thomas Landauer 717ef9106c Update events.rst (#8257)
* Update events.rst

Improved code formatting

* Update docs/en/reference/events.rst

I was wondering myself what the `#` was about ;-)

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

* Update events.rst

See https://github.com/doctrine/orm/pull/8257#discussion_r482305774

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-09-03 22:44:28 +02:00
Christoph Ziegenberg ccae8f7176 Fix for bug #8229 (id column from parent class renamed in child class) (#8234)
This fixes problems with id columns defined in the parent class but renamed in the child class using an attribute override. Before this change always the child column name was used (which was not present in the parent class), now the correct column names are used for the parent table when creating inserts, joins and deletions for it.

Co-authored-by: Crossjoin <crossjoin@users.noreply.github.com>
2020-08-29 13:25:18 +02:00
Grégoire Paris da18985aca Stop using the DBAL extension of PHPBench (#8252)
It has been removed, and the default XML storage driver is supposed to
be fine for our purposes.
2020-08-29 12:28:40 +02:00
Simon Podlipsky 1e2ed07731 Use consistent formatting in command line (#8238) 2020-08-12 08:38:00 +02:00
Grégoire Paris 424241f29c Use more accurate terminology (#8236)
I think this was a mistake when writing this documentation, and that the
original author meant to use attribute here, columns do not have
columns, they have attributes.
2020-08-09 22:48:52 +02:00
Grégoire Paris 8230afcde9 Fetch deeper
This is needed to preserve parent information and be able to find the
merge base with the head branch. The assumption here is that the common
ancestor can be found among the 10 parent commits.
2020-08-07 22:11:21 +02:00
Kirill Matasov 7cffba8743 Fix annotation in Expr 2020-08-07 22:11:21 +02:00
Benjamin Cremer 7e5fe79349 Change preferred cache driver for metadata and query caches (#8223)
See: https://twitter.com/lcobucci/status/1289087725694484481
2020-08-03 21:40:52 +02:00
njutn95 efd25484f4 Update aggregate-fields.rst (#8215)
Minor typo fix
2020-07-20 21:19:16 +02:00
Andreas Möller 271f3480c8 Fix: Typo (#8213) 2020-07-15 22:46:25 +02:00
orklah aab589b596 add/fix more types (checked by psalm) (#8199)
* add/fix more psalm types

* remove inexistant SimpleEntityExpression

* Declare template implements for TreeWalkerChainIterator
2020-07-10 22:08:13 +02:00
orklah 190218b267 Change list() syntax to array destructuring (short list syntax) (#8204) 2020-07-07 22:02:34 +02:00
Benjamin Eberlei 181114f2c7 [GH-8106] Move test into existing QueryTest testcase to reduce surface. 2020-07-05 21:51:35 +02:00
tom93 3689b76a86 Fix QueryBuilder::getParameter() on parameter names with colons (#8107)
* Fix type errors

(partially cherry picked from commit 17e7c2a42e)

* Fix QueryBuilder::getParameter() on parameter names with colons

Fixes #8106.

Co-authored-by: Michael Moravec <mail@majkl578.cz>
2020-07-05 21:46:48 +02:00
Igor Pellegrini 75fe18ea5f Add alert to "avoid persisting detached entities" (#8109)
The alert is hidden into the code of ``EntityManager``,
while it's useful to be mentioned in the documentation.
2020-07-05 20:24:08 +02:00
Grégoire Paris 6c73a6b720 Infer return type information with Psalter (#8150)
These changes are a subset of changes done with vendor/bin/psalm --alter
--issues=LessSpecificReturnType
--allow-backwards-incompatible-changes=false
2020-07-05 20:15:39 +02:00
Benjamin Eberlei 775d91c2a3 [GH-8122] Move test from AbstractMappingDriverTest to ClassMetadataFactoryTest case 2020-07-05 20:11:01 +02:00
Gildas Quéméner 64c3f68734 Prohibits class typo in the discriminator map (#8122)
* Prevents incorrect table aliases to be generated

When a defined subclass has a case typo, the query builder will be lost
and will generate exotic table alias. This commit fixes the issue at the
root by prohibiting case typo in discriminator map.

See https://github.com/doctrine/orm/pull/8112 for the consequence of
such typo.

* Controls growing rate of the abstract test class

* Fixes incorrect test case

The Cube class must be autoloaded with the correct case, otherwise
composer autoloader will complain.

* Removes non architecture compliant code

See https://github.com/doctrine/orm/pull/8122/files#r423952247

* Ensures discriminator map is case sensitive
2020-07-05 19:48:38 +02:00
Mohamed Ettaki Talbi 2a2a0b2980 Remove unwanted period (#8198) 2020-07-02 08:36:18 +02:00
vladyslavstartsev a438e90046 add dev files to .gitattribute (#8190)
those files probably are not used by end user of the lib
2020-06-19 13:48:45 +02:00
Nicolas Grekas 6a670d7d6d Allow using on PHP 7.1 with Composer 2 (#8184) 2020-06-18 23:05:13 +02:00
Grégoire Paris 765521d257 Use CodeCov instead of Scrutinizer (#8187)
* Document current branch status in the README

* Use CodeCov instead of Scrutinizer
2020-06-17 22:47:25 +02:00
Grégoire Paris 5ced62bf83 Run benchmark on PHP 7.4 (#8186)
phpbench recently dropped compatibilty with PHP 7.1
When this job was introduced, 7.1 was the latest version of PHP we
supported, so it makes sense to bump to 7.4 now.
See https://github.com/phpbench/phpbench/releases/tag/0.17.0
See e07c90df44
2020-06-17 22:06:42 +02:00
Alexander Berl 93867f8d77 TASK: Replace "Blacklist" example with "Banlist" (#8174) 2020-06-08 23:06:53 +02:00
Grégoire Paris d95e03ba66 Allow doctrine/common 3 and doctrine/persistence 2 (#8158) 2020-05-26 18:03:49 +02:00
Robert Basic 825ceb6b7a Fix inline code example (#8153)
* Fix inline code example

* Remove extra backslash
2020-05-22 22:45:24 +02:00
orklah de2e2a1d74 Add psalm types (#7989) 2020-05-18 21:48:28 +02:00
Grégoire Paris 6780a963f7 Migrate git-phpcs to Github actions (#8146) 2020-05-16 14:01:10 +02:00
Benjamin Eberlei 4d172e2591 Revert changes to embeddable mapping in 2.7 (#8138)
* Revert "Fix inherited embeddables and nesting after AnnotationDriver change #8006 (#8036)"

This reverts commit a9b6b72017.

* Revert "Make Embeddable not transient"

This reverts commit 58677c29b4.

* Housekeeping: CS fixes
2020-05-12 20:10:26 +02:00
Grégoire Paris 21a98234d0 Static analysis with Psalm (#8116)
* Remove useless ternaries

If these expressions are truish inside the condition, they will still be
truish inside the if.

* Describe properties more accurately

These are not objects, they are strings holding class names for classes
that implement TreeWalker.

* Remove duplicate key

Comparison::IS and Comparison::EQ are the same. I chose to remove IS
because it does not seem to exist anymore on master

* Remove unwanted . before = operator

This worked, but makes no sense.

* Setup static analysis with Psalm

* Move PHPStan to Github actions
2020-05-11 23:06:46 +02:00
Grégoire Paris 8a9954e46c Address deprecations from persistence (#7953)
A backwards-compatibility layer has been added to persistence to help
consumers move to the new namespacing. It is based on class aliases,
which means the type declaration changes should not be a BC-break: types
are the same.
See https://github.com/doctrine/persistence/pull/71

This means:
- using the new namespaces
- adding autoload calls for new types to types that may be extended and
use persistence types in type declarations of non-constructor methods,
so that signature compatibility is recognized by old versions of php.
More details on this at
https://dev.to/greg0ire/how-to-deprecate-a-type-in-php-48cf
2020-05-07 08:35:39 +02:00
Grzesiek 527fff53cc removed repository class from metadata (#8125)
The annotation is required only in the next chapter of the tutorial, specifically the "Entity Repositories"
2020-05-03 21:58:20 +02:00
Maks Rafalko 70fb1ecd78 Warn users about performance issues with DateTime objects in setParameter() (#8114) 2020-04-25 22:16:17 +02:00
Jeroen van den Heuvel 73ec483e9d Convert PHP to SQL for new object expression (#8062) 2020-04-16 23:01:43 +02:00
Mathieu 8d67eec812 Fix JoinColumn documentation (#7966) 2020-03-30 21:33:13 +02:00
Vincent Langlet a418cf6418 Remove TODO (#8078) 2020-03-30 20:06:04 +02:00
Arne 6138afdca9 [Docs] Make clear that calling remove() detaches the object (#8081)
I changed a relationship from eager to lazy loading which broker the behaviour of my application in regards to object removal. It was not clear for me that removing an object detaches it and subsequent calls like contains() in a OneToMany relationship with the object scheduled for removal will return false afterwards.
2020-03-27 19:42:39 +01:00
Vincent Langlet dafe298ce5 Fix phpdoc (#8074) 2020-03-19 07:41:02 +01:00
Matthias Pigulla 58b8130ea1 Fix regression in 2.7.1 when mysqli is used with discriminator column that is not a string (#8055)
* Add a test case showing the regression

* Cast the discriminator value to string

* Fix CS
2020-03-16 11:19:12 +01:00
Benjamin Eberlei a705f526fb [GH-7633] disallow cache partial objects (#8050)
* [GH-7633] Bugfix: Partial queries were stored in 2LC.

There was a check in DefaultQueryCache that prevented partial queries,
because they are not supported. However the checked hint
Query::HINT_FORCE_PARTIAL_LOAD is optional, so cant be used to prevent
caching partial DQL queries.

Introduce a new hint that the SqlWalker sets on detecing a PARTIAL
query and throw an exception in the DefaultQueryCache if thats found.

* Housekeeping: CS

* [GH-7633] HINT_FORCE_PARTIAL_LOAD still needs to be checked.

* Housekeeping: Fix CS
2020-03-15 01:11:34 +01:00
Maciej Malarz a9b6b72017 Fix inherited embeddables and nesting after AnnotationDriver change #8006 (#8036)
* Add test case

* Treat parent embeddables as mapped superclasses

* [GH-8031] Bugfix: Get working again on nested embeddables in inherited embeddables.

* Housekeeping: CS

* Update note on limitations

* [GH-8031] Verify assocations still do not work with Embeddables.

* Housekeeping: CS

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2020-03-15 01:00:58 +01:00
Jorrit Schippers cd905fff77 Fix documentation of default generated value behavior (#8068) 2020-03-13 20:40:31 +01:00
Andreas Möller eb700405be Fix: Use neutral pronouns (#8059) 2020-03-06 16:08:53 +01:00
Rosemary Orchard 9273057649 Annotations override naming strategy (#8041)
Add a note/warning that annotations override the naming strategy.
2020-03-01 14:01:26 +01:00
Grégoire Paris e04a79526e Merge pull request #7230 from holtkamp/patch-2
Mention that lifecycle callbacks do not support Embeddables
2020-02-17 23:00:44 +01:00
Menno Holtkamp d157a6cbeb Mention that lifecycle callbacks do not support Embeddables
As discussed in https://github.com/doctrine/doctrine2/issues/6855
2020-02-17 22:25:00 +01:00
Benjamin Eberlei ca57222010 Merge pull request #8023 from peterkeatingie/query-cache-fix
Put into cache using root entity name
2020-02-16 10:50:24 +01:00
Peter Keating 9bb2bf0cce Put into cache using root entity name 2020-02-15 15:53:47 +00:00
Benjamin Eberlei 445796af0e Travis: Use 7.4 instead of 7.4snapshot 2020-02-15 15:35:56 +01:00
Benjamin Eberlei ab93285284 Remove nightly builds from .travis.yml 2020-02-15 15:34:36 +01:00
Benjamin Eberlei a692670469 Merge pull request #8006 from doctrine/malarzm-patch-1
Make Embeddable not transient
2020-02-13 21:31:02 +01:00
Maciej Malarz 58677c29b4 Make Embeddable not transient 2020-02-13 21:05:52 +01:00
Benjamin Eberlei 9a0fcb5a86 Merge pull request #7940 from doctrine/GH-7864-ExtraLazyRemoveElement
[GH-7864] Bugfix in PersistentCollection::removeElement for EXTRA_LAZY.
2020-02-12 23:42:06 +01:00
Benjamin Eberlei 8104c65d6c Merge pull request #7987 from beberlei/GH-7982-NoSqlExecutor
[GH-7982] no sql executor leads to parse error
2020-02-12 23:37:39 +01:00
Benjamin Eberlei a64d254d07 [GH-7982] Bugfix: Passing string|null DQL to Lexer(string $input) leads to downstream notice. 2020-02-12 23:23:12 +01:00
Benjamin Eberlei fdad48278b Merge pull request #7991 from greg0ire/7.4-sa
Try running phpstan on php 7.4
2020-01-17 00:06:40 +01:00
Benjamin Eberlei fc94127d7f Make ocramius/package-versions 1.2 the lowest version for phpstan 2020-01-16 23:51:17 +01:00
Grégoire Paris dea3e5df44 Try running phpstan on php 7.4
It might be easier to find packages compatible with both our locked deps
and phpstan with that version of php.
2020-01-16 23:49:15 +01:00
Benjamin Eberlei 5d7d3e99a0 Downgrade ocramius/package-versions to lowest in composer.lock to support all PHP versions. 2020-01-16 23:18:00 +01:00
Benjamin Eberlei 3bc1096fd0 [GH-7982] Default Query state to dirty to fix execution of empty query. 2020-01-15 23:30:59 +01:00
Benjamin Eberlei a2f01f7ccc Allow everything from ocramius/package-versions ^1.0. 2020-01-15 22:56:08 +01:00
Benjamin Eberlei 401db453a2 Merge pull request #7974 from beberlei/gh-7505
[GH-7505] Bug in SimpleObjectHydrator when using inheritance with same field
2020-01-15 22:02:25 +01:00
Benjamin Eberlei 6e59ec8f16 [GH-7505] Fix cs 2020-01-15 21:52:11 +01:00
Benjamin Eberlei 87e491465a Add @group 2020-01-15 21:13:25 +01:00
Luís Cobucci 8b588eceb2 Merge pull request #7973 from DocFX/patch-1
Just a micro grammar update.
2020-01-14 11:26:21 +01:00
Benjamin Eberlei edce36598f Adjust tests back for 2.x. 2020-01-09 00:41:47 +01:00
Woody Gilk 20c46035d1 [Docs] Prefer PhpFileCache for caching and remove APC/XCache. 2020-01-08 19:36:08 +01:00
William Pinaud 324aacfb54 Just a micro grammar update. 2020-01-08 18:52:11 +01:00
Benjamin Eberlei 1edfcabead Merge pull request #7894 from TomckySan/convert-default-value-to-boolean
Fix boolean properties default value when generating entities.
2020-01-05 16:11:33 +01:00
Luís Cobucci 2785cde792 Merge pull request #7957 from lcobucci/fix-version-information
Fix version information
2019-12-17 19:19:05 +01:00
Luís Cobucci d67e3e8b1b Rely on ocramius/package-versions to render the version
Since `Doctrine\ORM\Version` is now deprecated it shall not be updated
on future releases.

This ensures that our CLI tool will present the correct version number.
2019-12-17 15:47:55 +01:00
Luís Cobucci d629c4e487 Remove build.xml and related files
We aren't using ant/phing to handle the releases any more.
2019-12-17 01:03:34 +01:00
Luís Cobucci 4a4226213f Merge pull request #7875 from nicolas-grekas/schema-tool
Whilelist existing assets we know about from metadata in SchemaTool::getUpdateSchemaSql()
2019-12-16 23:59:31 +01:00
Andreas Braun 0ce1440884 Add upgrade note about schema_filter change 2019-12-16 23:45:49 +01:00
Laurent VOULLEMIER 9aa28b4e33 Test asset whitelisting on SchemaTool#getUpdateSchemasSql() 2019-12-16 23:45:49 +01:00
Nicolas Grekas 5c2b6870bf Whitelist existing assets we know about from metadata in SchemaTool::getUpdateSchemaSql() 2019-12-16 23:22:50 +01:00
Luís Cobucci 4389b2c188 Merge pull request #7956 from lcobucci/fix-test-suite
Ignore Doctrine\Common\Persistence\ObjectManagerDecorator deprecation
2019-12-16 21:49:25 +01:00
Luís Cobucci e481d9880b Ignore Doctrine\Common\Persistence\ObjectManagerDecorator deprecation
Since applying the fixes requires bumping up the dependency, which isn't
done in a patch release.

This should be removed in v2.8.0.
2019-12-16 21:22:28 +01:00
Luís Cobucci 85528f28e2 Fix CS errors 2019-12-16 21:22:23 +01:00
Luís Cobucci 5873242fb5 Merge pull request #7937 from doctrine/GH-7930-SqliteForeignKeys
Revert SchemaTool change to check for foreign key support
2019-12-16 10:45:07 +01:00
Luís Cobucci c9e41d0aa7 Merge pull request #7934 from BenMorel/php74
Fix Trying to access array offset on value of type null
2019-12-09 21:32:58 +01:00
Benjamin Morel f37c12834d Fix Trying to access array offset on value of type null 2019-12-09 21:24:29 +01:00
Benjamin Eberlei 041404e8b3 [GH-7864] Revert removeElement EXTRA_LAZY support. 2019-12-07 00:03:09 +01:00
Benjamin Eberlei bfc68b3aba Add warning about removeElement on extra lazy 2019-12-03 20:34:44 +01:00
Benjamin Eberlei 1e628370c4 [GH-7864] Address review comments. 2019-12-03 19:35:49 +01:00
Benjamin Eberlei ae2b9b1921 Housekeeping: phpcbf to fix issues. 2019-12-01 21:11:09 +01:00
Benjamin Eberlei 419df77a09 [GH-7864] ExtraLazyCollectionTest is not cacahble and should not fail SLC suite. 2019-12-01 20:28:30 +01:00
Benjamin Eberlei d6f6b2e97c [GH-7864] Remove tests that checked invalid behavior. 2019-12-01 19:47:58 +01:00
Benjamin Eberlei 75d5adf599 [GH-7864] Bugfix in PersistentCollection::removeElement for EXTRA_LAZY. 2019-12-01 19:27:45 +01:00
Benjamin Eberlei cfd6fadf9c Revert "#7841 SchemaTool generates extra diff for platforms without FK support"
This reverts commit 3707c39124.
2019-12-01 11:23:45 +01:00
Tomoka Baba 2bf7916c52 Fix to pass code quality check. 2019-11-20 17:03:34 +09:00
Tomoka Baba 253fd10cc0 Modified test to use assertTrue. 2019-11-20 17:02:25 +09:00
Tomoka Baba 2c956d55f2 Fix to pass code quality check. 2019-11-20 17:02:25 +09:00
Tomoka Baba 3db992e953 Add test code. 2019-11-20 17:01:52 +09:00
Tomoka Baba 6fc9b3ab16 Fix to pass code quality check. 2019-11-20 17:01:52 +09:00
Tomoka Baba 2d833a5e86 Fix boolean properties default value when generating entities. 2019-11-20 17:01:19 +09:00
Luís Cobucci a416a9a8b2 Bump up version 2019-11-19 09:43:57 +01:00
Luís Cobucci 4d763ca4c9 Bump up version 2019-11-19 09:38:05 +01:00
Luís Cobucci 398d74deaa Merge pull request #7911 from lcobucci/be-more-explicit-on-deprecation-messages
Be explicit about which Doctrine package in message
2019-11-19 09:36:14 +01:00
Luís Cobucci 3314322929 Be explicit about which Doctrine package in message
Avoiding possible confusion while reading the deprecation messages.
2019-11-19 09:03:36 +01:00
Luís Cobucci ce93817bf7 Merge pull request #7909 from lcobucci/add-deprecation-messages
Add deprecation messages
2019-11-19 08:21:44 +01:00
Luís Cobucci 50992eafa2 Deprecated the usage of number unaware underscore naming strategy 2019-11-19 02:15:11 +01:00
Luís Cobucci 9ccb8837e7 Add deprecation message for EM#clear($entityName) 2019-11-19 01:34:50 +01:00
Luís Cobucci d959744c0a Merge pull request #7079 from mairo744/hotfix/sqlite-join-table-name
fix getJoinTableName for sqlite with schema attribute
2019-11-18 23:37:33 +01:00
mairo744 0264ba1759 Fix creation of join table names with schemas in SQLite
Join table name doesnt depending on the platform.
Table name was "schema.table" instead of "schema__table".

(cherry picked from commit 4878cd3f4ef30ffc6047c18e0f7b16aafeabc3b4)
2019-11-18 23:25:28 +01:00
Luís Cobucci 8332fa1855 Merge remote-tracking branch 'upstream/2.6' into 2.7 2019-11-18 23:06:28 +01:00
Luís Cobucci 4fae126459 Bump up version 2019-11-18 23:05:16 +01:00
Luís Cobucci 2d9b935183 Bump up version 2019-11-18 23:01:21 +01:00
Luís Cobucci 4804f602f8 Merge pull request #7908 from lcobucci/fix-bc-break-on-naming-strategy
Fix BC-break on underscore naming strategy
2019-11-18 22:57:27 +01:00
Luís Cobucci 3d17290eb5 Fix BC-break on underscore naming strategy
We broke our BC promises on the last patch release by changing how the
underscore naming strategy parses values with numbers.

This commit makes it possible to configure whether or not to make the
underscore naming strategy aware of numbers, keeping the old
configuration as default value.
2019-11-18 22:38:14 +01:00
Luís Cobucci 8420d24f90 Merge remote-tracking branch 'upstream/2.6' into 2.7 2019-11-18 19:59:58 +01:00
Luís Cobucci 52f2b37921 Bump up version 2019-11-18 12:17:41 +01:00
Luís Cobucci 16751d210f Bump up version 2019-11-18 12:06:51 +01:00
Luís Cobucci 686f508576 Merge pull request #7905 from lcobucci/7890-paginator-objecti
[Paginator] Fix type conversion during hydration of pagination limit subquery
2019-11-18 10:50:54 +01:00
Luís Cobucci 00ef1eba90 Add paginator query hint to force type conversion
We're keeping a BC layer in the hydrator, which prevents type conversion
in scalar results.

This makes bypasses such layer in order to always convert the identifier
types when limiting the result set during a pagination.

The main goal here is to keep the conversion DB->PHP inside of the
hydrator components.
2019-11-18 10:27:10 +01:00
Gabriel Ostrolucký 3843eee5cb [Paginator] Add test case for regression with custom id
Co-authored-by: Alexei Korolev <alexei.korolev@gmail.com>
2019-11-18 10:27:10 +01:00
Luís Cobucci f576e6c41f Merge pull request #7904 from greg0ire/validate-composer-json
Make sure composer files are valid
2019-11-16 11:47:02 +01:00
Grégoire Paris c79d2e0dc2 Make sure composer files are valid
The composer.lock is put under version control and it often happens to
be out of sync with the composer.json, which could lead to
hard-to-understand issues.
Using the --strict option here because we might as well aim for a
perfectly valid composer.json
2019-11-16 10:59:39 +01:00
Grégoire Paris 33b8d020a7 Synchronize lock file and json manifest 2019-11-16 10:59:39 +01:00
Luís Cobucci 1b2daac25d Merge pull request #7710 from rtek/pretty-tool-describe
Prettified arrays in tool command orm:mapping:describe
2019-11-16 02:15:31 +01:00
Luís Cobucci 977985f756 Merge pull request #7701 from someniatko/deprecate-use-result-cache
Split and deprecate AbstractQuery#useResultCache()
2019-11-16 02:12:29 +01:00
rtek 0c36f87935 Prettify arrays in orm:mapping:describe command
This will prevent excessive column width and wrapping in the output which uses Symfony\Component\Console\Style\SymfonyStyle::table().
2019-11-16 02:03:03 +01:00
someniatko e8f265d480 Make ResultCacheTest tests slightly more logical 2019-11-16 01:59:57 +01:00
Illia Somov 7bcbad076d Split and deprecate AbstractQuery#useResultCache() 2019-11-16 01:59:57 +01:00
Luís Cobucci 57496e32fd Add minor BC-break notes on output walkers in paginator
As explained in
https://github.com/doctrine/orm/pull/7863#issuecomment-554578313.
2019-11-16 01:48:37 +01:00
Luís Cobucci 797bfc53c4 Fix deprecation messages version 2019-11-16 01:32:15 +01:00
Luís Cobucci 8c47dcb6fc Merge pull request #7863 from Seb33300/skip-limit-subquery
Paginator: Skip limit subquery if not required
2019-11-16 01:21:43 +01:00
Sébastien ALFAIATE 6347190886 Skip limit subquery if not required 2019-11-16 01:03:22 +01:00
Luís Cobucci 9162f3519d Merge pull request #7900 from doctrine/2.6.x-merge-up-into-2.7
Merge up 2.6 to 2.7
2019-11-16 00:27:50 +01:00
Grégoire Paris fc9314d9f5 Merge remote-tracking branch 'origin/2.7' into 7900--2.6.x-merge-up-into-2.7 2019-11-15 23:50:05 +01:00
Luís Cobucci 26806d08eb Require more updated doctrine packages 2019-11-15 23:46:22 +01:00
Luís Cobucci 6a827d5b61 Merge pull request #7861 from ferrastas/bug_removing_collection
Delete statements will not be created using `clear`
2019-11-15 22:58:31 +01:00
Gabriel Ostrolucký 7d77984306 Restore ability to clear deferred explicit tracked collections
This was regression from #7862 which tried to respect tracking config
when clearing collections, but this logic can happen in UOW only,
PersistentCollection::clear is triggered too early to know what
is (going to be) persisted.

Fixes #7862
2019-11-15 22:49:06 +01:00
Ferran Vidal ec93014713 Delete statements will not be created using clear. 2019-11-15 22:43:53 +01:00
Luís Cobucci c83094bde0 Merge pull request #7684 from rharink/2.6
only replace '_id' at end of columnName
2019-11-15 16:50:16 +01:00
Robert den Harink 982d1519db only replace '_id' at end of columnName 2019-11-15 16:36:48 +01:00
Marco Pivetta f7c04ae537 Merge pull request #7901 from lcobucci/add-deprecation-notices
Add deprecation warnings for 2.7.x
2019-11-15 16:15:31 +01:00
Michael Moravec f9a4258ded Upgrading notes for 2.7 2019-11-15 14:43:33 +01:00
Michael Moravec eb9f11bf96 Added deprecation warnings for 2.x 2019-11-15 14:43:15 +01:00
Luís Cobucci 2b8cb9de79 Add basic tool to verify deprecation messages 2019-11-15 14:42:48 +01:00
Luís Cobucci 570abb5bad Fix PHP warnings in test suite 2019-11-15 14:42:47 +01:00
Luís Cobucci 855244fd10 Merge pull request #7865 from Ocramius/fix/#7837-paginate-with-custom-identifier-types-even-with-cached-dql-parsing
#7837 paginate with custom identifier types even with enabled DQL query cache
2019-11-15 11:08:22 +01:00
Guilherme Blanco c62977412c Merge pull request #7869 from BenMorel/patch-4
UnitOfWork::clear() misses $eagerLoadingEntities
2019-11-15 00:27:08 -05:00
Gabriel Ostrolucký 98e557b68e Improve assertion failure message for testWillFindSongsInPaginatorEvenWithCachedQueryParsing 2019-11-14 23:37:13 +01:00
Mickaël RAYBAUD-ROIG 3a32c00dcf Add a failing test for issue #7505 2019-11-14 23:28:42 +01:00
Gabriel Ostrolucký 1dde2c9e8e Add test case verifying eager loads are clear
Otherwise, getClassMetadata would be triggered more times
2019-11-14 22:17:06 +01:00
Marco Pivetta adfd010a78 Merge pull request #7889 from ajgarlag/hotfix/fix-tests-with-dbal-2.10
Use quoted collation declaration when available.
2019-11-05 15:52:18 +01:00
Antonio J. García Lagar 1bc4e1f594 Use quoted collation declaration when available. 2019-11-05 14:58:24 +01:00
Marco Pivetta 21680df9bd Merge pull request #7884 from rogeriolino/patch-1
[Documentation] Advanced field value... - missing entity alias
2019-11-05 01:23:52 +01:00
Rogério Alencar Lino Filho 19aa3c125c missing entity alias 2019-10-31 18:20:58 -03:00
Marco Pivetta e9e012a037 Merge pull request #7880 from kuraobi/update-doc-dql-qb
Update documentation to recommend DQL over QueryBuilder when possible
2019-10-29 19:04:03 +01:00
Mathieu Lemoine d1db0655ac Update documentation to recommend DQL over QueryBuilder when possible 2019-10-29 16:26:17 +01:00
Luís Cobucci 2d643e6b7b Merge pull request #7876 from nicolas-grekas/sf5-cmd
Fix compat of commands with Symfony 5
2019-10-23 16:12:18 +02:00
Nicolas Grekas 4d6b1f3e63 Fix compat of commands with Symfony 5 2019-10-23 16:00:19 +02:00
Jonathan H. Wage d9c30e34c4 Merge pull request #7723 from nicolas-grekas/sf5
Allow Symfony 5.0
2019-10-23 15:57:25 +02:00
Nicolas Grekas 90c1ee0bd0 Allow Symfony 5.0 2019-10-23 15:57:25 +02:00
Marco Pivetta cfcca3a63c Merge pull request #7600 from Majkl578/travis-php7.4-2.7
[2.7] CI: Test against PHP 7.4snapshot instead of nightly (8.0)
2019-10-23 15:57:24 +02:00
Michael Moravec af0949adab Merge pull request #7382 from Majkl578/homepage-2.7
Update homepage
2019-10-23 15:57:24 +02:00
Michael Moravec cdb652ad87 CI: Test against PHP 7.4snapshot instead of nightly (8.0) 2019-10-23 15:57:24 +02:00
Claudio Zizza 4fb1ebfc10 Create 2.7 upgrade headline for deprecation changes 2019-10-23 15:57:24 +02:00
Michael Moravec 46c1b57560 Update homepage 2019-10-23 15:57:24 +02:00
Claudio Zizza fdbbf7edd1 Add deprecation of EntityManagerInterface::copy() to upgrade information 2019-10-23 15:57:23 +02:00
Claudio Zizza 2fed8204c1 Set copy-method as deprecated 2019-10-23 15:57:23 +02:00
Michael Moravec 76f03b5db0 Bump version to 2.7-dev 2019-10-23 15:57:19 +02:00
Guilherme Blanco 9fef4e86e4 Merge pull request #7871 from BenMorel/2.6
AbstractQuery::getSingleScalarResult() throws exception when no result
2019-10-18 10:37:53 -04:00
Benjamin Morel 4781dc03e9 AbstractQuery::getSingleScalarResult() throws exception when no result 2019-10-16 20:41:00 +02:00
Benjamin Morel cc5f84ac22 UnitOfWork::clear() misses $eagerLoadingEntities 2019-10-16 10:11:55 +02:00
Marco Pivetta 023e94661a #7837 force expiry of query cache when WhereInWalker is being used
In order to figure out the paginated query identifier type, we would
have to parse the DQL query into an AST+SQL anyway, so we'd have
to re-parse it manually: instead of doing that, we can force the
`WhereInWalker` to be reached at all times by forcing the
`$whereInQuery` to use no query cache.

While it is a sad performance regression, it is also not a
noticeable one, since we'll be performing an `O(1)` operation
around an I/O one (query execution, in this case).
2019-10-10 18:23:31 +02:00
Marco Pivetta b59fc23f86 #7837 reproduced issue: DQL caching prevents WhereInWalker run
Since `WhereInWalker` does not run, query parameters are not translated
from their in-memory type to the expected SQL type when the paginator
is run again with the same DQL string. This is an architectural
issue, since (for the sake of simplicity) we moved parameter
translation into the SQL walker, we didn't consider that SQL
walkers only act when no cache is in place. The translatio
needs to be moved into the paginator logic again.
2019-10-10 17:30:43 +02:00
Luís Cobucci d71dd5d94f Bump up version 2019-10-08 20:04:50 +02:00
Luís Cobucci 63513e9a05 Merge pull request #7856 from lcobucci/fix/underscore-strategy-dont-work-with-numbers
Fix underscore naming strategy behaviour with numbers
2019-10-08 12:06:24 +02:00
Luís Cobucci c802bc46a5 Format NamingStrategyTest according to our CS 2019-10-08 11:56:11 +02:00
Luís Cobucci 506bf0ee12 Allow numbers in property names on underscore naming strategy 2019-10-08 11:56:11 +02:00
Luís Cobucci a36809db72 Merge pull request #7851 from peter-gribanov/reflFieldValue2.6
Remove not used variable $reflFieldValue in ObjectHydrator
2019-10-04 07:50:26 +02:00
Peter Gribanov 5b00d7ba5e remove not used variable $reflFieldValue in ObjectHydrator 2019-10-03 11:14:24 +03:00
Luís Cobucci b22604352d Merge pull request #7849 from axi/patch-1
Mention SQL logger impact on batch processing
2019-10-02 14:14:48 +02:00
axi 00c6b1bc60 Update batch-processing.rst
Clarify note
2019-10-02 14:00:06 +02:00
Luís Cobucci 4b0d86ee92 Merge pull request #7842 from vpArth-php/gh-7841
#7841 SchemaTool generates extra diff for platforms without FK support
2019-10-02 10:50:42 +02:00
Alexander Deider 3707c39124 #7841 SchemaTool generates extra diff for platforms without FK support 2019-10-02 15:35:59 +07:00
Luís Cobucci fe72b00df2 Merge pull request #7850 from nlx-lars/nlx-lars/bugfix/7836-dont-merge-criteria
Don't merge PersistentCollection orderBy with criteria in matching()
2019-10-02 10:02:38 +02:00
Lars Lauger 79a7ecc92f Don't merge PersistentCollection orderBy with criteria in matching()
If no orderings are given to PersistentCollection::matching(), the
orderBy annotation will be used if present. If the criteria contains
orderings, those will be used without merging them with the orderBy.

See #7836
2019-10-02 09:23:38 +02:00
Luís Cobucci 16df8bfe0d Merge pull request #7298 from dunglas/patch-2
Add a missing type in Query::getFirstResult PHPDoc
2019-10-02 04:27:19 +02:00
Kévin Dunglas b37ceaa9f7 Add a missing type in Query::getFirstResult and Query::getDQL 2019-10-02 04:13:42 +02:00
Luís Cobucci c41fdbce8a Merge pull request #7727 from madand/patch-1
[doc] Finish incomplete definition of class UTCDateTimeType
2019-10-02 04:11:20 +02:00
Luís Cobucci 7526adc80a Merge pull request #7443 from naitsirch/fix/issue6793
Added doc about exception in Query#getOneOrNullResult()
2019-10-02 04:07:25 +02:00
Andriy Kmit 766eb693fb Finish incomplete definition of class UTCDateTimeType 2019-10-02 03:57:06 +02:00
Luís Cobucci f9e2ae3488 Merge pull request #7667 from jschaedl/patch-1
Fixes example One-To-One, Self-referencing
2019-10-02 03:56:01 +02:00
Luís Cobucci 6bf2ff5d10 Merge pull request #7671 from jschaedl/patch-4
Added missing "the"
2019-10-02 03:45:50 +02:00
Jan Schädlich 27fcc01d81 Fixes example One-To-One, Self-referencing 2019-10-02 03:37:23 +02:00
Jan Schädlich 3ac1f8e680 Added missing "the" 2019-10-02 03:36:06 +02:00
Luís Cobucci b63db53552 Merge pull request #7764 from guillaume-a/7763
#7763 escape quotes in field comments
2019-10-02 02:56:05 +02:00
Guillaume Aveline bed8186573 Fix comment quoting in the EntityGenerator
Fixes: https://github.com/doctrine/orm/issues/7763
2019-10-02 02:42:09 +02:00
Luís Cobucci f08ff83d0a Merge pull request #7768 from mickaelandrieu/patch-1
EntityManagerHelper can't accept an array of paths
2019-10-01 22:51:13 +02:00
axi 7c8c0906be Update batch-processing.rst
Looking for a way to improve one of our bulk update treatment, I went back to this page then found elsewhere that setting logger to null was a really effective way to improve time and memory consumption. Might be a right place to state it ? Don't know if my edit style is ok
2019-10-01 17:46:09 +02:00
Grégoire Paris 167cb44ea1 Merge pull request #7742 from bocharsky-bw/patch-1
Start i var from 1 instead of 0
2019-09-28 18:54:56 +02:00
Mickaël Andrieu 5d74bdb240 Remove misleading documentation
EntityManagerHelper does not have a second argument, see
https://github.com/doctrine/orm/blob/ca38249f6c71bc1d1c355822040a1788e3eeebd6/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php#L49
2019-09-28 12:32:09 +02:00
Luís Cobucci ca38249f6c Merge pull request #7838 from samnela/fix/name-classmetadata
Fix the name of ClassMetadata in documentation
2019-09-27 22:31:49 +02:00
Samuel NELA 6a74f373b9 Fix the name of ClassMetadata in documentation 2019-09-27 21:59:32 +02:00
Luís Cobucci b52ef5a100 Merge pull request #7322 from dennisenderink/fix/joinedsubclasspersister-pass-identifier-types-on-delete
JoinedSubclassPersister pass identifier types on delete
2019-09-20 16:30:26 +02:00
Luís Cobucci ef783f7049 Make use of the PersisterHelper to get field type
Removing the unnecessary code duplication.
2019-09-20 16:17:43 +02:00
Luís Cobucci 435d624d33 Centralise functional test classes
Which provides better isolation and makes things a bit more
understandable.
2019-09-20 16:17:43 +02:00
Dennis Enderink 53775fe086 Added correct return types to docblock 2019-09-20 16:17:43 +02:00
Dennis Enderink 59f1679fed Patched spacing 2019-09-20 16:17:43 +02:00
Dennis Enderink 390d081fca Created new DBAL type and updated/reverted tests; also clarified new method return type 2019-09-20 16:17:43 +02:00
Dennis Enderink 37d1d57900 Added unit tests 2019-09-20 16:17:42 +02:00
Dennis Enderink d7a537c941 Pass ClassMetadata object instead of string in parent classes loop 2019-09-20 16:17:42 +02:00
Dennis Enderink cfe73cd74f Separated class identifiers types retrieval in a separate method and implemented in JoinedSubclassPersister delete method 2019-09-20 15:40:03 +02:00
Luís Cobucci d0e1da8c51 Merge pull request #7490 from vladyslavstartsev/patch-2
Fix broken link
2019-09-20 15:32:13 +02:00
vladyslavstartsev 7fbe663ea0 Fix broken link
closing #7489
2019-09-20 15:31:12 +02:00
Luís Cobucci 409f2f5d82 Merge pull request #7672 from jschaedl/patch-5
Added cross-links to relevant documentation
2019-09-20 15:30:14 +02:00
Luís Cobucci 3d8b672771 Merge pull request #7610 from smtchahal/patch-1
Change APC to OPcache in improving-performance.rst
2019-09-20 15:29:07 +02:00
Jan Schädlich 17650a6100 Added cross-links to relevant documentation 2019-09-20 15:19:49 +02:00
Luís Cobucci 1588ca7e1f Merge pull request #7821 from Ocramius/bug/#7820-paginator-ignores-dbal-type-conversions-in-identifiers
Bug: #7820 paginator ignores dbal type conversions in identifiers
2019-09-20 15:13:58 +02:00
Marco Pivetta 0de17319d3 #7820 use PersisterHelper to figure out identifier types
This logic was pre-existing, but I forgot about it while writing
#7820, therefore it was re-implemented inside this unit of
code. Now we just use the `PersisterHelper`, which does all
the nice and shiny identifier type discovery operations we need.
2019-09-20 15:03:22 +02:00
Marco Pivetta 681ff32e76 #7820 documented PersisterHelper#getTypeOfField() array return type
Array values are `string`, and the array is a packed array.
2019-09-20 14:57:44 +02:00
Marco Pivetta caee6c8685 #7820 restricted return type of Doctrine\ORM\Mapping\ClassMetadataInfo#getTypeOfColumn()
This method will always return `string|null`, so we can safely
remove DBAL types from its possible return types.
2019-09-20 14:51:56 +02:00
Marco Pivetta c67a515cc2 As per discussion with @lcobucci, it is better to keep dragons where
there be dragons, and this change does indeed rewrite the previous
approach by moving the responsibility of type conversion on a query
object from the `Paginator` to the `WhereInWalker`, which already
has access to class metadata for the root of the selection (and can
reliably detect the root of the selection too)
2019-09-19 20:05:34 +02:00
Luís Cobucci 24892779f7 Merge pull request #7818 from SenseException/simple-annotation-docs
Add note into docs about not using SimpleAnnotationReader
2019-09-18 10:49:43 +02:00
Marco Pivetta 39d2113549 Fixed #7820 - convert identifiers for WHERE IN(?) queries before binding parameters
This patch introduces new internal API on the `ResultSetMapping` class, which is responsible
for finding the type of the single column identifier of a DQL query selection root.
2019-09-17 16:54:25 +02:00
Marco Pivetta 65522d9775 Failing test case for #7820 - paginator doesn't use custom ID types
When using a `Doctrine\ORM\Tools\Pagination\Paginator` to iterate over a query that has entities with a custom DBAL type used in the identifier, then `$id->__toString()` is used implicitly by PDO, instead of being converted by the `Doctrine\DBAL\Types` system.

In order to reproduce this, you must have identifiers implementing `#__toString()` (to allow the `UnitOfWork` to hash them) and other accessors that are used by the custom DBAL type during DB/PHP conversions. If `#__toString()` and the DBAL type conversions are asymmetric, then the paginator will fail to find records.

Tricky situation, but this very much affects `ramsey/uuid-doctrine` and anyone relying on the `uuid_binary`.
2019-09-17 11:37:50 +02:00
Claudio Zizza 50eecf698c Add note into docs about not using SimpleAnnotationReader 2019-09-15 22:50:46 +02:00
Luís Cobucci 20ab78e3c1 Merge pull request #7753 from SenseException/getting-started-annotation
Add ORM annotations in getting-started docs
2019-09-12 17:01:53 +02:00
Luís Cobucci 613ffe9bbd Backport documentation sidebar 2019-09-10 16:31:41 +02:00
Luís Cobucci 61ff45f98e Merge pull request #7785 from mlocati/php74-fixes
Fix "access array offset on value of type null" PHP 7.4 notices
2019-09-10 16:08:49 +02:00
Luís Cobucci a8aa475d09 Add PHP 7.4 to test matrix 2019-09-10 15:48:05 +02:00
Luís Cobucci a4215cfa59 Update locked dependencies 2019-09-10 15:48:04 +02:00
Luís Cobucci a4ac9a721f Upgrade PHPUnit to 7.5 2019-09-10 15:48:03 +02:00
Michele Locati 447183e235 Fix "access array offset on value of type null" PHP 7.4 notices 2019-09-10 15:47:57 +02:00
Luís Cobucci 642e543b4b Merge pull request #7778 from umpirsky/fix/issue-7266
Guard L2C regions against corrupted data
2019-08-14 18:07:58 +02:00
Luís Cobucci 80503c4837 Guard cache regions against corrupted data
For some bizarre reason the underlying cache drivers are returning
unexpected values, which are leaking to the cache objects and causing
them to error.

This makes our cache regions much more strict about the types that are
fetched from the cache provider, ensuring that no invalid information is
ever sent to the hydrators.
2019-08-14 17:42:56 +02:00
Luís Cobucci 3577064f8c Make closure static
To adhere to our coding standard.
2019-08-14 17:42:56 +02:00
Luís Cobucci b6663733c0 Add type assertion to be more strict about persister type 2019-08-14 17:42:56 +02:00
Luís Cobucci b9d6834213 Remove unnecessary function calls 2019-08-14 17:42:56 +02:00
Luís Cobucci eafc4c5a0c Remove unnecessary parentheses 2019-08-14 17:42:56 +02:00
Saša Stamenković ecf80b47a0 Call to a member function resolveAssociationEntries() on boolean
The following mistakes occur occasionally:

```
Call to a member function resolveAssociationEntries() on boolean {"detail":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function resolveAssociationEntries() on boolean at /www/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php:140)"}
```

On cache miss the parameter `$entityEntry` sometimes will be false. This fixes issue #7266.
2019-08-14 17:42:56 +02:00
Luís Cobucci 5499555862 Merge pull request #7791 from Steveb-p/fix-docs
Fix preFlush event documentation stating incorrectly that flush can be called safely
2019-08-14 14:03:13 +02:00
Paweł Niedzielski 70df74f65f Fix preFlush event documentation stating incorrectly that flush can be called safely
Original author: egonolieux
Supersedes #6858
2019-08-14 13:41:31 +02:00
Luís Cobucci 74415becce Merge pull request #7737 from Smartel1/smartel1/patch1
Fix MEMBER_OF comparison when using criteria in query builder
2019-08-14 10:07:11 +02:00
drews 3a56cf8ad9 Add MEMBER_OF comparison to queryExpressionVisitor 2019-08-14 09:47:20 +02:00
Luís Cobucci 6b7f53f0f3 Merge pull request #7766 from stephanschuler/respect-collection-ordering-in-selectable-matching
Respect collection orderBy meta when matching()

Fixes https://github.com/doctrine/orm/issues/7767
2019-08-13 23:42:32 +02:00
Stephan Schuler e51666e8be Fix PersistentCollection::matching() not respecting collection ordering
The ordering of a Criteria is prefered over the collections default
ordering.

The default collection ordering used as additional sorting attributes.
2019-08-13 23:34:54 +02:00
Luís Cobucci 6e56bcd75f Merge pull request #7750 from AlexSmerw/issue_7735_null_values_in_entities_cache_for_2.6
Fix incorrect return of null values in L2C
2019-08-12 01:28:20 +02:00
Luís Cobucci 48bfef1f7a Merge pull request #7761 from paxal/persistent_collection/deferred_explicit_2.6
Do not modify UOW on PersistentCollection::clear() when owner has DEFFERED_EXPLICIT change tracking policy
2019-08-12 01:21:21 +02:00
A.Kuterev e8f91434a7 Avoid reusing variable name
The same variable name is used below, and that causes a bug etc.
Fixes https://github.com/doctrine/orm/issues/7735
2019-08-12 01:18:48 +02:00
Luís Cobucci 7e26d82790 Merge pull request #7794 from lcobucci/fix-compatibility-with-dev-dependencies
Fix test compatibility with DBAL 2.10.x-dev
2019-08-12 00:00:45 +02:00
Luís Cobucci 869b70e4db Use Ubuntu Xenial for MySQL 5.7 build
Since July 21st 2019 it's no longer possible to install MySQL 5.7 in
Ubuntu Trusty.

More info: https://docs.travis-ci.com/user/database-setup/#mysql-57
2019-08-11 23:41:32 +02:00
Luís Cobucci 33904cb9c1 Fix test compatibility with DBAL 2.10.x-dev 2019-08-11 23:41:32 +02:00
Cyril PASCAL a42191eecf Add functional test for ArrayCollection::clear() bug 2019-07-19 16:21:12 +02:00
Cyril PASCAL 3fbf163d34 Do not modify UOW on PersistentCollection::clear() when owner has DEFFERED_EXPLICIT change tracking policy 2019-06-26 16:07:15 +02:00
naitsirch 1c45e1b744 Fixed grammatical mistake in doc
Co-Authored-By: Grégoire Paris <postmaster@greg0ire.fr>
2019-06-24 22:07:56 +02:00
Claudio Zizza c777aa62b6 Fix of ORM annotation in examples 2019-06-23 23:39:41 +02:00
Luís Cobucci 6296bd4e1d Merge pull request #7744 from noobshow/patch-1
Fixed a typo-error
2019-06-18 08:30:35 +02:00
Luís Cobucci 5a236c19f5 Merge pull request #7731 from greg0ire/try-mysql-addon
Replace custom install script with add-on
2019-06-17 23:33:04 +02:00
Olumide Samson 4f8a1f92a3 Fixed a typo-error
exploitet changed to exploited
2019-06-17 09:00:45 +01:00
Victor Bocharsky 5612790307 Start i var from 1 instead of 0
Because (0 % $batchSize) === 0 but we don't want to execute flush() and clear() on the first iteration.
2019-06-11 13:19:56 +03:00
Jonathan H. Wage 0b5be00374 Merge pull request #7732 from lchrusciel/patch-1
[Documentation] Missing comma fix
2019-06-04 11:11:46 -05:00
Łukasz Chruściel 145cc782ff [Documentation] Missing comma fix 2019-06-04 17:38:26 +02:00
Jonathan H. Wage 9712506be8 Merge pull request #7729 from JoppeDC/patch-1
Update DATE_ADD and DATE_SUB docs
2019-06-04 10:23:15 -05:00
Grégoire Paris bd9ead11c5 Replace custom install script with add-on
Following this documentation:
https://docs.travis-ci.com/user/database-setup/#mysql-57
found via https://stackoverflow.com/a/49542847/353612
2019-06-03 22:12:54 +02:00
Joppe de Cuyper a98ebf7344 Whitespace fixes 2019-06-03 20:21:19 +02:00
Joppe de Cuyper c721ab63ee Update DATE_ADD and DATE_SUB docs 2019-06-03 20:20:03 +02:00
Jonathan H. Wage 2820438afc Merge pull request #7694 from darrylhein/patch-1
Change variable name in docs
2019-04-29 11:00:10 -05:00
Darryl Hein 180cfcc3e3 change variable name
to make it consistent throughout document
2019-04-28 21:07:22 -06:00
Marco Pivetta 52d806a34a Merge pull request #7612 from spirlici/patch-1
Update ordered-associations.rst
2019-03-12 00:16:09 +01:00
Marco Pivetta 49a8f2ec96 Merge pull request #7630 from yethee/gh-7629
Fix #7629 - `scheduledForSynchronization` leaks memory when using `@ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")`
2019-03-01 21:24:57 +01:00
yethee 7f5f4629e5 Ensure state is cleanup after empty commit 2019-03-01 23:00:01 +03:00
yethee d91e0b3867 Failing tests 2019-02-28 17:12:54 +03:00
Sergiu Pirlici b537758b32 Update ordered-associations.rst
Fixed some typos
2019-02-16 15:04:45 +02:00
Sumit Chahal 2ba6e473de Change APC to OPcache in improving-performance.rst
OPcache is a lot better supported now than APC,
which is apparently not maintained anymore.
2019-02-16 16:44:21 +05:30
Marco Pivetta de97061d65 Merge pull request #7596 from mbessolov/patch-1
Correct method names and broken link in docs
2019-02-09 15:47:17 +01:00
Michael Bessolov 624ee78081 Correct method names and broken link in docs
This basically applying the same documentation fix as in #7335 (master) to 2.6 branch
2019-02-08 22:29:10 -08:00
Marco Pivetta e003bb2bb4 Merge pull request #7577 from SenseException/advanced-config-link
Fix of single link to dbal docs in advanced-configuration.rst
2019-01-23 07:48:12 +01:00
Claudio Zizza 5c5f310646 Fix of link to dbal docs 2019-01-22 22:42:13 +01:00
Marco Pivetta c10433e512 Merge pull request #7572 from SenseException/remove-codeigniter
Remove codeigniter Framework example
2019-01-17 22:35:58 +01:00
Claudio Zizza 580c530041 Remove codeigniter example from docs 2019-01-17 21:54:33 +01:00
Marco Pivetta 4d461afbd6 Merge pull request #7571 from batwolf/patch-1
Fix typo in inheritance mappings docs
2019-01-17 21:42:45 +01:00
Marco Pivetta 536e31f343 Merge pull request #7385 from SenseException/links-and-typos
Update information and links of documentation
2019-01-17 21:11:50 +01:00
Marc Plotz c6eb4df25e fix typo
`has to allow null values` vs `has to allows null values`
2019-01-17 10:14:56 +01:00
Claudio Zizza aae00e3987 Fix of links and php version after review 2019-01-07 14:40:26 +01:00
Claudio Zizza b56800b15c Fix of links and anchors 2019-01-07 14:40:17 +01:00
Claudio Zizza be461be36b Update getting help section 2019-01-07 14:40:10 +01:00
Claudio Zizza 85171a9490 Fix of reStructuredText format 2019-01-07 14:40:02 +01:00
Claudio Zizza f5b9f2052a Update MySQL links to current version 2019-01-07 14:39:54 +01:00
Claudio Zizza 3d652997d1 Remove changelog from documentation
This was removed in favour of the UPGRADE.md file, which
contains the changelog information needed.
2019-01-07 14:39:42 +01:00
Marco Pivetta 10393dca68 Merge pull request #7557 from doctrine/malarzm-patch-1
Change Stackoverflow tag to doctrine-orm
2019-01-05 17:48:41 +01:00
Maciej Malarz 597bfaea03 Change Stackoverflow tag to doctrine-orm 2019-01-04 22:20:24 +01:00
Jonathan H. Wage 98b8ced814 Merge pull request #7551 from Majkl578/repo-rename/2.6
[2.6] Migrate repository name doctrine/doctrine2 -> doctrine/orm
2019-01-03 17:18:59 -06:00
Michael Moravec efaee8ce85 Migrate repository name doctrine/doctrine2 -> doctrine/orm 2019-01-03 09:07:03 +01:00
Luís Cobucci 6e93f5bb72 Merge pull request #7528 from Ocramius/fix/#7527-prevent-unit-of-work-lookup-for-known-value-types
Fix #7527:  prevent `UnitOfWork` lookup for DBAL types specified in `Doctrine\ORM\Query#setParameter()`
2018-12-21 21:54:20 +01:00
Marco Pivetta a41f5673bc #7527 automated CS checks 2018-12-20 22:59:46 +01:00
Marco Pivetta ca436f0bae #7527 performance benchmark - verifying performance impact of inferred query parameter types
As an example result:

```
./phpbench.phar run tests/Doctrine/Performance/Query --iterations=50 --revs=50 --report=aggregate
PhpBench 0.15-dev (dcbe193). Running benchmarks.
Using configuration file: /home/ocramius/Documents/doctrine/doctrine2/phpbench.json

\Doctrine\Performance\Query\QueryBoundParameterProcessingBench

    benchExecuteParsedQueryWithInferredParameterTypeI49 P0 	[μ Mo]/r: 643.684 634.664 (μs) 	[μSD μRSD]/r: 17.700μs 2.75%
    benchExecuteParsedQueryWithDeclaredParameterTypeI49 P0 	[μ Mo]/r: 97.673 94.251 (μs) 	[μSD μRSD]/r: 8.259μs 8.46%

2 subjects, 100 iterations, 100 revs, 0 rejects, 0 failures, 0 warnings
(best [mean mode] worst) = 88.460 [370.679 364.458] 127.400 (μs)
⅀T: 37,067.880μs μSD/r 12.980μs μRSD/r: 5.603%
suite: 133f0e30090f815142331ebec6af18241694e7c0, date: 2018-12-19, stime: 10:47:10
+------------------------------------+--------------------------------------------------+--------+--------+------+-----+------------+-----------+-----------+-----------+-----------+----------+--------+-------+
| benchmark                          | subject                                          | groups | params | revs | its | mem_peak   | best      | mean      | mode      | worst     | stdev    | rstdev | diff  |
+------------------------------------+--------------------------------------------------+--------+--------+------+-----+------------+-----------+-----------+-----------+-----------+----------+--------+-------+
| QueryBoundParameterProcessingBench | benchExecuteParsedQueryWithInferredParameterType |        | []     | 50   | 50  | 5,970,568b | 604.680μs | 643.684μs | 634.664μs | 677.640μs | 17.700μs | 2.75%  | 6.59x |
| QueryBoundParameterProcessingBench | benchExecuteParsedQueryWithDeclaredParameterType |        | []     | 50   | 50  | 5,922,424b | 88.460μs  | 97.673μs  | 94.251μs  | 127.400μs | 8.259μs  | 8.46%  | 1.00x |
+------------------------------------+--------------------------------------------------+--------+--------+------+-----+------------+-----------+-----------+-----------+-----------+----------+--------+-------+
```

This indicates that the performance impact for NOT declaring parameter types
explicitly is *MASSIVE*.
2018-12-19 10:52:11 +01:00
Marco Pivetta d8212e8dd6 Merge pull request #7530 from vladyslavstartsev/patch-3
Documentation error fix
2018-12-17 16:00:44 +01:00
vladyslavstartsev 12eb9f42dc Documentation error fix 2018-12-16 20:33:21 +02:00
Marco Pivetta 23af164d7a Note: this will still lead to the UnitOfWork#getSingleIdentifierValue() still being
called when not specifying the type of a DQL parameter being bound via
`Doctrine\ORM\Query#setParameter()`:

```php
$query->setParameter('foo', $theValue, $theType);
```

A full parameter bind is required in order to gain back performance:

```php
$query->setParameter('foo', $theValue, $theType);
```

This is up for discussion with patch reviewers.
2018-12-16 18:05:02 +01:00
Marco Pivetta 960a437d46 #7527 failing test case: UnitOfWork#getSingleIdentifierValue() should not be called for a well specified parameter type
As previously reported by @flaushi in https://github.com/doctrine/doctrine2/pull/7471#discussion_r241949045, we discovered
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance
regression when using any `object` type as parameter.

Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an
exception being thrown and garbage collected, plus multiple associated performance implications:

```php
$query->setParameter('foo', new DateTime());
$query->getResult();
```

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

This is due to following portion of code:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409

Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value.

That call leads to this segment being reached, which leads to the regression:

https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433

Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object:

```php
$query->setParameter('foo', new DateTime(), DateTimeType::NAME);
$query->getResult();
```

Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters.
In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter
out all parameters for which the type is given upfront, and later on merge them back in instead.

The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
2018-12-16 15:37:45 +01:00
Marco Pivetta 237bebe2ed Merge pull request #7519 from koftikes/fix/#7518-phpdoc-error
#7518 Fixed type mismatch between `EntityRepository#__construct()` and its documented constructor arguments
2018-12-13 08:14:30 +01:00
Jonathan H. Wage fc3dca772e Merge pull request #7521 from doctrine/update-chat-link
Update chat link from Gitter to Slack.
2018-12-12 20:07:31 +00:00
Konstantin Litvinov ee64d31f48 7518 Fixed PHPDoc Error. 2018-12-12 17:08:35 +03:00
Michael Moravec 493ff74a0d Merge pull request #7473 from Majkl578/incremental-cs-2.x
Incremental CS checks in 2.x branches
2018-12-10 14:43:55 +01:00
Michael Moravec 78c7000962 Lock dependencies for Code Quality stage 2018-12-10 13:58:51 +01:00
Michael Moravec 6a05e01298 Perform incremental coding standard checks for pull requests 2018-12-10 13:58:51 +01:00
Gabriel Ostrolucký 7de3434733 Update doctrine/coding-standard in 2.x branch
Co-Authored-By: Michael Moravec <me@majkl.me>
2018-12-10 13:58:51 +01:00
Luís Cobucci 74e6189f3e Merge pull request #7483 from javiereguiluz/patch-9
Fixed a minor syntax issue
2018-11-21 10:48:33 +01:00
Javier Eguiluz 2e7a3affba Fixed a minor syntax issue 2018-11-21 09:06:54 +01:00
Luís Cobucci 505ec21f97 Bump up development version 2018-11-21 01:24:06 +01:00
naitsirch 17bc627bf2 Added hint about exception in Query#getOneOrNullResult()
When calling `Query#getOneOrNullResult()` and there are more than one
objects in the result an `NonUniqueResultException` is thrown.
This information was missing in the documentation about the query result
formats.

This commit addresses #6793.
2018-10-29 21:26:02 +01:00
331 changed files with 10081 additions and 3291 deletions
+49
View File
@@ -0,0 +1,49 @@
{
"active": true,
"name": "Object Relational Mapper",
"shortName": "ORM",
"slug": "orm",
"docsSlug": "doctrine-orm",
"versions": [
{
"name": "3.0",
"branchName": "master",
"slug": "latest",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"upcoming": true
},
{
"name": "2.7",
"branchName": "2.7",
"slug": "2.7",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.6",
"branchName": "2.6",
"slug": "2.6",
"maintained": false
},
{
"name": "2.5",
"branchName": "2.5",
"slug": "2.5",
"maintained": false
},
{
"name": "2.4",
"branchName": "2.4",
"slug": "2.4",
"maintained": false
}
]
}
+4
View File
@@ -1,5 +1,6 @@
/tests export-ignore
/tools export-ignore
/.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitmodules export-ignore
@@ -11,3 +12,6 @@ CONTRIBUTING.md export-ignore
phpunit.xml.dist export-ignore
run-all.sh export-ignore
phpcs.xml.dist export-ignore
phpbench.json export-ignore
phpstan.neon export-ignore
psalm.xml export-ignore
+111
View File
@@ -0,0 +1,111 @@
name: CI
on:
pull_request:
jobs:
static-analysis-phpstan:
name: "Static Analysis with PHPStan"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: cs2pr
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-progress --no-suggest --no-interaction --prefer-dist"
- name: "Run a static analysis with phpstan/phpstan"
run: "php vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
static-analysis-psalm:
name: "Static Analysis with Psalm"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-interaction --no-progress --no-suggest"
- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 10
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-interaction --no-progress --no-suggest"
- name: "Install git-phpcs"
run: "wget https://github.com/diff-sniffer/git/releases/download/0.3.2/git-phpcs.phar"
- name: "Fetch head branch"
run: "git remote set-branches --add origin $GITHUB_BASE_REF && git fetch origin $GITHUB_BASE_REF"
- name: "Run git-phpcs"
run: "php git-phpcs.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"
@@ -0,0 +1,55 @@
name: "Automatic Releases"
on:
milestone:
types:
- "closed"
jobs:
release:
name: "Git tag, release & create merge-up PR"
runs-on: "ubuntu-20.04"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Release"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:release"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create Merge-Up Pull Request"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create and/or Switch to new Release Branch"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
env:
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create new milestones"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-milestones"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
-1
View File
@@ -12,6 +12,5 @@ lib/Doctrine/DBAL
.idea
*.iml
vendor/
composer.lock
/tests/Doctrine/Performance/history.db
/.phpcs-cache
-34
View File
@@ -1,34 +0,0 @@
build:
nodes:
analysis:
environment:
php:
version: 7.1
cache:
disabled: false
directories:
- ~/.composer/cache
project_setup:
override: true
tests:
override:
- php-scrutinizer-run
before_commands:
- "composer install --no-dev --prefer-source"
tools:
external_code_coverage:
timeout: 3600
filter:
excluded_paths:
- docs
- tools
build_failure_conditions:
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
- 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity
- 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection
- 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed
+20 -17
View File
@@ -6,7 +6,7 @@ php:
- 7.1
- 7.2
- 7.3
- nightly
- 7.4
env:
- DB=sqlite
@@ -17,7 +17,7 @@ before_install:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
- composer self-update
install: travis_retry composer update --prefer-dist
install: travis_retry composer validate --strict && composer update --prefer-dist
script:
- if [[ "$DB" == "mysql" || "$DB" == "mariadb" ]]; then mysql -e "CREATE SCHEMA doctrine_tests; GRANT ALL PRIVILEGES ON doctrine_tests.* to travis@'%'"; fi
@@ -32,22 +32,31 @@ jobs:
mariadb: 10.1
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: 7.1
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: 7.2
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: nightly
php: 7.4
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
@@ -71,32 +80,26 @@ jobs:
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
script:
- ENABLE_SECOND_LEVEL_CACHE=0 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --coverage-clover ./build/logs/clover.xml
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml
- stage: Code Quality
env: DB=none STATIC_ANALYSIS
install: travis_retry composer update --prefer-dist --prefer-stable
before_script:
- echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- travis_retry composer require --dev --prefer-dist --prefer-stable phpstan/phpstan:^0.9
script: vendor/bin/phpstan analyse -l 1 -c phpstan.neon lib
after_success:
- bash <(curl -s https://codecov.io/bash) -f ./build/logs/clover.xml
- stage: Code Quality
env: DB=none BENCHMARK
php: 7.4
before_script: wget https://phpbench.github.io/phpbench/phpbench.phar https://phpbench.github.io/phpbench/phpbench.phar.pubkey
script: php phpbench.phar run -l dots --report=default
- stage: Code Quality
if: NOT type = pull_request
env: DB=none CODING_STANDARDS
php: nightly
php: 7.4
install: travis_retry composer install --prefer-dist
script:
- ./vendor/bin/phpcs
allow_failures:
- php: nightly
- stage: Code Quality
env: DB=none CODING_STANDARDS
cache:
directories:
+4 -4
View File
@@ -44,12 +44,12 @@ Please try to add a test for your pull-request.
You can run the unit-tests by calling ``vendor/bin/phpunit`` from the root of the project.
It will run all the tests with an in memory SQLite database.
In order to do that, you will need a fresh copy of doctrine2, and you
In order to do that, you will need a fresh copy of the ORM, and you
will have to run a composer installation in the project:
```sh
git clone git@github.com:doctrine/doctrine2.git
cd doctrine2
git clone git@github.com:doctrine/orm.git
cd orm
curl -sS https://getcomposer.org/installer | php --
./composer.phar install
```
@@ -66,7 +66,7 @@ sqlite database.
Tips for creating unit tests:
1. If you put a test into the `Ticket` namespace as described above, put the testcase and all entities into the same class.
See `https://github.com/doctrine/doctrine2/tree/master/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
See `https://github.com/doctrine/orm/tree/master/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
example.
## Travis
+11 -11
View File
@@ -1,7 +1,7 @@
| [Master][Master] | [2.5][2.5] |
| [Master][Master] | [2.7][2.7] |
|:----------------:|:----------:|
| [![Build status][Master image]][Master] | [![Build status][2.5 image]][2.5] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.5 coverage image]][2.5 coverage] |
| [![Build status][Master image]][Master] | [![Build status][2.7 image]][2.7] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.7 coverage image]][2.7 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
@@ -16,11 +16,11 @@ without requiring unnecessary code duplication.
* [Documentation](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
[Master image]: https://img.shields.io/travis/doctrine/doctrine2/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/doctrine2
[Master coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/doctrine2/master.svg?style=flat-square
[Master coverage]: https://scrutinizer-ci.com/g/doctrine/doctrine2/?branch=master
[2.5 image]: https://img.shields.io/travis/doctrine/doctrine2/2.5.svg?style=flat-square
[2.5]: https://github.com/doctrine/doctrine2/tree/2.5
[2.5 coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/doctrine2/2.5.svg?style=flat-square
[2.5 coverage]: https://scrutinizer-ci.com/g/doctrine/doctrine2/?branch=2.5
[Master image]: https://img.shields.io/travis/doctrine/orm/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/orm
[Master coverage image]: https://codecov.io/gh/doctrine/orm/branch/master/graph/badge.svg
[Master coverage]: https://codecov.io/gh/doctrine/orm/branch/master
[2.7 image]: https://img.shields.io/travis/doctrine/orm/2.7.svg?style=flat-square
[2.7]: https://github.com/doctrine/orm/tree/2.7
[2.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.7/graph/badge.svg
[2.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.7
+1 -1
View File
@@ -11,7 +11,7 @@ Please read the documentation chapter on Security in Doctrine DBAL and ORM to
understand the assumptions we make.
- [DBAL Security Page](https://github.com/doctrine/dbal/blob/master/docs/en/reference/security.rst)
- [ORM Security Page](https://github.com/doctrine/doctrine2/blob/master/docs/en/reference/security.rst)
- [ORM Security Page](https://github.com/doctrine/orm/blob/master/docs/en/reference/security.rst)
If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core
+152 -10
View File
@@ -1,3 +1,145 @@
# Upgrade to 2.7
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
Method `Doctrine\ORM\AbstractQuery#useResultCache()` which could be used for both enabling and disabling the cache
(depending on passed flag) was split into two.
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
To optimize DB interaction, `Doctrine\ORM\Tools\Pagination\Paginator` no longer fetches identifiers to be able to
perform the pagination with join collections when max results isn't set in the query.
## Minor BC BREAK: tables filtered with `schema_filter` are no longer created
When generating schema diffs, if a source table is filtered out by a `schema_filter` expression, then a `CREATE TABLE` was
always generated, even if the table already existed. This has been changed in this release and the table will no longer
be created.
## Deprecated number unaware `Doctrine\ORM\Mapping\UnderscoreNamingStrategy`
In the last patch of the `v2.6.x` series, we fixed a bug that was not converting names properly when they had numbers
(e.g.: `base64Encoded` was wrongly converted to `base64encoded` instead of `base64_encoded`).
In order to not break BC we've introduced a way to enable the fixed behavior using a boolean constructor argument. This
argument will be removed in 3.0 and the default behavior will be the fixed one.
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
Method `Doctrine\ORM\AbstractQuery#useResultCache()` is deprecated because it is split into `enableResultCache()`
and `disableResultCache()`. It will be removed in 3.0.
## Deprecated code generators and related console commands
These console commands have been deprecated:
* `orm:convert-mapping`
* `orm:generate:entities`
* `orm:generate-repositories`
These classes have been deprecated:
* `Doctrine\ORM\Tools\EntityGenerator`
* `Doctrine\ORM\Tools\EntityRepositoryGenerator`
Whole Doctrine\ORM\Tools\Export namespace with all its members have been deprecated as well.
## Deprecated `Doctrine\ORM\Proxy\Proxy` marker interface
Proxy objects in Doctrine ORM 3.0 will no longer implement `Doctrine\ORM\Proxy\Proxy` nor
`Doctrine\Persistence\Proxy`: instead, they implement
`ProxyManager\Proxy\GhostObjectInterface`.
These related classes have been deprecated:
* `Doctrine\ORM\Proxy\ProxyFactory`
* `Doctrine\ORM\Proxy\Autoloader` - we suggest using the composer autoloader instead
These methods have been deprecated:
* `Doctrine\ORM\Configuration#getAutoGenerateProxyClasses()`
* `Doctrine\ORM\Configuration#getProxyDir()`
* `Doctrine\ORM\Configuration#getProxyNamespace()`
## Deprecated `Doctrine\ORM\Version`
The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctrine ORM 3.0:
please refrain from checking the ORM version at runtime or use
[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/).
## Deprecated `EntityManager#merge()` and `EntityManager#detach()` methods
Merge and detach semantics were a poor fit for the PHP "share-nothing" architecture.
In addition to that, merging/detaching caused multiple issues with data integrity
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
The following API methods were therefore deprecated:
* `EntityManager#merge()`
* `EntityManager#detach()`
* `UnitOfWork#merge()`
* `UnitOfWork#detach()`
Users are encouraged to migrate `EntityManager#detach()` calls to `EntityManager#clear()`.
In order to maintain performance on batch processing jobs, it is endorsed to enable
the second level cache (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
on entities that are frequently reused across multiple `EntityManager#clear()` calls.
An alternative to `EntityManager#merge()` will not be provided by ORM 3.0, since the merging
semantics should be part of the business domain rather than the persistence domain of an
application. If your application relies heavily on CRUD-alike interactions and/or `PATCH`
restful operations, you should look at alternatives such as [JMSSerializer](https://github.com/schmittjoh/serializer).
## Extending `EntityManager` is deprecated
Final keyword will be added to the `EntityManager::class` in Doctrine ORM 3.0 in order to ensure that EntityManager
is not used as valid extension point. Valid extension point should be EntityManagerInterface.
## Deprecated `EntityManager#clear($entityName)`
If your code relies on clearing a single entity type via `EntityManager#clear($entityName)`,
the signature has been changed to `EntityManager#clear()`.
The main reason is that partial clears caused multiple issues with data integrity
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
## Deprecated `EntityManager#flush($entity)` and `EntityManager#flush($entities)`
If your code relies on single entity flushing optimisations via
`EntityManager#flush($entity)`, the signature has been changed to
`EntityManager#flush()`.
Said API was affected by multiple data integrity bugs due to the fact
that change tracking was being restricted upon a subset of the managed
entities. The ORM cannot support committing subsets of the managed
entities while also guaranteeing data integrity, therefore this
utility was removed.
The `flush()` semantics will remain the same, but the change tracking will be performed
on all entities managed by the unit of work, and not just on the provided
`$entity` or `$entities`, as the parameter is now completely ignored.
The same applies to `UnitOfWork#commit($entity)`, which will simply be
`UnitOfWork#commit()`.
If you would still like to perform batching operations over small `UnitOfWork`
instances, it is suggested to follow these paths instead:
* eagerly use `EntityManager#clear()` in conjunction with a specific second level
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html)
## Deprecated `YAML` mapping drivers.
If your code relies on `YamlDriver` or `SimpleYamlDriver`, you **MUST** change to
annotation or XML drivers instead.
## Deprecated: `Doctrine\ORM\EntityManagerInterface#copy()`
Method `Doctrine\ORM\EntityManagerInterface#copy()` never got its implementation and is deprecated.
It will be removed in 3.0.
# Upgrade to 2.6
## Added `Doctrine\ORM\EntityRepository::count()` method
@@ -20,13 +162,13 @@ now has a required parameter `$pathExpr`.
Method `Doctrine\ORM\Query\Parser#isInternalFunction()` was removed because
the distinction between internal function and user defined DQL was removed.
[#6500](https://github.com/doctrine/doctrine2/pull/6500)
[#6500](https://github.com/doctrine/orm/pull/6500)
## Minor BC BREAK: removed `Doctrine\ORM\ORMException#overwriteInternalDQLFunctionNotAllowed()`
Method `Doctrine\ORM\Query\Parser#overwriteInternalDQLFunctionNotAllowed()` was
removed because of the choice to allow users to overwrite internal functions, ie
`AVG`, `SUM`, `COUNT`, `MIN` and `MAX`. [#6500](https://github.com/doctrine/doctrine2/pull/6500)
`AVG`, `SUM`, `COUNT`, `MIN` and `MAX`. [#6500](https://github.com/doctrine/orm/pull/6500)
## PHP 7.1 is now required
@@ -42,7 +184,7 @@ As a consequence, automatic cache setup in Doctrine\ORM\Tools\Setup::create*Conf
## Minor BC BREAK: removed `Doctrine\ORM\Query\SqlWalker#walkCaseExpression()`
Method `Doctrine\ORM\Query\SqlWalker#walkCaseExpression()` was unused and part
of the internal API of the ORM, so it was removed. [#5600](https://github.com/doctrine/doctrine2/pull/5600).
of the internal API of the ORM, so it was removed. [#5600](https://github.com/doctrine/orm/pull/5600).
## Minor BC BREAK: removed $className parameter on `AbstractEntityInheritancePersister#getSelectJoinColumnSQL()`
@@ -297,17 +439,17 @@ above you must implement these new methods.
## Metadata Drivers
Metadata drivers have been rewritten to reuse code from Doctrine\Common. Anyone who is using the
Metadata drivers have been rewritten to reuse code from `Doctrine\Persistence`. Anyone who is using the
`Doctrine\ORM\Mapping\Driver\Driver` interface should instead refer to
`Doctrine\Common\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\ORM\Mapping\Driver\AbstractFileDriver`: you should now refer to
`Doctrine\Common\Persistence\Mapping\Driver\FileDriver`.
`Doctrine\Persistence\Mapping\Driver\FileDriver`.
Also, following mapping drivers have been deprecated, please use their replacements in Doctrine\Common as listed:
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver`
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Persistence\Mapping\Driver\StaticPHPDriver`
# Upgrade to 2.2
@@ -396,7 +538,7 @@ Previously EntityManager#find(null) returned null. It now throws an exception.
## Interface for EntityRepository
The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
The EntityRepository now has an interface Doctrine\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
## AnnotationReader changes
-3
View File
@@ -1,3 +0,0 @@
# Version class and file
project.version_class = Doctrine\\ORM\\Version
project.version_file = lib/Doctrine/ORM/Version.php
-16
View File
@@ -1,16 +0,0 @@
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=
-101
View File
@@ -1,101 +0,0 @@
<?xml version="1.0"?>
<project name="DoctrineORM" default="build" basedir=".">
<property file="build.properties" />
<target name="php">
<exec executable="which" outputproperty="php_executable">
<arg value="php" />
</exec>
</target>
<target name="prepare">
<mkdir dir="build" />
</target>
<target name="build" depends="check-git-checkout-clean,prepare,php,composer">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="archive" />
<arg value="--dir=build" />
</exec>
</target>
<target name="composer" depends="php,composer-check,composer-download">
<exec executable="${php_executable}">
<arg value="build/composer.phar" />
<arg value="install" />
</exec>
</target>
<target name="composer-check" depends="prepare">
<available file="build/composer.phar" property="composer.present"/>
</target>
<target name="composer-download" unless="composer.present">
<exec executable="wget">
<arg value="-Obuild/composer.phar" />
<arg value="http://getcomposer.org/composer.phar" />
</exec>
</target>
<target name="make-release" depends="check-git-checkout-clean,prepare,php">
<replace file="${project.version_file}" token="-DEV" value="" failOnNoReplacements="true" />
<exec executable="${php_executable}" outputproperty="doctrine.current_version" failonerror="true">
<arg value="-r" />
<arg value="require_once '${project.version_file}';echo ${project.version_class}::VERSION;" />
</exec>
<exec executable="${php_executable}" outputproperty="doctrine.next_version" failonerror="true">
<arg value="-r" />
<arg value="$parts = explode('.', str_ireplace(array('-DEV', '-ALPHA', '-BETA'), '', '${doctrine.current_version}'));
if (count($parts) != 3) {
throw new \InvalidArgumentException('Version is assumed in format x.y.z, ${doctrine.current_version} given');
}
$parts[2]++;
echo implode('.', $parts);
" />
</exec>
<git-commit file="${project.version_file}" message="Release ${doctrine.current_version}" />
<git-tag version="${doctrine.current_version}" />
<replace file="${project.version_file}" token="${doctrine.current_version}" value="${doctrine.next_version}-DEV" />
<git-commit file="${project.version_file}" message="Bump version to ${doctrine.next_version}" />
</target>
<target name="check-git-checkout-clean">
<exec executable="git" failonerror="true">
<arg value="diff-index" />
<arg value="--quiet" />
<arg value="HEAD" />
</exec>
</target>
<macrodef name="git-commit">
<attribute name="file" default="NOT SET"/>
<attribute name="message" default="NOT SET"/>
<sequential>
<exec executable="git">
<arg value="add" />
<arg value="@{file}" />
</exec>
<exec executable="git">
<arg value="commit" />
<arg value="-m" />
<arg value="@{message}" />
</exec>
</sequential>
</macrodef>
<macrodef name="git-tag">
<attribute name="version" default="NOT SET" />
<sequential>
<exec executable="git">
<arg value="tag" />
<arg value="-m" />
<arg value="v@{version}" />
<arg value="v@{version}" />
</exec>
</sequential>
</macrodef>
</project>
+22 -13
View File
@@ -3,7 +3,7 @@
"type": "library",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",
"homepage": "https://www.doctrine-project.org/projects/orm.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
@@ -13,24 +13,33 @@
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
],
"config": {
"platform": {
"php": "7.1.3"
},
"sort-packages": true
},
"require": {
"php": "^7.1",
"ext-pdo": "*",
"doctrine/annotations": "~1.5",
"doctrine/cache": "~1.6",
"doctrine/collections": "^1.4",
"doctrine/common": "^2.7.1",
"doctrine/dbal": "^2.6",
"doctrine/instantiator": "~1.1",
"symfony/console": "~3.0|~4.0"
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.8",
"doctrine/cache": "^1.9.1",
"doctrine/collections": "^1.5",
"doctrine/common": "^2.11 || ^3.0",
"doctrine/dbal": "^2.9.3",
"doctrine/event-manager": "^1.1",
"doctrine/inflector": "^1.0",
"doctrine/instantiator": "^1.3",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^1.3.3 || ^2.0",
"symfony/console": "^3.0|^4.0|^5.0"
},
"require-dev": {
"doctrine/coding-standard": "^1.0",
"phpunit/phpunit": "^6.5",
"squizlabs/php_codesniffer": "^3.2",
"symfony/yaml": "~3.4|~4.0"
"doctrine/coding-standard": "^5.0",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^7.5",
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "^3.11"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
@@ -47,7 +56,7 @@
"bin": ["bin/doctrine"],
"extra": {
"branch-alias": {
"dev-master": "2.6.x-dev"
"dev-master": "2.7.x-dev"
}
},
"archive": {
Generated
+3634
View File
File diff suppressed because it is too large Load Diff
-711
View File
@@ -1,711 +0,0 @@
What is new in Doctrine ORM 2.5?
================================
This document describes changes between Doctrine ORM 2.4 and 2.5.
It contains a description of all the new features and sections about
behavioral changes and potential backwards compatibility breaks.
Please review this document carefully when updating to Doctrine 2.5.
First note, that with the ORM 2.5 release we are dropping support
for PHP 5.3. We are enforcing this with Composer, servers without
at least PHP 5.4 will not allow installing Doctrine 2.5.
New Features and Improvements
-----------------------------
Events: PostLoad now triggered after associations are loaded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before Doctrine 2.5 if you had an entity with a ``@PostLoad`` event
defined then Doctrine would trigger listeners after the fields were
loaded, but before assocations are available.
- `DDC-54 <http://doctrine-project.org/jira/browse/DDC-54>`_
- `Commit #a90629 <https://github.com/doctrine/doctrine2/commit/a906295c65f1516737458fbee2f6fa96254f27a5>`_
Events: Add API to programatically add event listeners to Entity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When developing third party libraries or decoupled applications
it can be interesting to develop an entity listener without knowing
the entities that require this listener.
You can now attach entity listeners to entities using the
``AttachEntityListenersListener`` class, which is listening to the
``loadMetadata`` event that is fired once for every entity during
metadata generation:
.. code-block:: php
<?php
use Doctrine\ORM\Tools\AttachEntityListenersListener;
use Doctrine\ORM\Events;
$listener = new AttachEntityListenersListener();
$listener->addEntityListener(
'MyProject\Entity\User', 'MyProject\Listener\TimestampableListener',
Events::prePersist, 'onPrePersist'
);
$evm->addEventListener(Events::loadClassMetadata, $listener);
class TimestampableListener
{
public function onPrePersist($event)
{
$entity = $event->getEntity();
$entity->setCreated(new \DateTime('now'));
}
}
Embeddable Objects
~~~~~~~~~~~~~~~~~~
Doctrine now supports creating multiple PHP objects from one database table
implementing a feature called "Embeddable Objects". Next to an ``@Entity``
class you can now define a class that is embeddable into a database table of an
entity using the ``@Embeddable`` annotation. Embeddable objects can never be
saved, updated or deleted on their own, only as part of an entity (called
"root-entity" or "aggregate"). Consequently embeddables don't have a primary
key, they are identified only by their values.
Example of defining and using embeddables classes:
.. code-block:: php
<?php
/** @Entity */
class Product
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Embedded(class = "Money") */
private $price;
}
/** @Embeddable */
class Money
{
/** @Column(type = "decimal") */
private $value;
/** @Column(type = "string") */
private $currency = 'EUR';
}
You can read more on the features of Embeddables objects `in the documentation
<http://docs.doctrine-project.org/en/latest/tutorials/embeddables.html>`_.
This feature was developed by external contributor `Johannes Schmitt
<https://twitter.com/schmittjoh>`_
- `DDC-93 <http://doctrine-project.org/jira/browse/DDC-93>`_
- `Pull Request #835 <https://github.com/doctrine/doctrine2/pull/835>`_
Second-Level-Cache
~~~~~~~~~~~~~~~~~~
Since version 2.0 of Doctrine, fetching the same object twice by primary key
would result in just one query. This was achieved by the identity map pattern
(first-level-cache) that kept entities in memory.
The newly introduced second-level-cache works a bit differently. Instead
of saving objects in memory, it saves them in a fast in-memory cache such
as Memcache, Redis, Riak or MongoDB. Additionally it allows saving the result
of more complex queries than by primary key. Summarized this feature works
like the existing Query result cache, but it is much more powerful.
As an example lets cache an entity Country that is a relation to the User
entity. We always want to display the country, but avoid the additional
query to this table.
.. code-block:: php
<?php
/**
* @Entity
* @Cache(usage="READ_ONLY", region="country_region")
*/
class Country
{
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
protected $id;
/**
* @Column(unique=true)
*/
protected $name;
}
In this example we have specified a caching region name called
``country_region``, which we have to configure now on the EntityManager:
.. code-block:: php
$config = new \Doctrine\ORM\Configuration();
$config->setSecondLevelCacheEnabled();
$cacheConfig = $config->getSecondLevelCacheConfiguration();
$regionConfig = $cacheConfig->getRegionsConfiguration();
$regionConfig->setLifetime('country_region', 3600);
Now Doctrine will first check for the data of any country in the cache
instead of the database.
- `Documentation
<http://docs.doctrine-project.org/en/latest/reference/second-level-cache.html>`_
- `Pull Request #808 <https://github.com/doctrine/doctrine2/pull/808>`_
Criteria API: Support for ManyToMany assocations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We introduced support for querying collections using the `Criteria API
<http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#filtering-collections>`_
in 2.4. This only worked efficently for One-To-Many assocations, not for
Many-To-Many. With the start of 2.5 also Many-To-Many associations get queried
instead of loading them into memory.
Criteria API: Add new contains() expression
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is now possible to use the Criteria API to check for string contains needle
using ``contains()``. This translates to using a ``column LIKE '%needle%'`` SQL
condition.
.. code-block:: php
<?php
use \Doctrine\Common\Collections\Criteria;
$criteria = Criteria::create()
->where(Criteria::expr()->contains('name', 'Benjamin'));
$users = $repository->matching($criteria);
Criteria API: Support for EXTRA_LAZY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A collection that is marked as ``fetch="EXTRA_LAZY"`` will now return another
lazy collection when using ``Collection::matching($criteria)``:
.. code-block:: php
<?php
class Post
{
/** @OneToMany(targetEntity="Comment", fetch="EXTRA_LAZY") */
private $comments;
}
$criteria = Criteria::create()
->where(Criteria->expr()->eq("published", 1));
$publishedComments = $post->getComments()->matching($criteria);
echo count($publishedComments);
The lazy criteria currently supports the ``count()`` and ``contains()``
functionality lazily. All other operations of the ``Collection`` interface
trigger a full load of the collection.
This feature was contributed by `Michaël Gallego <https://github.com/bakura10>`_.
- `Pull Request #882 <https://github.com/doctrine/doctrine2/pull/882>`_
- `Pull Request #1032 <https://github.com/doctrine/doctrine2/pull/1032>`_
Mapping: Allow configuring Index flags
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is now possible to control the index flags in the DBAL
schema abstraction from the ORM using metadata. This was possible
only with a schema event listener before.
.. code-block:: php
<?php
/**
* @Table(name="product", indexes={@Index(columns={"description"},flags={"fulltext"})})
*/
class Product
{
private $description;
}
This feature was contributed by `Adrian Olek <https://github.com/adrianolek>`_.
- `Pull Request #973 <https://github.com/doctrine/doctrine2/pull/973>`_
SQLFilter API: Check if a parameter is set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can now check in your SQLFilter if a parameter was set. This allows
to more easily control which features of a filter to enable or disable.
Extending on the locale example of the documentation:
.. code-block:: php
<?php
class MyLocaleFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if (!$targetEntity->reflClass->implementsInterface('LocaleAware')) {
return "";
}
if (!$this->hasParameter('locale')) {
return "";
}
return $targetTableAlias.'.locale = ' . $this->getParameter('locale');
}
}
This feature was contributed by `Miroslav Demovic <https://github.com/mdemo>`_
- `Pull Request #963 <https://github.com/doctrine/doctrine2/pull/963>`_
EXTRA_LAZY Improvements
~~~~~~~~~~~~~~~~~~~~~~~
1. Efficient query when using EXTRA_LAZY and containsKey
When calling ``Collection::containsKey($key)`` on one-to-many and many-to-many
collections using ``indexBy`` and ``EXTRA_LAZY`` a query is now executed to check
for the existance for the item. Prevoiusly this operation was performed in memory
by loading all entities of the collection.
.. code-block:: php
<?php
class User
{
/** @OneToMany(targetEntity="Group", indexBy="id") */
private $groups;
}
if ($user->getGroups()->containsKey($groupId)) {
echo "User is in group $groupId\n";
}
This feature was contributed by `Asmir Mustafic <https://github.com/goetas>`_
- `Pull Request #937 <https://github.com/doctrine/doctrine2/pull/937>`_
2. Add EXTRA_LAZY Support for get() for owning and inverse many-to-many
This was contributed by `Sander Marechal <https://github.com/sandermarechal>`_.
Improve efficiency of One-To-Many EAGER
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When marking a one-to-many association with ``fetch="EAGER"`` it will now
execute one query less than before and work correctly in combination with
``indexBy``.
Better support for EntityManagerInterface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Many of the locations where previously only the ``Doctrine\ORM\EntityManager``
was allowed are now changed to accept the ``EntityManagerInterface`` that was
introduced in 2.4. This allows you to more easily use the decorator pattern
to extend the EntityManager if you need. It's still not replaced everywhere,
so you still have to be careful.
DQL Improvements
~~~~~~~~~~~~~~~~
1. It is now possible to add functions to the ``ORDER BY`` clause in DQL statements:
.. code-block:: php
<?php
$dql = "SELECT u FROM User u ORDER BY CONCAT(u.username, u.name)";
2. Support for functions in ``IS NULL`` expressions:
.. code-block:: php
<?php
$dql = "SELECT u.name FROM User u WHERE MAX(u.name) IS NULL";
3. A ``LIKE`` expression is now suported in ``HAVING`` clause.
4. Subselects are now supported inside a ``NEW()`` expression:
.. code-block:: php
<?php
$dql = "SELECT new UserDTO(u.name, SELECT count(g.id) FROM Group g WHERE g.id = u.id) FROM User u";
5. ``MEMBER OF`` expression now allows to filter for more than one result:
.. code-block:: php
<?php
$dql = "SELECT u FROM User u WHERE :groups MEMBER OF u.groups";
$query = $entityManager->createQuery($dql);
$query->setParameter('groups', array(1, 2, 3));
$users = $query->getResult();
6. Expressions inside ``COUNT()`` now allowed
.. code-block:: php
<?php
$dql = "SELECT COUNT(DISTINCT CONCAT(u.name, u.lastname)) FROM User u";
7. Add support for ``HOUR`` in ``DATE_ADD()``/``DATE_SUB()`` functions
Custom DQL Functions: Add support for factories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously custom DQL functions could only be provided with their
full-qualified class-name, preventing runtime configuration through
dependency injection.
A simplistic approach has been contributed by `Matthieu Napoli
<https://github.com/mnapoli>`_ to pass a callback instead that resolves
the function:
.. code-block:: php
<?php
$config = new \Doctrine\ORM\Configuration();
$config->addCustomNumericFunction(
'IS_PUBLISHED', function($funcName) use ($currentSiteId) {
return new IsPublishedFunction($currentSiteId);
}
);
Query API: WHERE IN Query using a Collection as parameter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When performing a ``WHERE IN`` query for a collection of entities you can
now pass the array collection of entities as a parameter value to the query
object:
.. code-block:: php
<?php
$categories = $rootCategory->getChildren();
$queryBuilder
->select('p')
->from('Product', 'p')
->where('p.category IN (:categories)')
->setParameter('categories', $categories)
;
This feature was contributed by `Michael Perrin
<https://github.com/michaelperrin>`_.
- `Pull Request #590 <https://github.com/doctrine/doctrine2/pull/590>`_
- `DDC-2319 <http://doctrine-project.org/jira/browse/DDC-2319>`_
Query API: Add support for default Query Hints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To configure multiple different features such as custom AST Walker, fetch modes,
locking and other features affecting DQL generation we have had a feature
called "query hints" since version 2.0.
It is now possible to add query hints that are always enabled for every Query:
.. code-block:: php
<?php
$config = new \Doctrine\ORM\Configuration();
$config->setDefaultQueryHints(
'doctrine.customOutputWalker' => 'MyProject\CustomOutputWalker'
);
This feature was contributed by `Artur Eshenbrener
<https://github.com/Strate>`_.
- `Pull Request #863 <https://github.com/doctrine/doctrine2/pull/863>`_
ResultSetMappingBuilder: Add support for Single-Table Inheritance
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before 2.5 the ResultSetMappingBuilder did not work with entities
that are using Single-Table-Inheritance. This restriction was lifted
by adding the missing support.
YAML Mapping: Many-To-Many doesnt require join column definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Annotations and XML it was not necessary using conventions for naming
the many-to-many join column names, in YAML it was not possible however.
A many-to-many definition in YAML is now possible using this minimal
definition:
.. code-block:: yaml
manyToMany:
groups:
targetEntity: Group
joinTable:
name: users_groups
Schema Validator Command: Allow to skip sub-checks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Schema Validator command executes two independent checks
for validity of the mappings and if the schema is synchronized
correctly. It is now possible to skip any of the two steps
when executing the command:
::
$ php vendor/bin/doctrine orm:validate-schema --skip-mapping
$ php vendor/bin/doctrine orm:validate-schema --skip-sync
This allows you to write more specialized continuous integration and automation
checks. When no changes are found the command returns the exit code 0
and 1, 2 or 3 when failing because of mapping, sync or both.
EntityGenerator Command: Avoid backups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When calling the EntityGenerator for an existing entity, Doctrine would
create a backup file every time to avoid losing changes to the code. You
can now skip generating the backup file by passing the ``--no-backup``
flag:
::
$ php vendor/bin/doctrine orm:generate-entities src/ --no-backup
Support for Objects as Identifiers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is now possible to use Objects as identifiers for Entities
as long as they implement the magic method ``__toString()``.
.. code-block:: php
<?php
class UserId
{
private $value;
public function __construct($value)
{
$this->value = $value;
}
public function __toString()
{
return (string)$this->value;
}
}
class User
{
/** @Id @Column(type="userid") */
private $id;
public function __construct(UserId $id)
{
$this->id = $id;
}
}
class UserIdType extends \Doctrine\DBAL\Types\Type
{
// ...
}
Doctrine\DBAL\Types\Type::addType('userid', 'MyProject\UserIdType');
Behavioral Changes (BC Breaks)
------------------------------
NamingStrategy interface changed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``Doctrine\ORM\Mapping\NamingStrategyInterface`` changed slightly
to pass the Class Name of the entity into the join column name generation:
::
- function joinColumnName($propertyName);
+ function joinColumnName($propertyName, $className = null);
It also received a new method for supporting embeddables:
::
public function embeddedFieldToColumnName($propertyName, $embeddedColumnName);
Minor BC BREAK: EntityManagerInterface instead of EntityManager in type-hints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require
an ``EntityManagerInterface`` instead.
If you are extending any of the following classes, then you need to check following
signatures:
- ``Doctrine\ORM\Tools\DebugUnitOfWorkListener#dumpIdentityMap(EntityManagerInterface $em)``
- ``Doctrine\ORM\Mapping\ClassMetadataFactory#setEntityManager(EntityManagerInterface $em)``
Minor BC BREAK: Custom Hydrators API change
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of 2.5, ``AbstractHydrator`` does not enforce the usage of cache as part of
API, and now provides you a clean API for column information through the method
``hydrateColumnInfo($column)``.
Cache variable being passed around by reference is no longer needed since
Hydrators are per query instantiated since Doctrine 2.4.
- `DDC-3060 <http://doctrine-project.org/jira/browse/DDC-3060>`_
Minor BC BREAK: All non-transient classes in an inheritance must be part of the inheritance map
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of 2.5, classes, if you define an inheritance map for an inheritance tree, you are required
to map all non-transient classes in that inheritance, including the root of the inheritance.
So far, the root of the inheritance was allowed to be skipped in the inheritance map: this is
not possible anymore, and if you don't plan to persist instances of that class, then you should
either:
- make that class as ``abstract``
- add that class to your inheritance map
If you fail to do so, then a ``Doctrine\ORM\Mapping\MappingException`` will be thrown.
- `DDC-3300 <http://doctrine-project.org/jira/browse/DDC-3300>`_
- `DDC-3503 <http://doctrine-project.org/jira/browse/DDC-3503>`_
Minor BC BREAK: Entity based EntityManager#clear() calls follow cascade detach
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Whenever ``EntityManager#clear()`` method gets called with a given entity class
name, until 2.4, it was only detaching the specific requested entity.
As of 2.5, ``EntityManager`` will follow configured cascades, providing a better
memory management since associations will be garbage collected, optimizing
resources consumption on long running jobs.
Updates on entities scheduled for deletion are no longer processed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In Doctrine 2.4, if you modified properties of an entity scheduled for deletion, UnitOfWork would
produce an ``UPDATE`` statement to be executed right before the ``DELETE`` statement. The entity in question
was therefore present in ``UnitOfWork#entityUpdates``, which means that ``preUpdate`` and ``postUpdate``
listeners were (quite pointlessly) called. In ``preFlush`` listeners, it used to be possible to undo
the scheduled deletion for updated entities (by calling ``persist()`` if the entity was found in both
``entityUpdates`` and ``entityDeletions``). This does not work any longer, because the entire changeset
calculation logic is optimized away.
Minor BC BREAK: Default lock mode changed from LockMode::NONE to null in method signatures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A misconception concerning default lock mode values in method signatures lead to unexpected behaviour
in SQL statements on SQL Server. With a default lock mode of ``LockMode::NONE`` throughout the
method signatures in ORM, the table lock hint ``WITH (NOLOCK)`` was appended to all locking related
queries by default. This could result in unpredictable results because an explicit ``WITH (NOLOCK)``
table hint tells SQL Server to run a specific query in transaction isolation level READ UNCOMMITTED
instead of the default READ COMMITTED transaction isolation level.
Therefore there now is a distinction between ``LockMode::NONE`` and ``null`` to be able to tell
Doctrine whether to add table lock hints to queries by intention or not. To achieve this, the following
method signatures have been changed to declare ``$lockMode = null`` instead of ``$lockMode = LockMode::NONE``:
- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#getSelectSQL()``
- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#load()``
- ``Doctrine\ORM\Cache\Persister\AbstractEntityPersister#refresh()``
- ``Doctrine\ORM\Decorator\EntityManagerDecorator#find()``
- ``Doctrine\ORM\EntityManager#find()``
- ``Doctrine\ORM\EntityRepository#find()``
- ``Doctrine\ORM\Persisters\BasicEntityPersister#getSelectSQL()``
- ``Doctrine\ORM\Persisters\BasicEntityPersister#load()``
- ``Doctrine\ORM\Persisters\BasicEntityPersister#refresh()``
- ``Doctrine\ORM\Persisters\EntityPersister#getSelectSQL()``
- ``Doctrine\ORM\Persisters\EntityPersister#load()``
- ``Doctrine\ORM\Persisters\EntityPersister#refresh()``
- ``Doctrine\ORM\Persisters\JoinedSubclassPersister#getSelectSQL()``
You should update signatures for these methods if you have subclassed one of the above classes.
Please also check the calling code of these methods in your application and update if necessary.
.. note::
This in fact is really a minor BC BREAK and should not have any affect on database vendors
other than SQL Server because it is the only one that supports and therefore cares about
``LockMode::NONE``. It's really just a FIX for SQL Server environments using ORM.
Minor BC BREAK: __clone method not called anymore when entities are instantiated via metadata API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of PHP 5.6, instantiation of new entities is deferred to the
`doctrine/instantiator <https://github.com/doctrine/instantiator>`_ library, which will avoid calling ``__clone``
or any public API on instantiated objects.
BC BREAK: DefaultRepositoryFactory is now final
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please implement the ``Doctrine\ORM\Repository\RepositoryFactory`` interface instead of extending
the ``Doctrine\ORM\Repository\DefaultRepositoryFactory``.
BC BREAK: New object expression DQL queries now respects user provided aliasing and not return consumed fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When executing DQL queries with new object expressions, instead of returning
DTOs numerically indexes, it will now respect user provided aliases. Consider
the following query:
::
SELECT new UserDTO(u.id,u.name) as user,new AddressDTO(a.street,a.postalCode) as address, a.id as addressId
FROM User u INNER JOIN u.addresses a WITH a.isPrimary = true
Previously, your result would be similar to this:
::
array(
0=>array(
0=>{UserDTO object},
1=>{AddressDTO object},
2=>{u.id scalar},
3=>{u.name scalar},
4=>{a.street scalar},
5=>{a.postalCode scalar},
'addressId'=>{a.id scalar},
),
...
)
From now on, the resultset will look like this:
::
array(
0=>array(
'user'=>{UserDTO object},
'address'=>{AddressDTO object},
'addressId'=>{a.id scalar}
),
...
)
@@ -11,9 +11,9 @@ There are several ways to achieve this: converting the value inside the Type
class, converting the value on the database-level or a combination of both.
This article describes the third way by implementing the MySQL specific column
type `Point <http://dev.mysql.com/doc/refman/5.5/en/gis-class-point.html>`_.
type `Point <https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html>`_.
The ``Point`` type is part of the `Spatial extension <http://dev.mysql.com/doc/refman/5.5/en/spatial-extensions.html>`_
The ``Point`` type is part of the `Spatial extension <https://dev.mysql.com/doc/refman/8.0/en/spatial-extensions.html>`_
of MySQL and enables you to store a single location in a coordinate space by
using x and y coordinates. You can use the Point type to store a
longitude/latitude pair to represent a geographic location.
@@ -192,9 +192,9 @@ object into a string representation before saving to the database (in the
``convertToDatabaseValue`` method) and back into an object after fetching the
value from the database (in the ``convertToPHPValue`` method).
The format of the string representation format is called `Well-known text (WKT)
<http://en.wikipedia.org/wiki/Well-known_text>`_. The advantage of this format
is, that it is both human readable and parsable by MySQL.
The format of the string representation format is called
`Well-known text (WKT) <http://en.wikipedia.org/wiki/Well-known_text>`_.
The advantage of this format is, that it is both human readable and parsable by MySQL.
Internally, MySQL stores geometry values in a binary format that is not
identical to the WKT format. So, we need to let MySQL transform the WKT
@@ -204,8 +204,8 @@ This is where the ``convertToPHPValueSQL`` and ``convertToDatabaseValueSQL``
methods come into play.
This methods wrap a sql expression (the WKT representation of the Point) into
MySQL functions `PointFromText <http://dev.mysql.com/doc/refman/5.5/en/creating-spatial-values.html#function_pointfromtext>`_
and `AsText <http://dev.mysql.com/doc/refman/5.5/en/functions-to-convert-geometries-between-formats.html#function_astext>`_
MySQL functions `ST_PointFromText <https://dev.mysql.com/doc/refman/8.0/en/gis-wkt-functions.html#function_st-pointfromtext>`_
and `ST_AsText <https://dev.mysql.com/doc/refman/8.0/en/gis-format-conversion-functions.html#function_st-astext>`_
which convert WKT strings to and from the internal format of MySQL.
.. note::
@@ -249,7 +249,7 @@ Example usage
$em->clear();
// Fetch the Location object
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location l WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
$location = $query->getSingleResult();
/* @var Geo\ValueObject\Point */
+1 -1
View File
@@ -22,7 +22,7 @@ into the account can either be of positive or negative money
values. Each account has a credit limit and the account is never
allowed to have a balance below that value.
For simplicity we live in a world were money is composed of
For simplicity we live in a world where money is composed of
integers only. Also we omit the receiver/sender name, stated reason
for transfer and the execution date. These all would have to be
added on the ``Entry`` object.
+2 -2
View File
@@ -167,7 +167,7 @@ can be set via ``Query::setHint($name, $value)`` as shown in the
previous example with the ``HINT_CUSTOM_TREE_WALKERS`` query hint.
We will implement a custom Output Walker that allows to specify the
SQL\_NO\_CACHE query hint.
``SQL_NO_CACHE`` query hint.
.. code-block:: php
@@ -180,7 +180,7 @@ SQL\_NO\_CACHE query hint.
Our ``MysqlWalker`` will extend the default ``SqlWalker``. We will
modify the generation of the SELECT clause, adding the
SQL\_NO\_CACHE on those queries that need it:
``SQL_NO_CACHE`` on those queries that need it:
.. code-block:: php
@@ -21,7 +21,7 @@ the :doc:`Native Query <../reference/native-sql>` chapter.
The DQL Parser has hooks to register functions that can then be
used in your DQL queries and transformed into SQL, allowing to
extend Doctrines Query capabilities to the vendors strength. This
post explains the Used-Defined Functions API (UDF) of the Dql
post explains the User-Defined Functions API (UDF) of the Dql
Parser and shows some examples to give you some hints how you would
extend DQL.
@@ -70,7 +70,7 @@ methods, which are quite handy in my opinion:
Date Diff
---------
`Mysql's DateDiff function <http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_datediff>`_
`Mysql's DateDiff function <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_datediff>`_
takes two dates as argument and calculates the difference in days
with ``date1-date2``.
@@ -164,7 +164,7 @@ Date Add
Often useful it the ability to do some simple date calculations in
your DQL query using
`MySql's DATE\_ADD function <http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_date-add>`_.
`MySql's DATE_ADD function <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add>`_.
I'll skip the blah and show the code for this function:
@@ -246,6 +246,6 @@ vendor sql functions and extend the DQL languages scope.
Code for this Extension to DQL and other Doctrine Extensions can be
found
`in my Github DoctrineExtensions repository <http://github.com/beberlei/DoctrineExtensions>`_.
`in the GitHub DoctrineExtensions repository <http://github.com/beberlei/DoctrineExtensions>`_.
+1 -1
View File
@@ -44,7 +44,7 @@ Serializing entity into the session
-----------------------------------
Entities that are serialized into the session normally contain references to
other entities as well. Think of the user entity has a reference to his
other entities as well. Think of the user entity has a reference to their
articles, groups, photos or many other different entities. If you serialize
this object into the session then you don't want to serialize the related
entities as well. This is why you should call ``EntityManager#detach()`` on this
@@ -22,8 +22,8 @@ implement the ``NotifyPropertyChanged`` interface from the
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged;
use Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged;
use Doctrine\Persistence\PropertyChangedListener;
abstract class DomainObject implements NotifyPropertyChanged
{
@@ -11,8 +11,8 @@ However, it is quite easy to make use of these methods in a safe
way by guarding the custom wakeup or clone code with an entity
identity check, as demonstrated in the following sections.
Safely implementing \_\_wakeup
------------------------------
Safely implementing __wakeup
----------------------------
To safely implement ``__wakeup``, simply enclose your
implementation code in an identity check as follows:
@@ -37,8 +37,8 @@ implementation code in an identity check as follows:
//...
}
Safely implementing \_\_clone
-----------------------------
Safely implementing __clone
---------------------------
Safely implementing ``__clone`` is pretty much the same:
@@ -1,140 +0,0 @@
Integrating with CodeIgniter
============================
This is recipe for using Doctrine 2 in your
`CodeIgniter <http://www.codeigniter.com>`_ framework.
.. note::
This might not work for all CodeIgniter versions and may require
slight adjustments.
Here is how to set it up:
Make a CodeIgniter library that is both a wrapper and a bootstrap
for Doctrine 2.
Setting up the file structure
-----------------------------
Here are the steps:
- Add a php file to your system/application/libraries folder
called Doctrine.php. This is going to be your wrapper/bootstrap for
the D2 entity manager.
- Put the Doctrine folder (the one that contains Common, DBAL, and
ORM) inside that same libraries folder.
- Your system/application/libraries folder now looks like this:
system/applications/libraries -Doctrine -Doctrine.php -index.html
- If you want, open your config/autoload.php file and autoload
your Doctrine library.
<?php $autoload['libraries'] = array('doctrine');
Creating your Doctrine CodeIgniter library
------------------------------------------
Now, here is what your Doctrine.php file should look like.
Customize it to your needs.
.. code-block:: php
<?php
use Doctrine\Common\ClassLoader,
Doctrine\ORM\Configuration,
Doctrine\ORM\EntityManager,
Doctrine\Common\Cache\ArrayCache,
Doctrine\DBAL\Logging\EchoSQLLogger;
class Doctrine {
public $em = null;
public function __construct()
{
// load database configuration from CodeIgniter
require_once APPPATH.'config/database.php';
// Set up class loading. You could use different autoloaders, provided by your favorite framework,
// if you want to.
require_once APPPATH.'libraries/Doctrine/Common/ClassLoader.php';
$doctrineClassLoader = new ClassLoader('Doctrine', APPPATH.'libraries');
$doctrineClassLoader->register();
$entitiesClassLoader = new ClassLoader('models', rtrim(APPPATH, "/" ));
$entitiesClassLoader->register();
$proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
$proxiesClassLoader->register();
// Set up caches
$config = new Configuration;
$cache = new ArrayCache;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver(array(APPPATH.'models/Entities'));
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// Proxy configuration
$config->setProxyDir(APPPATH.'/models/proxies');
$config->setProxyNamespace('Proxies');
// Set up logger
$logger = new EchoSQLLogger;
$config->setSQLLogger($logger);
$config->setAutoGenerateProxyClasses( TRUE );
// Database connection information
$connectionOptions = array(
'driver' => 'pdo_mysql',
'user' => $db['default']['username'],
'password' => $db['default']['password'],
'host' => $db['default']['hostname'],
'dbname' => $db['default']['database']
);
// Create EntityManager
$this->em = EntityManager::create($connectionOptions, $config);
}
}
Please note that this is a development configuration; for a
production system you'll want to use a real caching system like
APC, get rid of EchoSqlLogger, and turn off
autoGenerateProxyClasses.
For more details, consult the
`Doctrine 2 Configuration documentation <http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html>`_.
Now to use it
-------------
Whenever you need a reference to the entity manager inside one of
your controllers, views, or models you can do this:
.. code-block:: php
<?php
$em = $this->doctrine->em;
That's all there is to it. Once you get the reference to your
EntityManager do your Doctrine 2.0 voodoo as normal.
Note: If you do not choose to autoload the Doctrine library, you
will need to put this line before you get a reference to it:
.. code-block:: php
<?php
$this->load->library('doctrine');
Good luck!
@@ -3,7 +3,7 @@ Strategy-Pattern
This recipe will give you a short introduction on how to design
similar entities without using expensive (i.e. slow) inheritance
but with not more than \* the well-known strategy pattern \* event
but with not more than *the well-known strategy pattern* event
listeners
Scenario / Problem
+3 -3
View File
@@ -25,8 +25,8 @@ the additional benefit of being able to re-use your validation in
any other part of your domain.
Say we have an ``Order`` with several ``OrderLine`` instances. We
never want to allow any customer to order for a larger sum than he
is allowed to:
never want to allow any customer to order for a larger sum than they
are allowed to:
.. code-block:: php
@@ -134,4 +134,4 @@ instances. This was already discussed in the previous blog post on
the Versionable extension, which requires another type of event
called "onFlush".
Further readings: :doc:`Lifecycle Events <../reference/events>`
Further readings: :ref:`reference-events-lifecycle-events`
+10 -2
View File
@@ -90,7 +90,10 @@ the UTC time at the time of the booking and the timezone the event happened in.
class UTCDateTimeType extends DateTimeType
{
static private $utc;
/**
* @var \DateTimeZone
*/
private static $utc;
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
@@ -110,7 +113,7 @@ the UTC time at the time of the booking and the timezone the event happened in.
$converted = \DateTime::createFromFormat(
$platform->getDateTimeFormatString(),
$value,
self::$utc ? self::$utc : self::$utc = new \DateTimeZone('UTC')
self::getUtc()
);
if (! $converted) {
@@ -123,6 +126,11 @@ the UTC time at the time of the booking and the timezone the event happened in.
return $converted;
}
private static function getUtc(): \DateTimeZone
{
return self::$utc ?: self::$utc = new \DateTimeZone('UTC');
}
}
This database type makes sure that every DateTime instance is always saved in UTC, relative
+9 -12
View File
@@ -13,11 +13,11 @@ If this documentation is not helping to answer questions you have about
Doctrine ORM don't panic. You can get help from different sources:
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
- The `Doctrine Mailing List <http://groups.google.com/group/doctrine-user>`_
- Internet Relay Chat (IRC) in #doctrine on Freenode
- Report a bug on `JIRA <http://www.doctrine-project.org/jira>`_.
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
- On `Twitter <https://twitter.com/search/%23doctrine2>`_ with ``#doctrine2``
- On `StackOverflow <http://stackoverflow.com/questions/tagged/doctrine2>`_
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
If you need more structure over the different topics you can browse the :doc:`table
of contents <toc>`.
@@ -72,9 +72,9 @@ Advanced Topics
* :doc:`Transactions and Concurrency <reference/transactions-and-concurrency>`
* :doc:`Filters <reference/filters>`
* :doc:`NamingStrategy <reference/namingstrategy>`
* :doc:`Improving Performance <reference/improving-performance>`
* :doc:`Caching <reference/caching>`
* :doc:`Partial Objects <reference/partial-objects>`
* :doc:`Improving Performance <reference/improving-performance>`
* :doc:`Caching <reference/caching>`
* :doc:`Partial Objects <reference/partial-objects>`
* :doc:`Change Tracking Policies <reference/change-tracking-policies>`
* :doc:`Best Practices <reference/best-practices>`
* :doc:`Metadata Drivers <reference/metadata-drivers>`
@@ -95,7 +95,7 @@ Tutorials
Changelogs
----------
* :doc:`Migration to 2.5 <changelog/migration_2_5>`
* `Upgrade <https://github.com/doctrine/doctrine2/blob/master/UPGRADE.md>`_
Cookbook
--------
@@ -103,7 +103,7 @@ Cookbook
* **Patterns**:
:doc:`Aggregate Fields <cookbook/aggregate-fields>` |
:doc:`Decorator Pattern <cookbook/decorator-pattern>` |
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
* **DQL Extension Points**:
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` |
@@ -118,9 +118,6 @@ Cookbook
:doc:`Entities in the Session <cookbook/entities-in-session>` |
:doc:`Keeping your Modules independent <cookbook/resolve-target-entity-listener>`
* **Integration into Frameworks/Libraries**
:doc:`CodeIgniter <cookbook/integrating-with-codeigniter>`
* **Hidden Gems**
:doc:`Prefixing Table Name <cookbook/sql-table-prefixes>`
+1 -1
View File
@@ -292,7 +292,7 @@ instance of ``Doctrine\DBAL\Connection``. If an array is passed it
is directly passed along to the DBAL Factory
``Doctrine\DBAL\DriverManager::getConnection()``. The DBAL
configuration is explained in the
`DBAL section <./../../../../../projects/doctrine-dbal/en/latest/reference/configuration.html>`_.
`DBAL section <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html>`_.
Proxy Objects
-------------
+7 -12
View File
@@ -99,7 +99,7 @@ Optional attributes:
- **length**: Used by the "string" type to determine its maximum
length in the database. Doctrine does not validate the length of a
string values for you.
string value for you.
- **precision**: The precision for a decimal (exact numeric) column
(applies only for decimal column), which is the maximum number of
@@ -181,7 +181,7 @@ Examples:
protected $initials;
/**
* @Column(type="integer", name="login_count" nullable=false, options={"unsigned":true, "default":0})
* @Column(type="integer", name="login_count", nullable=false, options={"unsigned":true, "default":0})
*/
protected $loginCount;
@@ -619,22 +619,17 @@ Examples:
This annotation is used in the context of relations in
:ref:`@ManyToOne <annref_manytoone>`, :ref:`@OneToOne <annref_onetoone>` fields
and in the Context of :ref:`@JoinTable <annref_jointable>` nested inside
a @ManyToMany. This annotation is not required. If it is not
specified the attributes *name* and *referencedColumnName* are
inferred from the table and primary key names.
Required attributes:
a @ManyToMany. If this annotation or both *name* and *referencedColumnName*
are missing they will be computed considering the field's name and the current
:doc:`naming strategy <namingstrategy>`.
Optional attributes:
- **name**: Column name that holds the foreign key identifier for
this relation. In the context of @JoinTable it specifies the column
name in the join table.
- **referencedColumnName**: Name of the primary key identifier that
is used for joining of this relation.
Optional attributes:
is used for joining of this relation. Defaults to *id*.
- **unique**: Determines whether this relation is exclusive between the
affected entities and should be enforced as such on the database
constraint level. Defaults to false.
+1 -1
View File
@@ -18,7 +18,7 @@ well.
Requirements
------------
Doctrine 2 requires a minimum of PHP 5.4. For greatly improved
Doctrine 2 requires a minimum of PHP 7.1. For greatly improved
performance it is also recommended that you use APC with PHP.
Doctrine 2 Packages
+4 -4
View File
@@ -18,9 +18,9 @@ This chapter is split into three different sections.
One tip for working with relations is to read the relation from left to right, where the left word refers to the current Entity. For example:
- OneToMany - One instance of the current Entity has Many instances (references) to the refered Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the refered Entity.
- OneToOne - One instance of the current Entity refers to One instance of the refered Entity.
- OneToMany - One instance of the current Entity has Many instances (references) to the referred Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the referred Entity.
- OneToOne - One instance of the current Entity refers to One instance of the referred Entity.
See below for all the possible relations.
@@ -286,7 +286,7 @@ below.
// ...
/**
* One Student has One Student.
* One Student has One Mentor.
* @OneToOne(targetEntity="Student")
* @JoinColumn(name="mentor_id", referencedColumnName="id")
*/
+3 -3
View File
@@ -270,7 +270,7 @@ A cookbook article shows how to define :doc:`your own custom mapping types
.. warning::
All Date types assume that you are exclusively using the default timezone
set by `date_default_timezone_set() <http://docs.php.net/manual/en/function.date-default-timezone-set.php>`_
set by `date_default_timezone_set() <http://php.net/manual/en/function.date-default-timezone-set.php>`_
or by the php.ini configuration ``date.timezone``. Working with
different timezones will cause troubles and unexpected behavior.
@@ -328,8 +328,8 @@ annotation.
In most cases using the automatic generator strategy (``@GeneratedValue``) is
what you want. It defaults to the identifier generation mechanism your current
database vendor prefers: AUTO_INCREMENT with MySQL, SERIAL with PostgreSQL,
Sequences with Oracle and so on.
database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL
and Oracle and so on.
Identifier Generation Strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+11 -2
View File
@@ -16,6 +16,15 @@ especially what the strategies presented here provide help with.
operations.
.. note::
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
To avoid that you should disable it in the DBAL configuration:
.. code-block:: php
<?php
$em->getConnection()->getConfiguration()->setSQLLogger(null);
Bulk Inserts
------------
@@ -75,7 +84,7 @@ with the batching strategy that was already used for bulk inserts:
<?php
$batchSize = 20;
$i = 0;
$i = 1;
$q = $em->createQuery('select u from MyProject\Model\User u');
$iterableResult = $q->iterate();
foreach ($iterableResult as $row) {
@@ -136,7 +145,7 @@ The following example shows how to do this:
<?php
$batchSize = 20;
$i = 0;
$i = 1;
$q = $em->createQuery('select u from MyProject\Model\User u');
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
+47 -54
View File
@@ -29,10 +29,10 @@ abstract protected methods that each of the drivers must
implement:
- \_doFetch($id)
- \_doContains($id)
- \_doSave($id, $data, $lifeTime = false)
- \_doDelete($id)
- doFetch($id)
- doContains($id)
- doSave($id, $data, $lifeTime = false)
- doDelete($id)
The public methods ``fetch()``, ``contains()`` etc. use the
above protected methods which are implemented by the drivers. The
@@ -43,43 +43,31 @@ these methods.
This documentation does not cover every single cache driver included
with Doctrine. For an up-to-date-list, see the
`cache directory on GitHub <https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache>`.
`cache directory on GitHub <https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache>`_.
APC
~~~
PhpFileCache
~~~~~~~~~~~~
In order to use the APC cache driver you must have it compiled and
enabled in your php.ini. You can read about APC
`in the PHP Documentation <http://us2.php.net/apc>`_. It will give
you a little background information about what it is and how you
can use it as well as how to install it.
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file. This allows for
opcode caching to be used and provides high performance in most scenarios.
Below is a simple example of how you could use the APC cache driver
by itself.
In order to use the ``PhpFileCache`` driver it must be able to write to
a directory.
Below is an example of how to use the ``PhpFileCache`` driver by itself.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\ApcCache();
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$cacheDriver->save('cache_id', 'my_data');
APCu
~~~~
In order to use the APCu cache driver you must have it compiled and
enabled in your php.ini. You can read about APCu
`in the PHP Documentation <http://us2.php.net/apcu>`_. It will give
you a little background information about what it is and how you
can use it as well as how to install it.
Below is a simple example of how you could use the APCu cache driver
by itself.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\ApcuCache();
$cacheDriver->save('cache_id', 'my_data');
The PhpFileCache is not distributed across multiple machines if you are running
your application in a distributed setup. This is ok for the metadata and query
cache but is not a good approach for the result cache.
Memcache
~~~~~~~~
@@ -128,24 +116,6 @@ driver by itself.
$cacheDriver->setMemcached($memcached);
$cacheDriver->save('cache_id', 'my_data');
Xcache
~~~~~~
In order to use the Xcache cache driver you must have it compiled
and enabled in your php.ini. You can read about Xcache
`here <http://xcache.lighttpd.net/>`_. It will give you a little
background information about what it is and how you can use it as
well as how to install it.
Below is a simple example of how you could use the Xcache cache
driver by itself.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\XcacheCache();
$cacheDriver->save('cache_id', 'my_data');
Redis
~~~~~
@@ -282,6 +252,8 @@ You can set the namespace a cache driver should use by using the
<?php
$cacheDriver->setNamespace('my_namespace_');
.. _integrating-with-the-orm:
Integrating with the ORM
------------------------
@@ -304,8 +276,11 @@ use on your ORM configuration.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
$config->setQueryCacheImpl($cacheDriver);
Result Cache
~~~~~~~~~~~~
@@ -318,7 +293,11 @@ cache implementation.
.. code-block:: php
<?php
$config->setResultCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$config->setResultCacheImpl($cacheDriver);
Now when you're executing DQL queries you can configure them to use
the result cache.
@@ -335,7 +314,11 @@ result cache driver.
.. code-block:: php
<?php
$query->setResultCacheDriver(new \Doctrine\Common\Cache\ApcuCache());
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$query->setResultCacheDriver($cacheDriver);
.. note::
@@ -387,7 +370,11 @@ first.
.. code-block:: php
<?php
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataCacheImpl($cacheDriver);
Now the metadata information will only be parsed once and stored in
the cache driver.
@@ -423,6 +410,12 @@ To clear the result cache use the ``orm:clear-cache:result`` task.
All these tasks accept a ``--flush`` option to flush the entire
contents of the cache instead of invalidating the entries.
.. note::
None of these tasks will work with APC, APCu, or XCache drivers
because the memory that the cache is stored in is only accessible
to the webserver.
Cache Chaining
--------------
@@ -71,8 +71,8 @@ follows:
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged,
Doctrine\Persistence\PropertyChangedListener;
/**
* @Entity
+3 -7
View File
@@ -1,9 +1,7 @@
Installation and Configuration
==============================
Doctrine can be installed with `Composer <http://www.getcomposer.org>`_. For
older versions we still have `PEAR packages
<http://pear.doctrine-project.org>`_.
Doctrine can be installed with `Composer <https://getcomposer.org>`_.
Define the following requirement in your ``composer.json`` file:
@@ -16,8 +14,7 @@ Define the following requirement in your ``composer.json`` file:
}
Then call ``composer install`` from your command line. If you don't know
how Composer works, check out their `Getting Started
<http://getcomposer.org/doc/00-intro.md>`_ to set up.
how Composer works, check out their `Getting Started <https://getcomposer.org/doc/00-intro.md>`_ to set up.
Class loading
-------------
@@ -93,8 +90,7 @@ Inside the ``Setup`` methods several assumptions are made:
- If `$isDevMode` is false, set then proxy classes have to be explicitly created through the command line.
- If third argument `$proxyDir` is not set, use the systems temporary directory.
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced
Configuration <reference/advanced-configuration>` section.
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration <reference/advanced-configuration>` section.
.. note::
@@ -103,15 +103,15 @@ their inclusion in the SELECT clause.
In this case, the result will be an array of arrays. In the example
above, each element of the result array would be an array of the
scalar name and address values.
scalar name and address values.
You can select scalars from any entity in the query.
You can select scalars from any entity in the query.
**Mixed**
.. code-block:: sql
``SELECT u, p.quantity FROM Users u...``
SELECT u, p.quantity FROM Users u...
Here, the result will again be an array of arrays, with each element
being an array made up of a User object and the scalar value
@@ -250,7 +250,7 @@ Retrieve the Username and Name of a CmsUser:
$users = $query->getResult(); // array of CmsUser username and name values
echo $users[0]['username'];
Retrieve a ForumUser and his single associated entity:
Retrieve a ForumUser and its single associated entity:
.. code-block:: php
@@ -259,7 +259,7 @@ Retrieve a ForumUser and his single associated entity:
$users = $query->getResult(); // array of ForumUser objects with the avatar association loaded
echo get_class($users[0]->getAvatar());
Retrieve a CmsUser and fetch join all the phonenumbers he has:
Retrieve a CmsUser and fetch join all the phonenumbers it has:
.. code-block:: php
@@ -491,7 +491,7 @@ Joins between entities without associations were not possible until version
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Blacklist b WITH u.email = b.email');
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
.. note::
The differences between WHERE, WITH and HAVING clauses may be
@@ -691,8 +691,8 @@ clauses:
- TRIM([LEADING \| TRAILING \| BOTH] ['trchar' FROM] str) - Trim
the string by the given trim char, defaults to whitespaces.
- UPPER(str) - Return the upper-case of the given string.
- DATE_ADD(date, days, unit) - Add the number of days to a given date. (Supported units are DAY, MONTH)
- DATE_SUB(date, days, unit) - Substract the number of days from a given date. (Supported units are DAY, MONTH)
- DATE_ADD(date, value, unit) - Add the given time to a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)
- DATE_SUB(date, value, unit) - Subtract the given time from a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)
- DATE_DIFF(date1, date2) - Calculate the difference in days between date1-date2.
Arithmetic operators
@@ -996,8 +996,9 @@ the Query class. Here they are:
result contains more than one object, an ``NonUniqueResultException``
is thrown. If the result contains no objects, an ``NoResultException``
is thrown. The pure/mixed distinction does not apply.
- ``Query#getOneOrNullResult()``: Retrieve a single object. If no
object is found null will be returned.
- ``Query#getOneOrNullResult()``: Retrieve a single object. If the
result contains more than one object, a ``NonUniqueResultException``
is thrown. If no object is found null will be returned.
- ``Query#getArrayResult()``: Retrieves an array graph (a nested
array) that is largely interchangeable with the object graph
generated by ``Query#getResult()`` for read-only purposes.
@@ -1172,7 +1173,7 @@ why we are listing as many of the assumptions here for reference:
- If an object is already in memory from a previous query of any kind, then
then the previous object is used, even if the database may contain more
recent data. Data from the database is discarded. This even happens if the
previous object is still an unloaded proxy.
previous object is still an unloaded proxy.
This list might be incomplete.
@@ -1452,10 +1453,10 @@ Given that there are 10 users and corresponding addresses in the database the ex
SELECT * FROM address WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
.. note::
Changing the fetch mode during a query mostly makes sense for one-to-one and many-to-one relations. In that case,
Changing the fetch mode during a query mostly makes sense for one-to-one and many-to-one relations. In that case,
all the necessary IDs are available after the root entity (``user`` in the above example) has been loaded. So, one
query per association can be executed to fetch all the referred-to entities (``address``).
For one-to-many relations, changing the fetch mode to eager will cause to execute one query **for every root entity
loaded**. This gives no improvement over the ``lazy`` fetch mode which will also initialize the associations on
a one-by-one basis once they are accessed.
+56 -47
View File
@@ -145,49 +145,53 @@ An example for a correct notation can be found in the example
Lifecycle Events
----------------
The EntityManager and UnitOfWork trigger a bunch of events during
the life-time of their registered entities.
The ``EntityManager`` and ``UnitOfWork`` classes trigger a bunch of
events during the life-time of their registered entities.
- preRemove - The preRemove event occurs for a given entity before
the respective EntityManager remove operation for that entity is
executed. It is not called for a DQL DELETE statement.
- postRemove - The postRemove event occurs for an entity after the
- ``preRemove`` - The ``preRemove`` event occurs for a given entity
before the respective ``EntityManager`` remove operation for that
entity is executed. It is not called for a DQL ``DELETE`` statement.
- ``postRemove`` - The ``postRemove`` event occurs for an entity after the
entity has been deleted. It will be invoked after the database
delete operations. It is not called for a DQL DELETE statement.
- prePersist - The prePersist event occurs for a given entity
before the respective EntityManager persist operation for that
delete operations. It is not called for a DQL ``DELETE`` statement.
- ``prePersist`` - The ``prePersist`` event occurs for a given entity
before the respective ``EntityManager`` persist operation for that
entity is executed. It should be noted that this event is only triggered on
*initial* persist of an entity (i.e. it does not trigger on future updates).
- postPersist - The postPersist event occurs for an entity after
- ``postPersist`` - 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.
- preUpdate - The preUpdate event occurs before the database
update operations to entity data. It is not called for a DQL UPDATE statement
nor when the computed changeset is empty.
- postUpdate - The postUpdate event occurs after the database
update operations to entity data. It is not called for a DQL UPDATE statement.
- postLoad - The postLoad event occurs for an entity after the
entity has been loaded into the current EntityManager from the
- ``preUpdate`` - The ``preUpdate`` event occurs before the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement nor when the computed changeset is empty.
- ``postUpdate`` - The ``postUpdate`` event occurs after the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement.
- ``postLoad`` - 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.
- loadClassMetadata - The loadClassMetadata event occurs after the
- ``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
mapping metadata for a class has been loaded from a mapping source
(annotations/xml/yaml). This event is not a lifecycle callback.
- onClassMetadataNotFound - Loading class metadata for a particular
- ``onClassMetadataNotFound`` - Loading class metadata for a particular
requested class name failed. Manipulating the given event args instance
allows providing fallback metadata even when no actual metadata exists
or could be found. This event is not a lifecycle callback.
- preFlush - The preFlush event occurs at the very beginning of a flush
operation.
- onFlush - The onFlush event occurs after the change-sets of all
- ``preFlush`` - The ``preFlush`` event occurs at the very beginning of
a flush operation.
- ``onFlush`` - The ``onFlush`` event occurs after the change-sets of all
managed entities are computed. This event is not a lifecycle
callback.
- postFlush - The postFlush event occurs at the end of a flush operation. This
- ``postFlush`` - The ``postFlush`` event occurs at the end of a flush operation. This
event is not a lifecycle callback.
- onClear - The onClear event occurs when the EntityManager#clear() operation is
invoked, after all references to entities have been removed from the unit of
work. This event is not a lifecycle callback.
- ``onClear`` - The ``onClear`` event occurs when the
``EntityManager#clear()`` operation is invoked, after all references
to entities have been removed from the unit of work. This event is not
a lifecycle callback.
.. warning::
@@ -199,7 +203,7 @@ the life-time of their registered entities.
.. warning::
Note that the postRemove event or any events triggered after an entity removal
Note that the ``postRemove`` event or any events triggered after an entity removal
can receive an uninitializable proxy in case you have configured an entity to
cascade remove relations. In this case, you should load yourself the proxy in
the associated pre event.
@@ -222,13 +226,13 @@ listeners:
- Lifecycle Event Listeners and Subscribers are classes with specific callback
methods that receives some kind of ``EventArgs`` instance.
The EventArgs instance received by the listener gives access to the entity,
EntityManager and other relevant data.
The ``EventArgs`` instance received by the listener gives access to the entity,
``EntityManager`` instance and other relevant data.
.. note::
All Lifecycle events that happen during the ``flush()`` of
an EntityManager have very specific constraints on the allowed
an ``EntityManager`` have very specific constraints on the allowed
operations that can be executed. Please read the
:ref:`reference-events-implementing-listeners` section very carefully
to understand which operations are allowed in which lifecycle event.
@@ -243,6 +247,11 @@ a relevant lifecycle event. More than one callback can be defined for each
lifecycle event. Lifecycle Callbacks are best used for simple operations
specific to a particular entity class's lifecycle.
.. note::
Note that Licecycle Callbacks are not supported for Embeddables.
.. code-block:: php
<?php
@@ -405,9 +414,9 @@ sit at a level above the entities and allow you to implement re-usable
behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner
workings of the EntityManager and UnitOfWork. Please read the
:ref:`reference-events-implementing-listeners` section carefully if you
are trying to write your own listener.
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
read the :ref:`reference-events-implementing-listeners` section
carefully if you are trying to write your own listener.
For event subscribers, there are no surprises. They declare the
lifecycle events in their ``getSubscribedEvents`` method and provide
@@ -418,7 +427,7 @@ A lifecycle event listener looks like the following:
.. code-block:: php
<?php
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventListener
{
@@ -440,8 +449,8 @@ A lifecycle event subscriber may look like this:
<?php
use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\EventSubscriber;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventSubscriber implements EventSubscriber
{
@@ -496,16 +505,16 @@ Implementing Event Listeners
----------------------------
This section explains what is and what is not allowed during
specific lifecycle events of the UnitOfWork. Although you get
passed the EntityManager in all of these events, you have to follow
these restrictions very carefully since operations in the wrong
event may produce lots of different errors, such as inconsistent
specific lifecycle events of the ``UnitOfWork`` class. Although you get
passed the ``EntityManager`` instance in all of these events, you have
to follow these restrictions very carefully since operations in the
wrong event may produce lots of different errors, such as inconsistent
data and lost updates/persists/removes.
For the described events that are also lifecycle callback events
the restrictions apply as well, with the additional restriction
that (prior to version 2.4) you do not have access to the
EntityManager or UnitOfWork APIs inside these events.
``EntityManager`` or ``UnitOfWork`` APIs inside these events.
prePersist
~~~~~~~~~~
@@ -548,8 +557,9 @@ preFlush
~~~~~~~~
``preFlush`` is called at ``EntityManager#flush()`` before
anything else. ``EntityManager#flush()`` can be called safely
inside its listeners.
anything else. ``EntityManager#flush()`` should not be called inside
its listeners, since `preFlush` event is dispatched in it, which would
result in infinite loop.
.. code-block:: php
@@ -580,8 +590,8 @@ entities and their associations have been computed. This means, the
- Collections scheduled for update
- Collections scheduled for removal
To make use of the onFlush event you have to be familiar with the
internal UnitOfWork API, which grants you access to the previously
To make use of the ``onFlush`` event you have to be familiar with the
internal ``UnitOfWork`` API, which grants you access to the previously
mentioned sets. See this example:
.. code-block:: php
@@ -729,7 +739,7 @@ Restrictions for this event:
the event to modify primitive field values, e.g. use
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
- Any calls to ``EntityManager#persist()`` or
``EntityManager#remove()``, even in combination with the UnitOfWork
``EntityManager#remove()``, even in combination with the ``UnitOfWork``
API are strongly discouraged and don't work as expected outside the
flush operation.
@@ -985,4 +995,3 @@ process and manipulate the instance.
}
}
+15
View File
@@ -198,6 +198,21 @@ No, it is not supported to sort by function in DQL. If you need this functionali
use a native-query or come up with another solution. As a side note: Sorting with ORDER BY RAND() is painfully slow
starting with 1000 rows.
Is it better to write DQL or to generate it with the query builder?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The purpose of the ``QueryBuilder`` is to generate DQL dynamically,
which is useful when you have optional filters, conditional joins, etc.
But the ``QueryBuilder`` is not an alternative to DQL, it actually generates DQL
queries at runtime, which are then interpreted by Doctrine. This means that
using the ``QueryBuilder`` to build and run a query is actually always slower
than only running the corresponding DQL query.
So if you only need to generate a query and bind parameters to it,
you should use plain DQL, as this is a simpler and much more readable solution.
You should only use the ``QueryBuilder`` when you can't achieve what you want to do with a DQL query.
A Query fails, how can I debug it?
----------------------------------
+1 -1
View File
@@ -39,7 +39,7 @@ proper quoting of parameters.
<?php
namespace Example;
use Doctrine\ORM\Mapping\ClassMetaData,
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Query\Filter\SQLFilter;
class MyLocaleFilter extends SQLFilter
+14 -4
View File
@@ -4,7 +4,7 @@ Improving Performance
Bytecode Cache
--------------
It is highly recommended to make use of a bytecode cache like APC.
It is highly recommended to make use of a bytecode cache like OPcache.
A bytecode cache removes the need for parsing PHP code on every
request and can greatly improve performance.
@@ -20,12 +20,19 @@ Metadata and Query caches
As already mentioned earlier in the chapter about configuring
Doctrine, it is strongly discouraged to use Doctrine without a
Metadata and Query cache (preferably with APC or Memcache as the
cache driver). Operating Doctrine without these caches means
Metadata and Query cache.
Operating Doctrine without these caches means
Doctrine will need to load your mapping information on every single
request and has to parse each DQL query on every single request.
This is a waste of resources.
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file.
This allows for opcode caching to be used and provides high performance in most scenarios.
See :ref:`integrating-with-the-orm`
Alternative Query Result Formats
--------------------------------
@@ -42,6 +49,8 @@ for updates, which means when you call flush on the EntityManager these entities
even if properties changed. Read-Only allows to persist new entities of a kind and remove existing
ones, they are just not considered for updates.
See :ref:`annref_entity`
Extra-Lazy Collections
----------------------
@@ -52,7 +61,7 @@ for more information on how this fetch mode works.
Temporarily change fetch mode in DQL
------------------------------------
See :ref:`Doctrine Query Language chapter <dql-temporarily-change-fetch-mode>`
See :ref:`dql-temporarily-change-fetch-mode`
Apply Best Practices
@@ -61,6 +70,7 @@ Apply Best Practices
A lot of the points mentioned in the Best Practices chapter will
also positively affect the performance of Doctrine.
See :doc:`Best Practices <reference/best-practices>`
Change Tracking policies
------------------------
+2 -2
View File
@@ -174,7 +174,7 @@ SQL Schema considerations
For Single-Table-Inheritance to work in scenarios where you are
using either a legacy database schema or a self-written database
schema you have to make sure that all columns that are not in the
root entity but in any of the different sub-entities has to allows
root entity but in any of the different sub-entities has to allow
null values. Columns that have NOT NULL constraints have to be on
the root entity of the single-table inheritance hierarchy.
@@ -584,7 +584,7 @@ Things to note:
- The "attribute override" specifies the overrides base on the property name.
- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException``
- The override can redefine all the columns except the type.
- The override can redefine all the attributes except the type.
Query the Type
--------------
+1 -2
View File
@@ -1,5 +1,4 @@
Installation
============
The installation chapter has moved to `Installation and Configuration
<reference/configuration>`_.
The installation chapter has moved to :doc:`Installation and Configuration <reference/configuration>`_.
@@ -63,7 +63,7 @@ Where the ``attribute_name`` column contains the key and
``$attributes``.
The feature request for persistence of primitive value arrays
`is described in the DDC-298 ticket <https://github.com/doctrine/doctrine2/issues/3743>`_.
`is described in the DDC-298 ticket <https://github.com/doctrine/orm/issues/3743>`_.
Cascade Merge with Bi-directional Associations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -71,8 +71,8 @@ Cascade Merge with Bi-directional Associations
There are two bugs now that concern the use of cascade merge in combination with bi-directional associations.
Make sure to study the behavior of cascade merge if you are using it:
- `DDC-875 <https://github.com/doctrine/doctrine2/issues/5398>`_ Merge can sometimes add the same entity twice into a collection
- `DDC-763 <https://github.com/doctrine/doctrine2/issues/5277>`_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability"
- `DDC-875 <https://github.com/doctrine/orm/issues/5398>`_ Merge can sometimes add the same entity twice into a collection
- `DDC-763 <https://github.com/doctrine/orm/issues/5277>`_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability"
Custom Persisters
~~~~~~~~~~~~~~~~~
@@ -83,8 +83,8 @@ Currently there is no way to overwrite the persister implementation
for a given entity, however there are several use-cases that can
benefit from custom persister implementations:
- `Add Upsert Support <https://github.com/doctrine/doctrine2/issues/5178>`_
- `Evaluate possible ways in which stored-procedures can be used <https://github.com/doctrine/doctrine2/issues/4946>`_
- `Add Upsert Support <https://github.com/doctrine/orm/issues/5178>`_
- `Evaluate possible ways in which stored-procedures can be used <https://github.com/doctrine/orm/issues/4946>`_
Persist Keys of Collections
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -94,7 +94,7 @@ PHP Arrays are ordered hash-maps and so should be the
evaluate a feature that optionally persists and hydrates the keys
of a Collection instance.
`Ticket DDC-213 <https://github.com/doctrine/doctrine2/issues/2817>`_
`Ticket DDC-213 <https://github.com/doctrine/orm/issues/2817>`_
Mapping many tables to one entity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -116,7 +116,6 @@ blog posts we have written on this topics:
- `A re-usable Versionable behavior for Doctrine2 <http://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html>`_
- `Write your own ORM on top of Doctrine2 <http://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html>`_
- `Doctrine 2 Behavioral Extensions <http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
- `Doctrator <https://github.com/pablodip/doctrator`>_
Doctrine 2 has enough hooks and extension points so that **you** can
add whatever you want on top of it. None of this will ever become
@@ -144,8 +143,7 @@ backwards compatibility issues or where no simple fix exists (yet).
We don't plan to add every bug in the tracker there, just those
issues that can potentially cause nightmares or pain of any sort.
See bugs, improvement and feature requests on `Github issues
<https://github.com/doctrine/doctrine2/issues>`_.
See bugs, improvement and feature requests on `Github issues <https://github.com/doctrine/orm/issues>`_.
Identifier Quoting and Legacy Databases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+5 -1
View File
@@ -4,9 +4,13 @@ Implementing a NamingStrategy
.. versionadded:: 2.3
Using a naming strategy you can provide rules for generating database identifiers,
column or table names when the column or table name is not given. This feature helps
column or table names. This feature helps
reduce the verbosity of the mapping document, eliminating repetitive noise (eg: ``TABLE_``).
.. warning
The naming strategy is always overridden by entity mapping such as the `Table` annotation.
Configuring a naming strategy
-----------------------------
The default strategy used by Doctrine is quite minimal.
+1 -1
View File
@@ -92,7 +92,7 @@ a mapping from DQL alias (key) to SQL alias (value)
<?php
$selectClause = $builder->generateSelectClause(array(
$selectClause = $rsm->generateSelectClause(array(
'u' => 't1',
'g' => 't2'
));
+26 -7
View File
@@ -9,6 +9,12 @@ programmatically build queries, and also provides a fluent API.
This means that you can change between one methodology to the other
as you want, or just pick a preferred one.
.. note::
The ``QueryBuilder`` is not an abstraction of DQL, but merely a tool to dynamically build it.
You should still use plain DQL when you can, as it is simpler and more readable.
More about this in the :doc:`FAQ <faq>`_.
Constructing a new QueryBuilder object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -80,7 +86,7 @@ Working with QueryBuilder
High level API methods
^^^^^^^^^^^^^^^^^^^^^^
To simplify even more the way you build a query in Doctrine, you can take
The most straightforward way to build a dynamic query with the ``QueryBuilder`` is by taking
advantage of Helper methods. For all base code, there is a set of
useful methods to simplify a programmer's life. To illustrate how
to work with them, here is the same example 6 re-written using
@@ -97,10 +103,9 @@ to work with them, here is the same example 6 re-written using
->orderBy('u.name', 'ASC');
``QueryBuilder`` helper methods are considered the standard way to
build DQL queries. Although it is supported, using string-based
queries should be avoided. You are greatly encouraged to use
``$qb->expr()->*`` methods. Here is a converted example 8 to
suggested standard way to build queries:
use the ``QueryBuilder``. The ``$qb->expr()->*`` methods can help you
build conditional expressions dynamically. Here is a converted example 8 to
suggested way to build queries with dynamic conditions:
.. code-block:: php
@@ -250,6 +255,21 @@ and for managed entities. If you want to set a type explicitly you can call
the third argument to ``setParameter()`` explicitly. It accepts either a PDO
type or a DBAL Type name for conversion.
.. note::
Even though passing DateTime instance is allowed, it impacts performance
as by default there is an attempt to load metadata for object, and if it's not found,
type is inferred from the original value.
.. code-block:: php
<?php
use Doctrine\DBAL\Types\Types;
// prevents attempt to load metadata for date time class, improving performance
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATE_IMMUTABLE)
If you've got several parameters to bind to your query, you can
also use setParameters() instead of setParameter() with the
following syntax:
@@ -502,7 +522,7 @@ complete list of supported helper methods available:
Adding a Criteria to a Query
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also add a :ref:`Criteria <filtering-collections>` to a QueryBuilder by
You can also add a :ref:`filtering-collections` to a QueryBuilder by
using ``addCriteria``:
.. code-block:: php
@@ -576,4 +596,3 @@ same query of example 6 written using
->add('from', new Expr\From('User', 'u'))
->add('where', new Expr\Comparison('u.id', '=', '?1'))
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
+5 -5
View File
@@ -97,7 +97,7 @@ Defines a contract for accessing a particular region.
Defines a contract for accessing a particular cache region.
`See API Doc <http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.Cache.Region.html>`_.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Region.html>`_.
Concurrent cache region
~~~~~~~~~~~~~~~~~~~~~~~
@@ -111,7 +111,7 @@ If you want to use an ``READ_WRITE`` cache, you should consider providing your o
Defines contract for concurrently managed data region.
`See API Doc <http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.Cache.ConcurrentRegion.html>`_.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/ConcurrentRegion.html>`_.
Timestamp region
~~~~~~~~~~~~~~~~
@@ -120,7 +120,7 @@ Timestamp region
Tracks the timestamps of the most recent updates to particular entity.
`See API Doc <http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.Cache.TimestampRegion.html>`_.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/TimestampRegion.html>`_.
.. _reference-second-level-cache-mode:
@@ -209,7 +209,7 @@ It allows you to provide a specific implementation of the following components :
* ``EntityHydrator`` Transform an entity into a cache entry and cache entry into entities
* ``CollectionHydrator`` Transform a collection into a cache entry and cache entry into collection
`See API Doc <http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.Cache.DefaultCacheFactory.html>`_.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/DefaultCacheFactory.html>`_.
Region Lifetime
~~~~~~~~~~~~~~~
@@ -270,7 +270,7 @@ By providing a cache logger you should be able to get information about all cach
If you want to get more information you should implement ``\Doctrine\ORM\Cache\Logging\CacheLogger``.
and collect all information you want.
`See API Doc <http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.Cache.CacheLogger.html>`_.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Logging/CacheLogger.html>`_.
Entity cache definition
+2 -2
View File
@@ -10,7 +10,7 @@ we cannot protect you from SQL injection.
Please also read the documentation chapter on Security in Doctrine DBAL. This
page only handles Security issues in the ORM.
- [DBAL Security Page](https://github.com/doctrine/dbal/blob/master/docs/en/reference/security.rst)
- `DBAL Security Page <http://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html>`
If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core
@@ -119,7 +119,7 @@ entity might look like this:
}
Now the possiblity of mass-asignment exists on this entity and can
be exploitet by attackers to set the "isAdmin" flag to true on any
be exploited by attackers to set the "isAdmin" flag to true on any
object when you pass the whole request data to this method like:
.. code-block:: php
-9
View File
@@ -252,15 +252,6 @@ will output the SQL for the ran operation.
Before using the orm:schema-tool commands, remember to configure
your cli-config.php properly.
.. note::
When using the Annotation Mapping Driver you have to either setup
your autoloader in the cli-config.php correctly to find all the
entities, or you can use the second argument of the
``EntityManagerHelper`` to specify all the paths of your entities
(or mapping files), i.e.
``new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em, $mappingPaths);``
Entity Generation
-----------------
@@ -39,7 +39,7 @@ side of the association and these 2 references both represent the
same association but can change independently of one another. Of
course, in a correct application the semantics of the bidirectional
association are properly maintained by the application developer
(that's his responsibility). Doctrine needs to know which of these
(that's their responsibility). Doctrine needs to know which of these
two in-memory references is the one that should be persisted and
which not. This is what the owning/inverse concept is mainly used
for.
+3 -3
View File
@@ -148,15 +148,15 @@ Hydration
~~~~~~~~~
Responsible for creating a final result from a raw database statement and a
result-set mapping object. The developer can choose which kind of result he
wishes to be hydrated. Default result-types include:
result-set mapping object. The developer can choose which kind of result they
wish to be hydrated. Default result-types include:
- SQL to Entities
- SQL to structured Arrays
- SQL to simple scalar result arrays
- SQL to a single result variable
Hydration to entities and arrays is one of most complex parts of Doctrine
Hydration to entities and arrays is one of the most complex parts of Doctrine
algorithm-wise. It can build results with for example:
- Single table selects
@@ -716,6 +716,7 @@ methods:
* ``in($field, array $values)``
* ``notIn($field, array $values)``
* ``contains($field, $value)``
* ``memberOf($value, $field)``
* ``startsWith($field, $value)``
* ``endsWith($field, $value)``
+23 -8
View File
@@ -245,11 +245,17 @@ as follows:
persist operation. However, the persist operation is cascaded to
entities referenced by X, if the relationships from X to these
other entities are mapped with cascade=PERSIST or cascade=ALL (see
":ref:`Transitive Persistence <transitive-persistence>`").
":ref:`transitive-persistence`").
- If X is a removed entity, it becomes managed.
- If X is a detached entity, an exception will be thrown on
flush.
.. caution::
Do not pass detached entities to the persist operation. The persist operation always
considers entities that are not yet known to the ``EntityManager`` as new entities
(refer to the ``STATE_NEW`` constant inside the ``UnitOfWork``).
Removing entities
-----------------
@@ -286,12 +292,12 @@ as follows:
- If X is a new entity, it is ignored by the remove operation.
However, the remove operation is cascaded to entities referenced by
X, if the relationship from X to these other entities is mapped
with cascade=REMOVE or cascade=ALL (see ":ref:`Transitive Persistence <transitive-persistence>`").
with cascade=REMOVE or cascade=ALL (see ":ref:`transitive-persistence`").
- If X is a managed entity, the remove operation causes it to
become removed. The remove operation is cascaded to entities
referenced by X, if the relationships from X to these other
entities is mapped with cascade=REMOVE or cascade=ALL (see
":ref:`Transitive Persistence <transitive-persistence>`").
":ref:`transitive-persistence`").
- If X is a detached entity, an InvalidArgumentException will be
thrown.
- If X is a removed entity, it is ignored by the remove operation.
@@ -315,7 +321,7 @@ in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine 2
will fetch this association. If its a Single association it will
pass this entity to
´EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()\`.
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
In both cases the cascade remove semantics are applied recursively.
For large object graphs this removal strategy can be very costly.
2. Using a DQL ``DELETE`` statement allows you to delete multiple
@@ -330,6 +336,13 @@ in multiple ways with very different performance impacts.
because Doctrine will fetch and remove all associated entities
explicitly nevertheless.
.. note::
Calling ``remove`` on an entity will remove the object from the identiy
map and therefore detach it. Querying the same entity again, for example
via a lazy loaded relation, will return a new object.
Detaching entities
------------------
@@ -357,14 +370,14 @@ as follows:
become detached. The detach operation is cascaded to entities
referenced by X, if the relationships from X to these other
entities is mapped with cascade=DETACH or cascade=ALL (see
":ref:`Transitive Persistence <transitive-persistence>`"). Entities which previously referenced X
":ref:`transitive-persistence`"). Entities which previously referenced X
will continue to reference X.
- If X is a new or detached entity, it is ignored by the detach
operation.
- If X is a removed entity, the detach operation is cascaded to
entities referenced by X, if the relationships from X to these
other entities is mapped with cascade=DETACH or cascade=ALL (see
":ref:`Transitive Persistence <transitive-persistence>`"). Entities which previously referenced X
":ref:`transitive-persistence`"). Entities which previously referenced X
will continue to reference X.
There are several situations in which an entity is detached
@@ -423,7 +436,7 @@ as follows:
- If X is a managed entity, it is ignored by the merge operation,
however, the merge operation is cascaded to entities referenced by
relationships from X if these relationships have been mapped with
the cascade element value MERGE or ALL (see ":ref:`Transitive Persistence <transitive-persistence>`").
the cascade element value MERGE or ALL (see ":ref:`transitive-persistence`").
- For all entities Y referenced by relationships from X having the
cascade element value MERGE or ALL, Y is merged recursively as Y'.
For all such Y referenced by X, X' is set to reference Y'. (Note
@@ -800,7 +813,9 @@ DQL and its syntax as well as the Doctrine class can be found in
:doc:`the dedicated chapter <dql-doctrine-query-language>`.
For programmatically building up queries based on conditions that
are only known at runtime, Doctrine provides the special
``Doctrine\ORM\QueryBuilder`` class. More information on
``Doctrine\ORM\QueryBuilder`` class. While this a powerful tool,
it also brings more complexity to your code compared to plain DQL,
so you should only use it when you need it. More information on
constructing queries with a QueryBuilder can be found
:doc:`in Query Builder chapter <query-builder>`.
+83
View File
@@ -0,0 +1,83 @@
.. toc::
.. tocheader:: Tutorials
.. toctree::
:depth: 3
tutorials/getting-started
tutorials/getting-started-database
tutorials/getting-started-models
tutorials/working-with-indexed-associations
tutorials/extra-lazy-associations
tutorials/composite-primary-keys
tutorials/ordered-associations
tutorials/override-field-association-mappings-in-subclasses
tutorials/pagination
tutorials/embeddables
.. toc::
.. tocheader:: Reference
.. toctree::
:depth: 3
reference/architecture
reference/configuration
reference/faq
reference/basic-mapping
reference/association-mapping
reference/inheritance-mapping
reference/working-with-objects
reference/working-with-associations
reference/events
reference/unitofwork
reference/unitofwork-associations
reference/transactions-and-concurrency
reference/batch-processing
reference/dql-doctrine-query-language
reference/query-builder
reference/native-sql
reference/change-tracking-policies
reference/partial-objects
reference/xml-mapping
reference/yaml-mapping
reference/annotations-reference
reference/php-mapping
reference/caching
reference/improving-performance
reference/tools
reference/metadata-drivers
reference/best-practices
reference/limitations-and-known-issues
tutorials/pagination
reference/filters
reference/namingstrategy
reference/advanced-configuration
reference/second-level-cache
reference/security
.. toc::
.. tocheader:: Cookbook
.. toctree::
:depth: 3
cookbook/aggregate-fields
cookbook/custom-mapping-types
cookbook/decorator-pattern
cookbook/dql-custom-walkers
cookbook/dql-user-defined-functions
cookbook/implementing-arrayaccess-for-domain-objects
cookbook/implementing-the-notify-changetracking-policy
cookbook/implementing-wakeup-or-clone
cookbook/resolve-target-entity-listener
cookbook/sql-table-prefixes
cookbook/strategy-cookbook-introduction
cookbook/validation-of-entities
cookbook/working-with-datetime
cookbook/mysql-enums
cookbook/advanced-field-value-conversion-using-custom-mapping-types
cookbook/entities-in-session
-1
View File
@@ -75,7 +75,6 @@ Cookbook
cookbook/implementing-arrayaccess-for-domain-objects
cookbook/implementing-the-notify-changetracking-policy
cookbook/implementing-wakeup-or-clone
cookbook/integrating-with-codeigniter
cookbook/resolve-target-entity-listener
cookbook/sql-table-prefixes
cookbook/strategy-cookbook-introduction
+10 -1
View File
@@ -3,7 +3,7 @@ Extra Lazy Associations
.. versionadded:: 2.1
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog.
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog
where posts can be commented, you always have to assume that a post draws hundreds of comments.
In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This
can lead to pretty serious performance problems, if your associations contain several hundreds or thousands
@@ -35,6 +35,15 @@ With extra lazy collections you can now not only add entities to large collectio
easily using a combination of ``count`` and ``slice``.
.. warning::
``removeElement`` directly issued DELETE queries to the database from
version 2.4.0 to 2.7.0. This circumvents the flush operation and might run
outside a transactional boundary if you don't create one yourself. We
consider this a critical bug in the assumptio of how the ORM works and
reverted ``removeElement`` EXTRA_LAZY behavior in 2.7.1.
Enabling Extra-Lazy Associations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -7,7 +7,7 @@ Getting Started: Database First
start with developing Objects and then map them onto your database. When
you :doc:`Model First <getting-started-models>`, you are modelling your application using tools (for
example UML) and generate database schema and PHP code from this model.
When you have a :doc:`Database First <getting-started-database>`, you already have a database schema
When you have a Database First, you already have a database schema
and generate the corresponding PHP code from it.
.. note::
+1 -1
View File
@@ -5,7 +5,7 @@ Getting Started: Model First
When you :doc:`Code First <getting-started>`, you
start with developing Objects and then map them onto your database. When
you :doc:`Model First <getting-started-models>`, you are modelling your application using tools (for
you Model First, you are modelling your application using tools (for
example UML) and generate database schema and PHP code from this model.
When you have a :doc:`Database First <getting-started-database>`, then you already have a database schema
and generate the corresponding PHP code from it.
+101 -53
View File
@@ -19,7 +19,7 @@ installed:
- PHP (latest stable version)
- Composer Package Manager (`Install Composer
<http://getcomposer.org/doc/00-intro.md>`_)
<https://getcomposer.org/doc/00-intro.md>`_)
The code of this tutorial is `available on Github <https://github.com/doctrine/doctrine2-orm-tutorial>`_.
@@ -31,9 +31,8 @@ The code of this tutorial is `available on Github <https://github.com/doctrine/d
What is Doctrine?
-----------------
Doctrine 2 is an `object-relational mapper (ORM)
<http://en.wikipedia.org/wiki/Object-relational_mapping>`_ for PHP 5.4+ that
provides transparent persistence for PHP objects. It uses the Data Mapper
Doctrine 2 is an `object-relational mapper (ORM) <https://en.wikipedia.org/wiki/Object-relational_mapping>`_
for PHP 7.1+ that provides transparent persistence for PHP objects. It uses the Data Mapper
pattern at the heart, aiming for a complete separation of your domain/business
logic from the persistence in a relational database management system.
@@ -62,7 +61,7 @@ An Example Model: Bug Tracker
For this Getting Started Guide for Doctrine we will implement the
Bug Tracker domain model from the
`Zend\_Db\_Table <http://framework.zend.com/manual/1.12/en/zend.db.adapter.html>`_
`Zend_Db_Table <https://framework.zend.com/manual/1.12/en/zend.db.adapter.html>`_
documentation. Reading their documentation we can extract the
requirements:
@@ -73,7 +72,7 @@ requirements:
- Bug reporters and engineers are both Users of the system.
- A User can create new Bugs.
- The assigned engineer can close a Bug.
- A User can see all his reported or assigned Bugs.
- A User can see all their reported or assigned Bugs.
- Bugs can be paginated through a list-view.
Project Setup
@@ -139,7 +138,10 @@ step:
// Create a simple "default" Doctrine ORM configuration for Annotations
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode);
$proxyDir = null;
$cache = null;
$useSimpleAnnotationReader = false;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode, $proxyDir, $cache, $useSimpleAnnotationReader);
// or if you prefer yaml or XML
//$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);
@@ -157,6 +159,10 @@ step:
The YAML driver is deprecated and will be removed in version 3.0.
It is strongly recommended to switch to one of the other mappings.
.. note::
It is recommended not to use the SimpleAnnotationReader because its
usage will be removed for version 3.0.
The ``require_once`` statement sets up the class autoloading for Doctrine and
its dependencies using Composer's autoloader.
@@ -169,7 +175,7 @@ read up on the configuration details in the
The third block shows the configuration options required to connect to
a database. In this case, we'll use a file-based SQLite database. All the
configuration options for all the shipped drivers are given in the
`DBAL Configuration section of the manual <http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/>`_.
`DBAL Configuration section of the manual <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/>`_.
The last block shows how the ``EntityManager`` is obtained from a
factory method.
@@ -284,14 +290,24 @@ but you only need to choose one.
<?php
// src/Product.php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity @Table(name="products")
**/
* @ORM\Entity
* @ORM\Table(name="products")
*/
class Product
{
/** @Id @Column(type="integer") @GeneratedValue **/
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
protected $id;
/** @Column(type="string") **/
/**
* @ORM\Column(type="string")
*/
protected $name;
// .. (other code)
@@ -468,28 +484,36 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
<?php
// src/Bug.php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity(repositoryClass="BugRepository") @Table(name="bugs")
* @ORM\Table(name="bugs")
*/
class Bug
{
/**
* @Id @Column(type="integer") @GeneratedValue
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
* @var int
*/
protected $id;
/**
* @Column(type="string")
* @ORM\Column(type="string")
* @var string
*/
protected $description;
/**
* @Column(type="datetime")
* @ORM\Column(type="datetime")
* @var DateTime
*/
protected $created;
/**
* @Column(type="string")
* @ORM\Column(type="string")
* @var string
*/
protected $status;
@@ -534,18 +558,25 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
<?php
// src/User.php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity @Table(name="users")
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User
{
/**
* @Id @GeneratedValue @Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @var int
*/
protected $id;
/**
* @Column(type="string")
* @ORM\Column(type="string")
* @var string
*/
protected $name;
@@ -775,7 +806,7 @@ the database that points from Bugs to Products.
{
// ... (previous code)
protected $products = null;
protected $products;
public function assignToProduct(Product $product)
{
@@ -797,41 +828,50 @@ the ``Product`` before:
<?php
// src/Bug.php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity @Table(name="bugs")
**/
* @ORM\Entity
* @ORM\Table(name="bugs")
*/
class Bug
{
/**
* @Id @Column(type="integer") @GeneratedValue
**/
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
protected $id;
/**
* @Column(type="string")
**/
* @ORM\Column(type="string")
*/
protected $description;
/**
* @Column(type="datetime")
**/
* @ORM\Column(type="datetime")
*/
protected $created;
/**
* @Column(type="string")
**/
* @ORM\Column(type="string")
*/
protected $status;
/**
* @ManyToOne(targetEntity="User", inversedBy="assignedBugs")
**/
* @ORM\ManyToOne(targetEntity="User", inversedBy="assignedBugs")
*/
protected $engineer;
/**
* @ManyToOne(targetEntity="User", inversedBy="reportedBugs")
**/
* @ORM\ManyToOne(targetEntity="User", inversedBy="reportedBugs")
*/
protected $reporter;
/**
* @ManyToMany(targetEntity="Product")
**/
* @ORM\ManyToMany(targetEntity="Product")
*/
protected $products;
// ... (other code)
@@ -925,34 +965,40 @@ Finally, we'll add metadata mappings for the ``User`` entity.
<?php
// src/User.php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity @Table(name="users")
**/
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User
{
/**
* @Id @GeneratedValue @Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @var int
**/
*/
protected $id;
/**
* @Column(type="string")
* @ORM\Column(type="string")
* @var string
**/
*/
protected $name;
/**
* @OneToMany(targetEntity="Bug", mappedBy="reporter")
* @ORM\OneToMany(targetEntity="Bug", mappedBy="reporter")
* @var Bug[] An ArrayCollection of Bug objects.
**/
protected $reportedBugs = null;
*/
protected $reportedBugs;
/**
* @OneToMany(targetEntity="Bug", mappedBy="engineer")
* @ORM\OneToMany(targetEntity="Bug", mappedBy="engineer")
* @var Bug[] An ArrayCollection of Bug objects.
**/
protected $assignedBugs = null;
*/
protected $assignedBugs;
// .. (other code)
}
@@ -1163,8 +1209,7 @@ The console output of this script is then:
throw your ORM into the dumpster, because it doesn't support some
the more powerful SQL concepts.
Instead of handwriting DQL you can use the ``QueryBuilder`` retrieved
If you need to build your query dynamically, you can use the ``QueryBuilder`` retrieved
by calling ``$entityManager->createQueryBuilder()``. There are more
details about this in the relevant part of the documentation.
@@ -1490,9 +1535,12 @@ we have to adjust the metadata slightly.
.. code-block:: php
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity(repositoryClass="BugRepository")
* @Table(name="bugs")
* @ORM\Entity(repositoryClass="BugRepository")
* @ORM\Table(name="bugs")
**/
class Bug
{
+4 -4
View File
@@ -5,8 +5,8 @@ There are use-cases when you'll want to sort collections when they are
retrieved from the database. In userland you do this as long as you
haven't initially saved an entity with its associations into the
database. To retrieve a sorted collection from the database you can
use the ``@OrderBy`` annotation with an collection that specifies
an DQL snippet that is appended to all queries with this
use the ``@OrderBy`` annotation with a collection that specifies
a DQL snippet that is appended to all queries with this
collection.
Additional to any ``@OneToMany`` or ``@ManyToMany`` annotation you
@@ -64,7 +64,7 @@ positional statement. Multiple Fields are separated by a comma (,).
The referenced field names have to exist on the ``targetEntity``
class of the ``@ManyToMany`` or ``@OneToMany`` annotation.
The semantics of this feature can be described as follows.
The semantics of this feature can be described as follows:
- ``@OrderBy`` acts as an implicit ORDER BY clause for the given
@@ -73,7 +73,7 @@ The semantics of this feature can be described as follows.
- All collections of the ordered type are always retrieved in an
ordered fashion.
- To keep the database impact low, these implicit ORDER BY items
are only added to an DQL Query if the collection is fetch joined in
are only added to a DQL Query if the collection is fetch joined in
the DQL query.
Given our previously defined example, the following would not add
+59 -26
View File
@@ -19,15 +19,14 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Persistence\Mapping\MappingException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -72,7 +71,8 @@ abstract class AbstractQuery
/**
* The parameter map of this query.
*
* @var \Doctrine\Common\Collections\ArrayCollection
* @var ArrayCollection|Parameter[]
* @psalm-var ArrayCollection<int, Parameter>
*/
protected $parameters;
@@ -241,7 +241,7 @@ abstract class AbstractQuery
*
* @param integer $lifetime
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setLifetime($lifetime)
{
@@ -261,7 +261,7 @@ abstract class AbstractQuery
/**
* @param integer $cacheMode
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setCacheMode($cacheMode)
{
@@ -306,7 +306,7 @@ abstract class AbstractQuery
/**
* Get all defined parameters.
*
* @return \Doctrine\Common\Collections\ArrayCollection The defined query parameters.
* @return ArrayCollection The defined query parameters.
*/
public function getParameters()
{
@@ -322,11 +322,13 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
$key = Query\Parameter::normalizeName($key);
$filteredParameters = $this->parameters->filter(
function (Query\Parameter $parameter) use ($key) : bool {
$parameterName = $parameter->getName();
return $key === $parameterName || (string) $key === (string) $parameterName;
return $key === $parameterName;
}
);
@@ -336,14 +338,17 @@ abstract class AbstractQuery
/**
* Sets a collection of query parameters.
*
* @param \Doctrine\Common\Collections\ArrayCollection|array $parameters
* @param ArrayCollection|mixed[] $parameters
*
* @return static This query instance.
*
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
*/
public function setParameters($parameters)
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
$parameterCollection = new ArrayCollection();
foreach ($parameters as $key => $value) {
@@ -389,9 +394,11 @@ abstract class AbstractQuery
*
* @param mixed $value
*
* @return array|string
* @return mixed[]|string|int|float|bool
*
* @throws \Doctrine\ORM\ORMInvalidArgumentException
*
* @psalm-return array|scalar
*/
public function processParameterValue($value)
{
@@ -469,7 +476,7 @@ abstract class AbstractQuery
*/
private function translateNamespaces(Query\ResultSetMapping $rsm)
{
$translate = function ($alias) {
$translate = function ($alias) : string {
return $this->_em->getClassMetadata($alias)->getName();
};
@@ -583,21 +590,45 @@ abstract class AbstractQuery
* Set whether or not to cache the results of this query and if so, for
* how long and which ID to use for the cache entry.
*
* @param boolean $bool
* @param integer $lifetime
* @param string $resultCacheId
* @deprecated 2.7 Use {@see enableResultCache} and {@see disableResultCache} instead.
*
* @param bool $useCache
* @param int $lifetime
* @param string $resultCacheId
*
* @return static This query instance.
*/
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
public function useResultCache($useCache, $lifetime = null, $resultCacheId = null)
{
if ($bool) {
$this->setResultCacheLifetime($lifetime);
$this->setResultCacheId($resultCacheId);
return $useCache
? $this->enableResultCache($lifetime, $resultCacheId)
: $this->disableResultCache();
}
return $this;
}
/**
* Enables caching of the results of this query, for given or default amount of seconds
* and optionally specifies which ID to use for the cache entry.
*
* @param int|null $lifetime How long the cache entry is valid, in seconds.
* @param string|null $resultCacheId ID to use for the cache entry.
*
* @return static This query instance.
*/
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null) : self
{
$this->setResultCacheLifetime($lifetime);
$this->setResultCacheId($resultCacheId);
return $this;
}
/**
* Disables caching of the results of this query.
*
* @return static This query instance.
*/
public function disableResultCache() : self
{
$this->_queryCacheProfile = null;
return $this;
@@ -606,7 +637,7 @@ abstract class AbstractQuery
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $lifetime How long the cache entry is valid.
* @param int|null $lifetime How long the cache entry is valid.
*
* @return static This query instance.
*/
@@ -822,8 +853,9 @@ abstract class AbstractQuery
*
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
*
* @return mixed The scalar result, or NULL if the query returned no result.
* @return mixed The scalar result.
*
* @throws NoResultException If the query returned no result.
* @throws NonUniqueResultException If the query result is not unique.
*/
public function getSingleScalarResult()
@@ -940,10 +972,11 @@ abstract class AbstractQuery
$this->setParameters($parameters);
}
$setCacheEntry = function() {};
$setCacheEntry = static function () : void {
};
if ($this->_hydrationCacheProfile !== null) {
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
[$cacheKey, $realCacheKey] = $this->getHydrationCacheId();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
@@ -957,7 +990,7 @@ abstract class AbstractQuery
$result = [];
}
$setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) : void {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
@@ -1044,7 +1077,7 @@ abstract class AbstractQuery
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @return array ($key, $hash)
* @return array<string, string> ($key, $hash)
*/
protected function getHydrationCacheId()
{
-3
View File
@@ -60,9 +60,6 @@ class DefaultCache implements Cache
*/
private $defaultQueryCache;
/**
* {@inheritdoc}
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
+26 -15
View File
@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Cache;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
@@ -29,6 +30,7 @@ use Doctrine\ORM\PersistentCollection;
use Doctrine\Common\Proxy\Proxy;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Query;
use function assert;
/**
* Default query cache implementation.
@@ -106,25 +108,27 @@ class DefaultQueryCache implements QueryCache
$result = [];
$entityName = reset($rsm->aliasMap);
$hasRelation = ( ! empty($rsm->relationMap));
$hasRelation = ! empty($rsm->relationMap);
$persister = $this->uow->getEntityPersister($entityName);
$region = $persister->getCacheRegion();
$regionName = $region->getName();
assert($persister instanceof CachedEntityPersister);
$region = $persister->getCacheRegion();
$regionName = $region->getName();
$cm = $this->em->getClassMetadata($entityName);
$generateKeys = function (array $entry) use ($cm): EntityCacheKey {
$generateKeys = static function (array $entry) use ($cm) : EntityCacheKey {
return new EntityCacheKey($cm->rootEntityName, $entry['identifier']);
};
$cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $cacheEntry->result));
$entries = $region->getMultiple($cacheKeys);
$entries = $region->getMultiple($cacheKeys) ?? [];
// @TODO - move to cache hydration component
foreach ($cacheEntry->result as $index => $entry) {
$entityEntry = is_array($entries) && array_key_exists($index, $entries) ? $entries[$index] : null;
$entityEntry = $entries[$index] ?? null;
if ($entityEntry === null) {
if (! $entityEntry instanceof EntityCacheEntry) {
if ($this->cacheLogger !== null) {
$this->cacheLogger->entityCacheMiss($regionName, $cacheKeys->identifiers[$index]);
}
@@ -145,9 +149,11 @@ class DefaultQueryCache implements QueryCache
$data = $entityEntry->data;
foreach ($entry['associations'] as $name => $assoc) {
$assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
$assocRegion = $assocPersister->getCacheRegion();
$assocMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
$assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
assert($assocPersister instanceof CachedEntityPersister);
$assocRegion = $assocPersister->getCacheRegion();
$assocMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
if ($assoc['type'] & ClassMetadata::TO_ONE) {
@@ -254,7 +260,7 @@ class DefaultQueryCache implements QueryCache
throw new CacheException("Second-level cache query supports only select statements.");
}
if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD]) && $hints[Query::HINT_FORCE_PARTIAL_LOAD]) {
if (($hints[Query\SqlWalker::HINT_PARTIAL] ?? false) === true || ($hints[Query::HINT_FORCE_PARTIAL_LOAD] ?? false) === true) {
throw new CacheException("Second level cache does not support partial entities.");
}
@@ -267,15 +273,18 @@ class DefaultQueryCache implements QueryCache
$rootAlias = key($rsm->aliasMap);
$persister = $this->uow->getEntityPersister($entityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! $persister instanceof CachedEntityPersister) {
throw CacheException::nonCacheableEntity($entityName);
}
$region = $persister->getCacheRegion();
$cm = $this->em->getClassMetadata($entityName);
assert($cm instanceof ClassMetadata);
foreach ($result as $index => $entity) {
$identifier = $this->uow->getEntityIdentifier($entity);
$entityKey = new EntityCacheKey($entityName, $identifier);
$identifier = $this->uow->getEntityIdentifier($entity);
$entityKey = new EntityCacheKey($cm->rootEntityName, $identifier);
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
// Cancel put result if entity put fail
@@ -339,7 +348,9 @@ class DefaultQueryCache implements QueryCache
* @param array $assoc
* @param mixed $assocValue
*
* @return array|null
* @return mixed[]|null
*
* @psalm-return array{targetEntity: string, type: mixed, list?: array[], identifier?: array}|null
*/
private function storeAssociationCache(QueryCacheKey $key, array $assoc, $assocValue)
{
@@ -33,17 +33,17 @@ use Doctrine\ORM\Cache\QueryCacheKey;
class StatisticsCacheLogger implements CacheLogger
{
/**
* @var array
* @var int[]
*/
private $cacheMissCountMap = [];
/**
* @var array
* @var int[]
*/
private $cacheHitCountMap = [];
/**
* @var array
* @var int[]
*/
private $cachePutCountMap = [];
@@ -142,7 +142,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionHitCount($regionName)
{
@@ -154,7 +154,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionMissCount($regionName)
{
@@ -166,7 +166,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionPutCount($regionName)
{
@@ -222,7 +222,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of put in cache.
*
* @return integer
* @return int
*/
public function getPutCount()
{
@@ -232,7 +232,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of entries successfully retrieved from cache.
*
* @return integer
* @return int
*/
public function getHitCount()
{
@@ -242,7 +242,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of cached entries *not* found in cache.
*
* @return integer
* @return int
*/
public function getMissCount()
{
@@ -144,7 +144,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
* @param \Doctrine\ORM\PersistentCollection $collection
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
*
* @return \Doctrine\ORM\PersistentCollection|null
* @return object[]|null
*/
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
{
@@ -243,20 +243,6 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
return $this->persister->get($collection, $index);
}
/**
* {@inheritdoc}
*/
public function removeElement(PersistentCollection $collection, $element)
{
if ($persisterResult = $this->persister->removeElement($collection, $element)) {
$this->evictCollectionCache($collection);
$this->evictElementCache($this->sourceEntity->rootEntityName, $collection->getOwner());
$this->evictElementCache($this->targetEntity->rootEntityName, $element);
}
return $persisterResult;
}
/**
* {@inheritdoc}
*/
@@ -283,17 +283,17 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* Generates a string of currently query
*
* @param array $query
* @param string $criteria
* @param array $orderBy
* @param integer $limit
* @param integer $offset
* @param string $query
* @param string[]|Criteria $criteria
* @param string[] $orderBy
* @param int $limit
* @param int $offset
*
* @return string
*/
protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null)
{
list($params) = ($criteria instanceof Criteria)
[$params] = $criteria instanceof Criteria
? $this->persister->expandCriteriaParameters($criteria)
: $this->persister->expandParameters($criteria);
@@ -452,12 +452,14 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$class = $this->metadataFactory->getMetadataFor($cacheEntry->class);
}
if (($entity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity)) !== null) {
$cachedEntity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity);
if ($cachedEntity !== null) {
if ($this->cacheLogger) {
$this->cacheLogger->entityCacheHit($this->regionName, $cacheKey);
}
return $entity;
return $cachedEntity;
}
}
@@ -542,19 +544,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
$key = null;
if ( ! $hasCache) {
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -564,7 +565,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);
@@ -578,18 +579,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
if ( ! $hasCache) {
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -599,7 +600,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);
@@ -100,6 +100,12 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache['update'][] = $entity;
}
/**
* @param object $entity
* @param bool $isChanged
*
* @return bool
*/
private function updateCache($entity, $isChanged)
{
$class = $this->metadataFactory->getMetadataFor(get_class($entity));
@@ -21,6 +21,7 @@
namespace Doctrine\ORM\Cache\Region;
use Doctrine\Common\Cache\MultiGetCache;
use Doctrine\ORM\Cache\CacheEntry;
use Doctrine\ORM\Cache\CollectionCacheEntry;
/**
@@ -67,7 +68,12 @@ class DefaultMultiGetRegion extends DefaultRegion
}
$returnableItems = [];
foreach ($keysToRetrieve as $index => $key) {
if (! $items[$key] instanceof CacheEntry) {
return null;
}
$returnableItems[$index] = $items[$key];
}
@@ -94,7 +94,13 @@ class DefaultRegion implements Region
*/
public function get(CacheKey $key)
{
return $this->cache->fetch($this->getCacheEntryKey($key)) ?: null;
$entry = $this->cache->fetch($this->getCacheEntryKey($key));
if (! $entry instanceof CacheEntry) {
return null;
}
return $entry;
}
/**
@@ -108,7 +114,7 @@ class DefaultRegion implements Region
$entryKey = $this->getCacheEntryKey($key);
$entryValue = $this->cache->fetch($entryKey);
if ($entryValue === false) {
if (! $entryValue instanceof CacheEntry) {
return null;
}
@@ -249,6 +249,8 @@ class FileLockRegion implements ConcurrentRegion
/**
* {@inheritdoc}
*
* @return bool
*/
public function unlock(CacheKey $key, Lock $lock)
{
+34 -4
View File
@@ -25,8 +25,6 @@ use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
@@ -39,6 +37,9 @@ use Doctrine\ORM\Mapping\NamingStrategy;
use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\ObjectRepository;
use function interface_exists;
/**
* Configuration container for all configuration options of Doctrine.
@@ -70,6 +71,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* Gets the directory where Doctrine generates any necessary proxy class files.
*
* @return string|null
*
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
* @see https://github.com/Ocramius/ProxyManager
*/
public function getProxyDir()
{
@@ -82,6 +86,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* Gets the strategy for automatically generating proxy classes.
*
* @return int Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
*
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
* @see https://github.com/Ocramius/ProxyManager
*/
public function getAutoGenerateProxyClasses()
{
@@ -107,6 +114,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* Gets the namespace where proxy classes reside.
*
* @return string|null
*
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
* @see https://github.com/Ocramius/ProxyManager
*/
public function getProxyNamespace()
{
@@ -432,6 +442,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomStringFunction($name)
{
@@ -484,6 +495,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomNumericFunction($name)
{
@@ -524,6 +536,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @psalm-param class-string|callable $className
*/
public function addCustomDatetimeFunction($name, $className)
{
@@ -536,6 +550,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
*
* @psalm-return ?class-string $name
*/
public function getCustomDatetimeFunction($name)
{
@@ -557,6 +573,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param array $functions The map of custom DQL date/time functions.
*
* @return void
*
* @psalm-param array<string, string> $functions
*/
public function setCustomDatetimeFunctions(array $functions)
{
@@ -587,6 +605,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $modeName The hydration mode name.
*
* @return string|null The hydrator class name.
*
* @psalm-return ?class-string
*/
public function getCustomHydrationMode($modeName)
{
@@ -614,6 +634,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $cmfName
*
* @return void
*
* @psalm-param class-string $cmfName
*/
public function setClassMetadataFactoryName($cmfName)
{
@@ -622,6 +644,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* @return string
*
* @psalm-return class-string
*/
public function getClassMetadataFactoryName()
{
@@ -648,8 +672,10 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null if it is not
* @return string|null The class name of the filter, or null if it is not
* defined.
*
* @psalm-return ?class-string
*/
public function getFilterClassName($name)
{
@@ -667,7 +693,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @return void
*
* @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository
* @throws ORMException If $classname is not an ObjectRepository.
*/
public function setDefaultRepositoryClassName($className)
{
@@ -686,6 +712,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @since 2.2
*
* @return string
*
* @psalm-return class-string
*/
public function getDefaultRepositoryClassName()
{
@@ -909,3 +937,5 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['defaultQueryHints'][$name] = $value;
}
}
interface_exists(MappingDriver::class);
@@ -21,7 +21,7 @@ namespace Doctrine\ORM\Decorator;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManagerDecorator;
use Doctrine\Persistence\ObjectManagerDecorator;
/**
* Base class for EntityManager decorators
@@ -65,7 +65,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function beginTransaction()
{
return $this->wrapped->beginTransaction();
$this->wrapped->beginTransaction();
}
/**
@@ -81,7 +81,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function commit()
{
return $this->wrapped->commit();
$this->wrapped->commit();
}
/**
@@ -89,7 +89,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function rollback()
{
return $this->wrapped->rollback();
$this->wrapped->rollback();
}
/**
@@ -153,7 +153,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function close()
{
return $this->wrapped->close();
$this->wrapped->close();
}
/**
@@ -169,15 +169,15 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
return $this->wrapped->lock($entity, $lockMode, $lockVersion);
$this->wrapped->lock($entity, $lockMode, $lockVersion);
}
/**
* {@inheritdoc}
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
return $this->wrapped->find($entityName, $id, $lockMode, $lockVersion);
return $this->wrapped->find($className, $id, $lockMode, $lockVersion);
}
/**
@@ -185,7 +185,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function flush($entity = null)
{
return $this->wrapped->flush($entity);
$this->wrapped->flush($entity);
}
/**
+37 -11
View File
@@ -28,7 +28,12 @@ use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Persistence\Mapping\MappingException;
use Doctrine\Persistence\ObjectRepository;
use Throwable;
use function ltrim;
use const E_USER_DEPRECATED;
use function trigger_error;
/**
* The EntityManager is the central access point to ORM functionality.
@@ -323,7 +328,7 @@ use Throwable;
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
[$sql, $rsm] = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@@ -354,6 +359,13 @@ use Throwable;
*/
public function flush($entity = null)
{
if ($entity !== null) {
@trigger_error(
'Calling ' . __METHOD__ . '() with any arguments to flush specific entities is deprecated and will not be supported in Doctrine ORM 3.0.',
E_USER_DEPRECATED
);
}
$this->errorIfClosed();
$this->unitOfWork->commit($entity);
@@ -362,7 +374,7 @@ use Throwable;
/**
* Finds an Entity by its identifier.
*
* @param string $entityName The class name of the entity to find.
* @param string $className The class name of the entity to find.
* @param mixed $id The identity of the entity to find.
* @param integer|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
@@ -377,9 +389,9 @@ use Throwable;
* @throws TransactionRequiredException
* @throws ORMException
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
$class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
if ($lockMode !== null) {
$this->checkLockRequirements($lockMode, $class);
@@ -537,9 +549,9 @@ use Throwable;
*
* @return void
*
* @throws ORMInvalidArgumentException if a non-null non-string value is given
* @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
* found in the mappings
* @throws ORMInvalidArgumentException If a non-null non-string value is given.
* @throws MappingException If a $entityName is given, but that entity is not
* found in the mappings.
*/
public function clear($entityName = null)
{
@@ -547,6 +559,13 @@ use Throwable;
throw ORMInvalidArgumentException::invalidEntityName($entityName);
}
if ($entityName !== null) {
@trigger_error(
'Calling ' . __METHOD__ . '() with any arguments to clear specific entities is deprecated and will not be supported in Doctrine ORM 3.0.',
E_USER_DEPRECATED
);
}
$this->unitOfWork->clear(
null === $entityName
? null
@@ -649,9 +668,13 @@ use Throwable;
* @return void
*
* @throws ORMInvalidArgumentException
*
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
*/
public function detach($entity)
{
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
}
@@ -670,9 +693,13 @@ use Throwable;
*
* @throws ORMInvalidArgumentException
* @throws ORMException
*
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
*/
public function merge($entity)
{
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
if ( ! is_object($entity)) {
throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
}
@@ -684,12 +711,11 @@ use Throwable;
/**
* {@inheritDoc}
*
* @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e:
* Fatal error: Maximum function nesting level of '100' reached, aborting!
*/
public function copy($entity, $deep = false)
{
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
throw new \BadMethodCallException("Not implemented.");
}
@@ -706,7 +732,7 @@ use Throwable;
*
* @param string $entityName The name of the entity.
*
* @return \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository The repository class.
* @return ObjectRepository|EntityRepository The repository class.
*/
public function getRepository($entityName)
{
+3 -1
View File
@@ -19,8 +19,8 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\ObjectManager;
/**
* EntityManager interface
@@ -190,6 +190,8 @@ interface EntityManagerInterface extends ObjectManager
/**
* Creates a copy of the given entity. Can create a shallow or a deep copy.
*
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
*
* @param object $entity The entity to copy.
* @param boolean $deep FALSE for a shallow copy, TRUE for a deep copy.
*
+3 -6
View File
@@ -19,11 +19,11 @@
namespace Doctrine\ORM;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Persistence\ObjectRepository;
/**
* An EntityRepository serves as a repository for entities with generic as well as
@@ -57,9 +57,6 @@ class EntityRepository implements ObjectRepository, Selectable
/**
* Initializes a new <tt>EntityRepository</tt>.
*
* @param EntityManager $em The EntityManager to use.
* @param Mapping\ClassMetadata $class The class descriptor.
*/
public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class)
{
@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
/**
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
use Doctrine\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
/**
* Class that holds event arguments for a loadMetadata event.
@@ -19,9 +19,10 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\ManagerEventArgs;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\Event\ManagerEventArgs;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\ObjectManager;
use function interface_exists;
/**
* Class that holds event arguments for a `onClassMetadataNotFound` event.
@@ -84,3 +85,4 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
}
}
interface_exists(ClassMetadata::class);
+1 -1
View File
@@ -38,7 +38,7 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
private $em;
/**
* @var string
* @var string|null
*/
private $entityClass;
+1 -1
View File
@@ -40,7 +40,7 @@ abstract class AbstractIdGenerator
* By default, this method returns FALSE. Generators that have this requirement
* must override this method and return TRUE.
*
* @return boolean
* @return bool
*/
public function isPostInsertGenerator()
{
@@ -23,6 +23,7 @@ use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker;
use PDO;
use function array_map;
use function in_array;
@@ -227,14 +228,14 @@ abstract class AbstractHydrator
*
* Template method.
*
* @param array $data The row data.
* @param array $result The result to fill.
* @param mixed[] $row The row data.
* @param mixed[] $result The result to fill.
*
* @return void
*
* @throws HydrationException
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
}
@@ -259,8 +260,19 @@ abstract class AbstractHydrator
* @param array &$id Dql-Alias => ID-Hash.
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
*
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias.
* @return array<string, array<string, mixed>> An array with all the fields
* (name => value) of the data
* row, grouped by their
* component alias.
*
* @psalm-return array{
* data: array<array-key, array>,
* newObjects?: array<array-key, array{
* class: mixed,
* args?: array
* }>,
* scalars?: array
* }
*/
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
{
@@ -351,13 +363,11 @@ abstract class AbstractHydrator
// WARNING: BC break! We know this is the desired behavior to type convert values, but this
// erroneous behavior exists since 2.0 and we're forced to keep compatibility.
if ( ! isset($cacheKeyInfo['isScalar'])) {
$dqlAlias = $cacheKeyInfo['dqlAlias'];
$type = $cacheKeyInfo['type'];
$fieldName = $dqlAlias . '_' . $fieldName;
$value = $type
? $type->convertToPHPValue($value, $this->_platform)
: $value;
if (! isset($cacheKeyInfo['isScalar'])) {
$type = $cacheKeyInfo['type'];
$value = $type ? $type->convertToPHPValue($value, $this->_platform) : $value;
$fieldName = $cacheKeyInfo['dqlAlias'] . '_' . $fieldName;
}
$rowData[$fieldName] = $value;
@@ -422,6 +432,12 @@ abstract class AbstractHydrator
'class' => new \ReflectionClass($mapping['className']),
];
case isset($this->_rsm->scalarMappings[$key], $this->_hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
return $this->_cache[$key] = [
'fieldName' => $this->_rsm->scalarMappings[$key],
'type' => Type::getType($this->_rsm->typeMappings[$key]),
'dqlAlias' => '',
];
case (isset($this->_rsm->scalarMappings[$key])):
return $this->_cache[$key] = [
'isScalar' => true,
@@ -422,7 +422,7 @@ class ObjectHydrator extends AbstractHydrator
$this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
}
} else if ( ! $reflFieldValue) {
$reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
$reflFieldValue->setInitialized(true);
}
@@ -47,8 +47,8 @@ class ScalarHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$result[] = $this->gatherScalarRowData($data);
$result[] = $this->gatherScalarRowData($row);
}
}
@@ -22,6 +22,8 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
use function array_keys;
use function in_array;
class SimpleObjectHydrator extends AbstractHydrator
{
@@ -76,10 +78,11 @@ class SimpleObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$entityName = $this->class->name;
$data = [];
$entityName = $this->class->name;
$data = [];
$discrColumnValue = null;
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
@@ -90,26 +93,27 @@ class SimpleObjectHydrator extends AbstractHydrator
$discrColumnName = $metaMappingDiscrColumnName;
}
if ( ! isset($sqlResult[$discrColumnName])) {
if (! isset($row[$discrColumnName])) {
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
}
if ($sqlResult[$discrColumnName] === '') {
if ($row[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$discrMap = $this->class->discriminatorMap;
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
if (! isset($discrMap[$row[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($row[$discrColumnName], array_keys($discrMap));
}
$entityName = $discrMap[$sqlResult[$discrColumnName]];
$entityName = $discrMap[$row[$discrColumnName]];
$discrColumnValue = $row[$discrColumnName];
unset($sqlResult[$discrColumnName]);
unset($row[$discrColumnName]);
}
foreach ($sqlResult as $column => $value) {
foreach ($row as $column => $value) {
// An ObjectHydrator should be used instead of SimpleObjectHydrator
if (isset($this->_rsm->relationMap[$column])) {
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
@@ -134,6 +138,11 @@ class SimpleObjectHydrator extends AbstractHydrator
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if ( ! isset($data[$fieldName]) || ! $valueIsNull) {
// If we have inheritance in resultset, make sure the field belongs to the correct class
if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array((string) $discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) {
continue;
}
$data[$fieldName] = $value;
}
}
@@ -89,7 +89,7 @@ final class HydrationCompleteHandler
$this->deferredPostLoadInvocations = [];
foreach ($toInvoke as $classAndEntity) {
list($class, $invoke, $entity) = $classAndEntity;
[$class, $invoke, $entity] = $classAndEntity;
$this->listenersInvoker->invoke(
$class,
@@ -58,7 +58,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function mappedBy($fieldName)
{
@@ -70,7 +70,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function inversedBy($fieldName)
{
@@ -80,7 +80,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeAll()
{
@@ -90,7 +90,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadePersist()
{
@@ -100,7 +100,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRemove()
{
@@ -110,7 +110,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeMerge()
{
@@ -120,7 +120,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeDetach()
{
@@ -130,7 +130,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRefresh()
{
@@ -140,7 +140,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchExtraLazy()
{
@@ -150,7 +150,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchEager()
{
@@ -160,7 +160,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchLazy()
{
@@ -179,7 +179,7 @@ class AssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return AssociationBuilder
* @return static
*/
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
@@ -198,7 +198,7 @@ class AssociationBuilder
/**
* Sets field as primary key.
*
* @return self
* @return static
*/
public function makePrimaryKey()
{
@@ -210,7 +210,7 @@ class AssociationBuilder
/**
* Removes orphan entities when detached from their parent.
*
* @return self
* @return static
*/
public function orphanRemoval()
{
@@ -57,7 +57,7 @@ class ClassMetadataBuilder
/**
* Marks the class as mapped superclass.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setMappedSuperClass()
{
@@ -70,7 +70,7 @@ class ClassMetadataBuilder
/**
* Marks the class as embeddable.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setEmbeddable()
{
@@ -107,7 +107,7 @@ class ClassMetadataBuilder
*
* @param string $repositoryClassName
*
* @return ClassMetadataBuilder
* @return static
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -119,7 +119,7 @@ class ClassMetadataBuilder
/**
* Marks class read only.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setReadOnly()
{
@@ -133,7 +133,7 @@ class ClassMetadataBuilder
*
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function setTable($name)
{
@@ -148,7 +148,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addIndex(array $columns, $name)
{
@@ -167,7 +167,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addUniqueConstraint(array $columns, $name)
{
@@ -186,7 +186,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $dqlQuery
*
* @return ClassMetadataBuilder
* @return static
*/
public function addNamedQuery($name, $dqlQuery)
{
@@ -203,7 +203,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a joined table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setJoinedTableInheritance()
{
@@ -215,7 +215,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a single table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setSingleTableInheritance()
{
@@ -231,7 +231,7 @@ class ClassMetadataBuilder
* @param string $type
* @param int $length
*
* @return ClassMetadataBuilder
* @return static
*/
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
{
@@ -252,7 +252,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $class
*
* @return ClassMetadataBuilder
* @return static
*/
public function addDiscriminatorMapClass($name, $class)
{
@@ -264,7 +264,7 @@ class ClassMetadataBuilder
/**
* Sets deferred explicit change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyDeferredExplicit()
{
@@ -276,7 +276,7 @@ class ClassMetadataBuilder
/**
* Sets notify change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyNotify()
{
@@ -291,7 +291,7 @@ class ClassMetadataBuilder
* @param string $methodName
* @param string $event
*
* @return ClassMetadataBuilder
* @return static
*/
public function addLifecycleEvent($methodName, $event)
{
@@ -307,7 +307,7 @@ class ClassMetadataBuilder
* @param string $type
* @param array $mapping
*
* @return ClassMetadataBuilder
* @return static
*/
public function addField($name, $type, array $mapping = [])
{
@@ -74,7 +74,7 @@ class FieldBuilder
*
* @param int $length
*
* @return FieldBuilder
* @return static
*/
public function length($length)
{
@@ -88,7 +88,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function nullable($flag = true)
{
@@ -102,7 +102,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function unique($flag = true)
{
@@ -116,7 +116,7 @@ class FieldBuilder
*
* @param string $name
*
* @return FieldBuilder
* @return static
*/
public function columnName($name)
{
@@ -130,7 +130,7 @@ class FieldBuilder
*
* @param int $p
*
* @return FieldBuilder
* @return static
*/
public function precision($p)
{
@@ -144,7 +144,7 @@ class FieldBuilder
*
* @param int $s
*
* @return FieldBuilder
* @return static
*/
public function scale($s)
{
@@ -167,7 +167,7 @@ class FieldBuilder
/**
* Sets field as primary key.
*
* @return FieldBuilder
* @return static
*/
public function makePrimaryKey()
{
@@ -182,7 +182,7 @@ class FieldBuilder
* @param string $name
* @param mixed $value
*
* @return FieldBuilder
* @return static
*/
public function option($name, $value)
{
@@ -194,7 +194,7 @@ class FieldBuilder
/**
* @param string $strategy
*
* @return FieldBuilder
* @return static
*/
public function generatedValue($strategy = 'AUTO')
{
@@ -206,7 +206,7 @@ class FieldBuilder
/**
* Sets field versioned.
*
* @return FieldBuilder
* @return static
*/
public function isVersionField()
{
@@ -222,7 +222,7 @@ class FieldBuilder
* @param int $allocationSize
* @param int $initialValue
*
* @return FieldBuilder
* @return static
*/
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
{
@@ -240,7 +240,7 @@ class FieldBuilder
*
* @param string $def
*
* @return FieldBuilder
* @return static
*/
public function columnDefinition($def)
{
@@ -42,7 +42,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
/**
* @param string $name
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function setJoinTable($name)
{
@@ -61,7 +61,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
@@ -32,7 +32,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param array $fieldNames
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setOrderBy(array $fieldNames)
{
@@ -44,7 +44,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param string $fieldName
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setIndexBy($fieldName)
{
@@ -19,9 +19,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\DBAL\Platforms;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
@@ -30,7 +27,14 @@ use Doctrine\ORM\Events;
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
use Doctrine\ORM\Id\IdentityGenerator;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionException;
use function assert;
use function interface_exists;
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
@@ -56,7 +60,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private $targetPlatform;
/**
* @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
* @var MappingDriver
*/
private $driver;
@@ -275,6 +279,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
if ( ! $class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name);
}
foreach ($class->subClasses as $subClass) {
if ((new ReflectionClass($subClass))->name !== $subClass) {
throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name);
}
}
}
} else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
@@ -401,10 +410,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->fieldMappings as $mapping) {
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
}
if ( ! isset($mapping['declared'])) {
if (! isset($mapping['declared'])) {
$mapping['declared'] = $parentClass->name;
}
$subClass->addInheritedFieldMapping($mapping);
@@ -703,6 +712,9 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
case ClassMetadata::GENERATOR_TYPE_CUSTOM:
$definition = $class->customGeneratorDefinition;
if ($definition === null) {
throw new ORMException("Can't instantiate custom generator : no custom generator definition");
}
if ( ! class_exists($definition['class'])) {
throw new ORMException("Can't instantiate custom generator : " .
$definition['class']);
@@ -792,3 +804,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
return $this->targetPlatform;
}
}
interface_exists(ClassMetadataInterface::class);
interface_exists(ReflectionService::class);
+87 -26
View File
@@ -20,14 +20,18 @@
namespace Doctrine\ORM\Mapping;
use BadMethodCallException;
use Doctrine\Instantiator\Instantiator;
use InvalidArgumentException;
use RuntimeException;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Instantiator\Instantiator;
use Doctrine\ORM\Cache\CacheException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\ReflectionService;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use function array_key_exists;
use function explode;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@@ -241,9 +245,9 @@ class ClassMetadataInfo implements ClassMetadata
* )
* </code>
*
* @var array
*
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*
* @var array<string, string>|null
*/
public $customGeneratorDefinition;
@@ -251,7 +255,8 @@ class ClassMetadataInfo implements ClassMetadata
* The name of the custom repository class used for the entity class.
* (Optional).
*
* @var string
* @var string|null
* @psalm-var ?class-string
*/
public $customRepositoryClassName;
@@ -392,6 +397,8 @@ class ClassMetadataInfo implements ClassMetadata
* Whether a unique constraint should be generated for the column.
*
* @var array
*
* @psalm-var array<string, array{type: string, fieldName: string, columnName: string, inherited: class-string}>
*/
public $fieldMappings = [];
@@ -639,7 +646,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionProperty instances of the mapped class.
*
* @var \ReflectionProperty[]
* @var ReflectionProperty[]|null[]
*/
public $reflFields = [];
@@ -666,7 +673,9 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperties of the mapped class.
*
* @return array An array of ReflectionProperty instances.
* @return ReflectionProperty[]|null[] An array of ReflectionProperty instances.
*
* @psalm-return array<ReflectionProperty|null>
*/
public function getReflectionProperties()
{
@@ -678,7 +687,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $name
*
* @return \ReflectionProperty
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
@@ -688,7 +697,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return \ReflectionProperty
* @return ReflectionProperty
*
* @throws BadMethodCallException If the class has a composite identifier.
*/
@@ -804,7 +813,7 @@ class ClassMetadataInfo implements ClassMetadata
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
* @return string[] The names of all the fields that should be serialized.
*/
public function __sleep()
{
@@ -914,7 +923,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Restores some state that can not be serialized/unserialized.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*/
@@ -975,7 +984,7 @@ class ClassMetadataInfo implements ClassMetadata
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
* @param ReflectionService $reflService The reflection service.
*
* @return void
*/
@@ -1037,7 +1046,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Validates lifecycle callbacks.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*
@@ -1095,7 +1104,10 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $fieldName
* @param array $cache
*
* @return array
* @return mixed[]
*
* @psalm-param array{usage: mixed, region: mixed} $cache
* @psalm-return array{usage: mixed, region: mixed}
*/
public function getAssociationCacheDefaults($fieldName, array $cache)
{
@@ -1444,9 +1456,25 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping.
*
* @return array The updated mapping.
* @return mixed[] The updated mapping.
*
* @throws MappingException If something is wrong with the mapping.
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool
* }
*/
protected function _validateAndCompleteAssociationMapping(array $mapping)
{
@@ -1564,10 +1592,12 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws RuntimeException
* @throws MappingException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool, isCascadeRemove: bool}
*/
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
@@ -1655,10 +1685,27 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate and complete.
*
* @return array The validated and completed mapping.
* @return mixed[] The validated and completed mapping.
*
* @throws MappingException
* @throws InvalidArgumentException
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: int|mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool,
* orphanRemoval: bool
* }
*/
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
@@ -1682,9 +1729,11 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws \InvalidArgumentException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool}
*/
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
@@ -1861,7 +1910,9 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array|null $fieldNames
*
* @return array
* @return mixed[]
*
* @psalm-return list<string>
*/
public function getColumnNames(array $fieldNames = null)
{
@@ -2017,7 +2068,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $fieldName
*
* @return \Doctrine\DBAL\Types\Type|string|null
* @return string|null
*
* @todo 3.0 Remove this. PersisterHelper should fix it somehow
*/
@@ -2033,7 +2084,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $columnName
*
* @return \Doctrine\DBAL\Types\Type|string|null
* @return string|null
*
* @deprecated 3.0 remove this. this method is bogus and unreliable, since it cannot resolve the type of a column
* that is derived by a referenced field on a different entity.
@@ -2216,6 +2267,12 @@ class ClassMetadataInfo implements ClassMetadata
throw MappingException::invalidOverrideFieldType($this->name, $fieldName);
}
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// The contained 'inherited' information was accidentally deleted by the unset() call below.
if (array_key_exists('inherited', $this->fieldMappings[$fieldName])) {
$overrideMapping['inherited'] = $this->fieldMappings[$fieldName]['inherited'];
}
unset($this->fieldMappings[$fieldName]);
unset($this->fieldNames[$mapping['columnName']]);
unset($this->columnNames[$mapping['fieldName']]);
@@ -2297,7 +2354,7 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($table['name'])) {
// Split schema and table name from a table name like "myschema.mytable"
if (strpos($table['name'], '.') !== false) {
list($this->table['schema'], $table['name']) = explode('.', $table['name'], 2);
[$this->table['schema'], $table['name']] = explode('.', $table['name'], 2);
}
if ($table['name'][0] === '`') {
@@ -2523,7 +2580,7 @@ class ClassMetadataInfo implements ClassMetadata
if (!isset($field['column'])) {
$fieldName = $field['name'];
if (strpos($fieldName, '.')) {
list(, $fieldName) = explode('.', $fieldName);
[, $fieldName] = explode('.', $fieldName);
}
$resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
@@ -2625,6 +2682,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $repositoryClassName The class name of the custom mapper.
*
* @return void
*
* @psalm-param class-string $repositoryClassName
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -3253,6 +3312,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string|null $className
*
* @return string|null null if the input value is null
*
* @psalm-param ?class-string $className
*/
public function fullyQualifiedClassName($className)
{
@@ -30,6 +30,8 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
{
/**
* @var array Map to store entity listener instances.
*
* @psalm-var array<class-string, object>
*/
private $instances = [];
@@ -99,7 +99,8 @@ class DefaultQuoteStrategy implements QuoteStrategy
$schema = '';
if (isset($association['joinTable']['schema'])) {
$schema = $association['joinTable']['schema'] . '.';
$schema = $association['joinTable']['schema'];
$schema .= ! $platform->supportsSchemas() && $platform->canEmulateSchemas() ? '__' : '.';
}
$tableName = $association['joinTable']['name'];
@@ -20,12 +20,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use function interface_exists;
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
@@ -39,7 +40,8 @@ use Doctrine\ORM\Mapping\MappingException;
class AnnotationDriver extends AbstractAnnotationDriver
{
/**
* {@inheritDoc}
* @var int[]
* @psalm-var array<class-string, int>
*/
protected $entityAnnotationClasses = [
Mapping\Entity::class => 1,
@@ -273,7 +275,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
@@ -504,7 +505,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
$hasMapping = false;
$listenerClass = new \ReflectionClass($listenerClassName);
/* @var $method \ReflectionMethod */
foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// find method callbacks.
$callbacks = $this->getMethodCallbacks($method);
@@ -524,7 +524,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
// Evaluate @HasLifecycleCallbacks annotation
if (isset($classAnnotations[Mapping\HasLifecycleCallbacks::class])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
foreach ($this->getMethodCallbacks($method) as $value) {
$metadata->addLifecycleCallback($value[0], $value[1]);
@@ -557,7 +556,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
*
* @param \ReflectionMethod $method
*
* @return array
* @return callable[]
*/
private function getMethodCallbacks(\ReflectionMethod $method)
{
@@ -605,7 +604,17 @@ class AnnotationDriver extends AbstractAnnotationDriver
* Parse the given JoinColumn as array
*
* @param Mapping\JoinColumn $joinColumn
* @return array
*
* @return mixed[]
*
* @psalm-return array{
* name: string,
* unique: bool,
* nullable: bool,
* onDelete: mixed,
* columnDefinition: string,
* referencedColumnName: string
* }
*/
private function joinColumnToArray(Mapping\JoinColumn $joinColumn)
{
@@ -625,7 +634,20 @@ class AnnotationDriver extends AbstractAnnotationDriver
* @param string $fieldName
* @param Mapping\Column $column
*
* @return array
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type: mixed,
* scale: int,
* length: int,
* unique: bool,
* nullable: bool,
* precision: int,
* options?: mixed[],
* columnName?: string,
* columnDefinition?: string
* }
*/
private function columnToArray($fieldName, Mapping\Column $column)
{
@@ -671,3 +693,5 @@ class AnnotationDriver extends AbstractAnnotationDriver
return new self($reader, $paths);
}
}
interface_exists(ClassMetadata::class);
@@ -20,15 +20,18 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use function interface_exists;
use function preg_replace;
/**
* The DatabaseDriver reverse engineers the mapping metadata from a database.
@@ -386,6 +389,22 @@ class DatabaseDriver implements MappingDriver
* @param \Doctrine\DBAL\Schema\Column $column
*
* @return array
*
* @psalm-return array{
* fieldName: string,
* columnName: string,
* type: string,
* nullable: bool,
* options?: array{
* unsigned?: bool,
* fixed?: bool,
* comment?: string,
* default?: string
* },
* precision?: int,
* scale?: int,
* length?: int|null
* }
*/
private function buildFieldMapping($tableName, Column $column)
{
@@ -486,7 +505,9 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return ForeignKeyConstraint[]
*
* @psalm-return array<string, ForeignKeyConstraint>
*/
private function getTableForeignKeys(Table $table)
{
@@ -500,7 +521,7 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return string[]
*/
private function getTablePrimaryKeys(Table $table)
{
@@ -548,9 +569,11 @@ class DatabaseDriver implements MappingDriver
// Replace _id if it is a foreignkey column
if ($fk) {
$columnName = str_replace('_id', '', $columnName);
$columnName = preg_replace('/_id$/', '', $columnName);
}
return Inflector::camelize($columnName);
}
}
interface_exists(ClassMetadata::class);
@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\MappingDriverChain instead
*/
class DriverChain extends MappingDriverChain
{

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