Compare commits

...

667 Commits

Author SHA1 Message Date
Grégoire Paris
a588555ecd Merge pull request #8586 from KartaviK/patch-3
Additional psalm param typehint for orderBy argument in findBy method
2021-04-05 20:38:36 +02:00
Grégoire Paris
7de84537f6 Merge pull request #8591 from DmitriiBezborodnikov/case_insensive_parenthesis
Return case insensitive check
2021-04-05 14:40:51 +02:00
Grégoire Paris
97f8325dad Make sure tests are suffixed with Test
They will not be taken into account when running vendor/bin/phpunit
otherwise.
2021-04-05 14:32:40 +02:00
Grégoire Paris
0ebd7052d7 Drop create table at shutdown
It makes tests more isolated from each other: another test relying on
some tables including some of the ones created here may fail creating
the tables it needs because they already exist.
2021-04-05 14:03:49 +02:00
Dmitrii Bezborodnikov
5d73378b92 Return case insensitive check 2021-04-05 14:03:49 +02:00
Grégoire Paris
10572ec441 Merge pull request #8590 from VincentLanglet/patch-2
Fix phpdoc of ClassMetadataInfo::getIdentifierValues
2021-04-04 23:47:09 +02:00
Vincent Langlet
76278d801d Fix phpdoc 2021-04-04 21:19:54 +02:00
Roman Varkuta
ca80830b26 Describe $orderBy parameter as a hash
A list of string is incorrect, it actually looks like this:
['someField' => 'DESC', 'someOtherField' => 'ASC'…]`
2021-04-03 12:45:24 +02:00
Grégoire Paris
bcb4889a2c Merge pull request #8583 from greg0ire/sync-static-analysis-workflows
Synchronize static analysis jobs with upstream
2021-04-02 08:58:50 +02:00
Grégoire Paris
961da8b0cc Synchronize static analysis jobs with upstream 2021-04-01 23:32:04 +02:00
Benjamin Eberlei
657a30f8ce [GH-6394] Bugfix: IdentifierFlattener support for association non-object values. (#8384)
* [GH-6394] Bugfix: IdentifierFlattener support for association non-object values

* [GH-6394] Bugfix: BasicEntityPersister::update used wrong identifiers for version assignment.

* Exclude MissingNativeTypeHint phpcs rule as 7.4 is not lowest version.
2021-04-01 23:16:53 +02:00
Grégoire Paris
0b25d4d8b0 Merge pull request #8573 from greg0ire/fix-build
Fix build issues
2021-04-01 07:49:27 +02:00
Grégoire Paris
a88242ee6c Adapt test logic to PHP and SQLite
There seems to be at least 2 camps in the software world when it comes
to the question "What's today minus one month", today being at the end
of march.

While PHP and SQLite agree that that would be the 2nd of March, other
RDBMS than SQLite and humans will tell you that it's the last day of
February.

This patch ensures that we check one logic for SQLite, and the other
logic for other platforms.
2021-03-30 21:08:29 +02:00
Grégoire Paris
fe4964008d Accommodate 2 behaviors of symfony/console in test
Decorated text used to be wrapped too early in SymfonyStyle->block()
See https://github.com/symfony/symfony/pull/40348
The fix was not contributed to version 3, which means we have to rewrite
the test so that it passes for both the correct and the buggy version.
2021-03-30 08:41:10 +02:00
Grégoire Paris
3f3de70c3e Merge pull request #8564 from cybercitizen7/featureIncludeDirectory
Adding DIR to include statement to fix issue with pathing
2021-03-26 19:46:40 +01:00
darkw1z
eb4e317144 Adding DIR to include statement to fix issue with pathing 2021-03-26 14:04:46 +01:00
Grégoire Paris
c8f2f61ea1 Merge pull request #8556 from VincentLanglet/patch-2
Fix fieldMapping phpdoc
2021-03-26 08:26:40 +01:00
Vincent Langlet
c9502d3d0b Fix fieldMapping phpdoc 2021-03-24 15:07:08 +01:00
Grégoire Paris
3358ccde39 Merge pull request #8547 from greg0ire/psalm-lv6-phpdoc
Make phpdoc types correct
2021-03-21 22:11:51 +01:00
Grégoire Paris
47475f3a67 Merge pull request #8532 from acoulton/bug-fix-ci-db-connection
All CI runs are using the sqlite fallback connection instead of the expected driver
2021-03-17 19:49:56 +01:00
acoulton
61c4a5da0a Rename tmpdb_ to privileged_db in test config and TestUtil
To avoid confusion, the `tmpdb_` test config values are now named
`privileged_db_` and better documented in the phpunit.xml.dist.

The TestUtil class has been refactored to more closely mirror the
structure and method / variable naming of the equivalent in
doctrine/dbal. This does not introduce any significant functional
changes. The only real difference is that the test output now prints
the selected database driver the first time it is referenced,
rather than repeating this through the test run.
2021-03-17 10:31:22 +00:00
acoulton
dd34bca4eb Upgrade previously-skipped tests to phpunit 9
These tests had not been running in CI so missed the previous
phpunit upgrade.

Note that assertions in decimal/floaty values in GH7941Test have
been changed to compare numerically with a reasonable level of
precision, instead of using regex. This is because the types
returned by the different drivers are inconsistent, and phpunit
now only allows regex comparisons on strings.
2021-03-17 10:31:22 +00:00
acoulton
3e21c50f61 Fix unit test and CI database driver / credential configuration
Builds using the github actions phpunit.xml files were not properly
recognising driver-specific configuration values, so were all
falling back to use the in-memory sqlite database instead of the
expected driver. This also meant a number of tests were skipped
as they rely on functionality not available in sqlite.

This commit addresses that by:

* REMOVING the automatic fallback to the sqlite memory database -
  phpunit.xml must now always specify explicit parameters for the
  desired connection.

* Displaying the active driver in the build output for visibility
  and debugging.

* Changing the way TestUtil loads the database config in line
  with the equivalent logic in doctrine/dbal, and to support the
  way that the config is/was specified in the phpunit.xml files
  for CI.

Note that this means a couple of the expected config variable names
have changed. Developers that are using customised phpunit.xml files
locally will need to update them to provide:

* Database config variables if they want to use the sqlite/memory
  driver - see phpunit.xml.dist for details.
* `db_driver` instead of `db_type`
* `db_user` instead of `db_username`
* `db_dbname` instead of `db_name`
* And, if in use, the equivalent changes to the `tmpdb_` values

The other change is that now if you provide any value for
`db_driver` we will attempt to create that connection type and
that will throw if other details (username / password / etc as
required by the driver) are not provided. Previously providing
partial configuration would cause TestUtil to silently fall back
to the in-memory sqlite driver.
2021-03-17 10:31:22 +00:00
Grégoire Paris
bc3592bcc8 Make phpdoc type correct 2021-03-16 19:20:11 +01:00
Grégoire Paris
5247c56fce Merge pull request #8539 from greg0ire/cs-20210311
🎉 Final CS batch 🎉
2021-03-14 18:47:03 +01:00
Grégoire Paris
cc37c490c2 Synchronize coding standard workflow with upstream
Now that there no longer are cs issues, we can thank diff-sniffer and
kiss it goodbye!
2021-03-13 09:55:38 +01:00
Grégoire Paris
95824efd61 Manually fix cs 2021-03-13 09:46:38 +01:00
Grégoire Paris
44d4712e64 Ignore rule about annotation phpdoc
These phpdoc is parsed by doctrine/annotations, and that package does
not understand things like array<string, mixed> yet.
2021-03-13 09:46:38 +01:00
Grégoire Paris
930f44c02f Ignore rule for externally-defined property 2021-03-13 00:08:03 +01:00
Grégoire Paris
6e3c011e65 Ignore rule about superflous comment
We can fix it with a breaking change.
2021-03-13 00:08:03 +01:00
Grégoire Paris
a82de0d422 Ignore rule about unused method
It cannot work when you call the private method like a callable.
2021-03-13 00:08:03 +01:00
Grégoire Paris
9917488179 Ignore rule about empty statements
This should be implemented in a separate pull request.
2021-03-12 08:20:46 +01:00
Grégoire Paris
93f31d2c33 Merge pull request #8533 from acoulton/test-string-lock-version
Add test coverage for passing optimistic lock version as string
2021-03-11 21:41:32 +01:00
acoulton
77356b954f Add test coverage for passing optimistic lock version as string
As discussed in #8527, when using optimistic locking with integer
version columns, Doctrine has always supported passing the lock
version as a string. For example when passing in a version
received in POST / GET.

Technically speaking this does not comply with the docs and phdoc
(which show the app explicitly casting to int before passing).

Nonetheless the maintainers decided it should continue to be valid
for now and reinstated the old soft-equals logic with #8531.

This modified test just avoids accidental changes in future.
2021-03-11 13:24:53 +00:00
Grégoire Paris
92f764206e Ignore broken rule 2021-03-11 09:11:24 +01:00
Grégoire Paris
141539673e Merge pull request #8530 from doctrine/cs-20210310
CS-batch 25/26 🤩
2021-03-11 00:05:31 +01:00
Grégoire Paris
23dc804c9b Merge pull request #8531 from beberlei/GH-8527-RevertLockEquals
[GH-8527] Revert cs fixes for entity version compares in lock+merge
2021-03-10 23:30:25 +01:00
Benjamin Eberlei
9e3baa7baa [GH-8527] Revert cs fixes for entity version compares in lock+merge 2021-03-10 22:46:07 +01:00
Grégoire Paris
322ea51ecf Manually fix cs 2021-03-10 22:17:31 +01:00
Grégoire Paris
21b046452b Merge pull request #8529 from greg0ire/cs-20210308
CS batch 24/26 🤞
2021-03-10 19:53:52 +01:00
Grégoire Paris
c57b81ada4 Manually fix cs 2021-03-09 21:15:33 +01:00
Grégoire Paris
4fa7c9c6de Merge pull request #8521 from greg0ire/cs-20210228
CS batch 23/an estimated 26
2021-03-08 19:57:18 +01:00
Grégoire Paris
3580517aac Manually fix cs 2021-03-01 21:49:10 +01:00
Grégoire Paris
f9e7c3c2d8 Merge pull request #8516 from greg0ire/cs-20210227
CS batch 22/an estimated 26
2021-02-28 21:27:52 +01:00
Grégoire Paris
3600c0fbca Manually fix cs 2021-02-28 18:31:38 +01:00
Grégoire Paris
f779513042 Remove unused properties
They should have been removed as part of a6b43b93ac
2021-02-28 18:31:38 +01:00
Diego Rin Martín
07d426edf5 Changed lock function to compare timestamps instead of DateTimeInterface objects directly. (#8508)
When using optimistic lock with DateTimeInterface based version field a bug appears due to the use of the === operator for comparing the lock version and the entity version. This comparison always resolves to false because the === operator when comparing objects is only true when both sides are the exact same instance of the object.

To fix the issue I have decided to compare timestamps instead the DateTimeInterface based objects directly, calling getTimestamp() method and doing a strict comparison.

Modified OptimisticLockException to use DateTimeInterface instead of DateTime class.

Added test suite to cover case.

Fixes #8499
2021-02-27 18:40:48 +01:00
Grégoire Paris
4afd4069be Merge pull request #8515 from greg0ire/cs-20210226
CS batch 21/an estimated 26
2021-02-27 14:30:25 +01:00
Grégoire Paris
239215c2e5 Merge pull request #8502 from greg0ire/rework-contributing-md
Rework CONTRIBUTING.md
2021-02-27 13:03:20 +01:00
Grégoire Paris
e6f11652d2 Add section for 2.9.x branch 2021-02-27 12:16:49 +01:00
Grégoire Paris
2910a73927 Rework badges urls
Some .x were missing, and ugly urlencoding can be avoided.
2021-02-27 12:10:47 +01:00
Grégoire Paris
3959b2743c Remove references to Travis 2021-02-27 12:03:35 +01:00
Grégoire Paris
658e54027e Remove trailing whitespace 2021-02-27 12:01:06 +01:00
Grégoire Paris
ba882451b0 Refer to our actual coding/standard
We do much more than just PSR 1 and 2
2021-02-27 12:01:05 +01:00
Grégoire Paris
1ed9840123 Refer to global workflow policy
We are doing things differently now, and the how is already documented.
2021-02-27 12:01:05 +01:00
Grégoire Paris
71044894a1 Manually fix cs 2021-02-26 21:30:49 +01:00
Grégoire Paris
1a41d6b87c Fix configuration mix up 2021-02-26 08:25:44 +01:00
Grégoire Paris
5dfcb08999 Merge pull request #8512 from greg0ire/cs-20210225
CS batch 20/an estimated 26
2021-02-25 23:23:24 +01:00
Grégoire Paris
284bd6fd03 Manually fix cs 2021-02-25 21:22:50 +01:00
Grégoire Paris
e40ac3e1d0 Merge pull request #8510 from greg0ire/cs-20210224
CS batch 19/an estimated 26
2021-02-24 22:41:28 +01:00
Grégoire Paris
0bce2472f2 Manually fix cs 2021-02-24 18:51:02 +01:00
Grégoire Paris
89f57de884 Merge pull request #8504 from greg0ire/cs-20210223
CS batch 18/an estimated 26
2021-02-23 23:18:42 +01:00
Grégoire Paris
ae19f40958 Merge pull request #8495 from Warxcell/fix_to_iterable_with_cache
Fix bug when using Result Cache with Query::toIterable
2021-02-23 20:16:39 +01:00
Grégoire Paris
c2d69a3c48 Merge pull request #8507 from greg0ire/address-move-away-from-master
Address move away from master
2021-02-23 18:19:47 +01:00
Grégoire Paris
6ce91dd37b Address move away from master 2021-02-23 09:24:40 +01:00
Grégoire Paris
57e6ba25c9 Merge pull request #8505 from dbu/patch-1
fix typo in changelog
2021-02-23 08:56:31 +01:00
David Buchmann
9d2e67bbb4 fix typo in changelog 2021-02-23 08:17:31 +01:00
Grégoire Paris
2dce5b20ad Manually fix cs 2021-02-22 23:50:09 +01:00
Warxcell
930859f803 Fix bug when using ResultCache with Query::toIterable.
Signed-off-by: Warxcell <warxcell@gmail.com>
2021-02-22 23:35:22 +02:00
Yup
a70c73ae3a Use RegEx to match if queryPart contains OR/AND (#8453)
This allows fixes cases of queries that contain line feeds or tabs but
do not benefit from automatic wrapping of parenthesis.
2021-02-22 20:58:06 +01:00
David Buchmann
074346b8d5 Note deprecation of AbstractQuery::iterator (#8497) 2021-02-22 20:30:05 +01:00
Grégoire Paris
9ed4a8c043 Merge pull request #8498 from greg0ire/cs-20210222
CS batch 17/an estimated 26
2021-02-22 20:25:06 +01:00
Grégoire Paris
9c917811e5 Manually fix cs 2021-02-22 09:12:04 +01:00
Grégoire Paris
f883820257 Ignore rule about wrong comment style 2021-02-22 08:48:46 +01:00
Grégoire Paris
a32045dd51 Ignore rule violated by external package 2021-02-22 07:52:57 +01:00
Grégoire Paris
672b04a55d Merge pull request #8483 from olsavmic/fix-single-scalar-hydrator-memory-leak-on-exception
Fix single scalar hydrator memory leak on exception
2021-02-21 21:12:50 +01:00
Grégoire Paris
261334aca2 Merge pull request #8494 from greg0ire/cs-20210221
CS batch 16/an estimated 26
2021-02-21 20:29:47 +01:00
Warxcell
7f6ed094cd Add test to verify that using ResultCache with Query::toIterable is failing. 2021-02-21 21:12:52 +02:00
Grégoire Paris
a792655813 Manually fix cs 2021-02-21 12:20:19 +01:00
Grégoire Paris
fb71204910 Relax assertion (#8493)
EntityManager is too restrictive, any implementation can actually be
returned here.

Closes #8488
2021-02-21 07:43:56 +01:00
Grégoire Paris
b918661cf1 Merge pull request #8492 from greg0ire/cs-20210220
CS batch 15/an estimated 26
2021-02-20 20:49:25 +01:00
Michael Olšavský
7971a53164 Method hydrateAll() does not take into account possible exception
from hydrateAllData() which in turn does not call cleanup()
2021-02-20 18:58:50 +01:00
Grégoire Paris
a175f96ae8 Manually fix cs 2021-02-20 15:37:15 +01:00
Grégoire Paris
7c1cde6471 Ignore rule that triggers on external property 2021-02-20 15:32:26 +01:00
Grégoire Paris
1ffc0cacf4 Merge pull request #8491 from greg0ire/cs-20210219
CS batch 14/an estimated 26
2021-02-20 11:10:27 +01:00
Grégoire Paris
e979d0d50f Manually fix cs 2021-02-20 00:01:41 +01:00
Grégoire Paris
553ea03079 Ignore rule about case mismatch
@group does not have to do with the Group entity at all.
2021-02-19 23:33:25 +01:00
Grégoire Paris
149014879d Ignore rule about property defined externally 2021-02-19 23:11:43 +01:00
Grégoire Paris
b991c58988 Merge pull request #8490 from greg0ire/cs-20210218
CS batch 13/an estimated 26
2021-02-19 23:08:25 +01:00
Aleksandr Frolov
ee9627b82e Update QueryBuilder::setParameters docs (#8487)
Use `ArrayCollection` instead of plain array (which is supported only for bc)
2021-02-19 01:45:14 +01:00
Grégoire Paris
e3f03414f9 Manually fix cs 2021-02-18 23:17:03 +01:00
Grégoire Paris
1f406fd3df Merge pull request #8484 from greg0ire/cs-20210217
CS batch 12/an estimated 26
2021-02-18 21:54:43 +01:00
Grégoire Paris
b747bf15ff Manually fix cs 2021-02-17 16:32:39 +01:00
Grégoire Paris
5fe85bfc03 Ignore rule about underscore in method name
We inherit from a class defined in another package.
2021-02-17 15:55:21 +01:00
Grégoire Paris
0dccf05ca8 Automatically fix cs 2021-02-17 15:55:21 +01:00
Grégoire Paris
ebae57eb96 Merge pull request #8480 from greg0ire/cs-20210216
CS batch 11/an estimated 26
2021-02-16 23:10:18 +01:00
Benjamin Eberlei
30a7c2aa67 [GH-8410] Fix memory leak in new toIterable and state bug. (#8467)
* [GH-8410] Fix memory leak in new toIterable and state bug.

The new AbstractQuery::toIterable() had a memory leak that
AbstractQuery::iterable() did not have. This leak is now fixed.

After fixing the leak, one test failed where the identity map in
ObjectHydrator triggered and lead to a notice. Introduced a new
AbstractHydrator::cleanupAfterRowIteration() that the ObjectHydrator
uses to cleanup the state.

* [GH-8413] Bugfix: Iterating with multiple, mixed results

When multiple entity results are part of a row, the result handling
must be different. In addition mixed results with scalars are broken
and now throw an exception as illegal operation.

* Housekeeping: phpcs

* [GH-8413] Add assertions for entity alias iteration.

* [GH-8387] Missing @deprecated on Query::iterate
2021-02-16 17:52:20 +01:00
Benjamin Eberlei
3a9b8fde9b Housekeeping: Fix cs 2021-02-16 16:24:19 +01:00
Yosh
4f864bc178 Identifier type is not set when many2many relations are deleted (#8401)
* Ensure identifier type is set on deleteJoinTableRecords

* Housekeeping: phpcs

* Housekeeping: phpcs

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-02-16 16:12:39 +01:00
Grégoire Paris
d76cbd755f Manually fix cs 2021-02-16 09:07:26 +01:00
Grégoire Paris
4aece04ae7 Automatically fix cs 2021-02-16 08:48:48 +01:00
Grégoire Paris
f31dbf8d4e Merge pull request #8479 from greg0ire/cs-20210215
CS batch 10/an estimated 27
2021-02-15 23:44:27 +01:00
Grégoire Paris
416f35dba9 Manually fix cs 2021-02-14 21:00:58 +01:00
Grégoire Paris
c29370e061 Automatically fix cs 2021-02-14 14:39:35 +01:00
Grégoire Paris
4e0f6837d0 Merge pull request #8478 from beberlei/CsFixes2
CS Fixes 2 string interpolation to sprintf
2021-02-14 14:39:00 +01:00
Benjamin Eberlei
e45d212f02 Housekeeping: CS fixes Doctrine\ORM\Mapping\MappingException 2021-02-14 14:28:42 +01:00
Benjamin Eberlei
8f62bd39b5 Housekeeping: CS fixes Doctrine\ORM\ORMException 2021-02-14 09:53:19 +01:00
Benjamin Eberlei
5e11afcdf1 Housekeeping: CS fixes Doctrine\ORM\Mapping\MappingException 2021-02-14 09:49:39 +01:00
Benjamin Eberlei
f833222017 Cs fixes1 (#8475)
* Housekeeping: CS Query, AbstractQuery, NativeQuery.

* Housekeeping: phpcs TreeWalker

* Housekeeping: CS Doctrine\ORM\EntityManager

* Housekeeping: CS Doctrine\ORM\Cache

* Upgrade git-phpcs

* Drop unused method parameter

* Describe types more precisely

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-02-14 09:23:15 +01:00
Grégoire Paris
c7f39ebbde Merge pull request #8477 from greg0ire/cs-20210214
CS batch 9/an estimated 28
2021-02-14 09:20:11 +01:00
Grégoire Paris
15f08ed006 Manually fix cs 2021-02-14 00:04:18 +01:00
Grégoire Paris
b6fd4b5ef3 Automatically fix cs 2021-02-14 00:04:11 +01:00
Grégoire Paris
5e4dae88f3 Merge pull request #8476 from greg0ire/cs-20210213
CS batch 8/an estimated 30
2021-02-13 17:26:58 +01:00
Grégoire Paris
7312ddeda7 Manually fix cs 2021-02-13 13:46:01 +01:00
Grégoire Paris
9a67b6f699 Merge pull request #8474 from greg0ire/cs-20210212
CS batch 7/an estimated 30
2021-02-12 23:03:28 +01:00
Grégoire Paris
f59a0c349b Manually fix cs 2021-02-12 20:43:17 +01:00
Grégoire Paris
4c8831f716 Remove unused helper method 2021-02-12 20:04:56 +01:00
Grégoire Paris
01ca442be7 Ignore error about no assignment
These files must be require'd
2021-02-12 08:45:07 +01:00
Grégoire Paris
01374ca2ab Ignore rule about lone comment
That comment is mistaken for a method comment because it precedes one.
The issue was reported but will most likely not be fixed.
2021-02-12 07:39:56 +01:00
Grégoire Paris
94e8b1d43c Merge pull request #8470 from greg0ire/cs-20210211
CS batch 6/an estimated 30
2021-02-12 07:25:43 +01:00
Grégoire Paris
61d0f96c17 Manually fix cs 2021-02-11 21:02:10 +01:00
Grégoire Paris
41729be80a Spell "first" properly 2021-02-11 18:24:56 +01:00
Grégoire Paris
6dbaa39016 Merge pull request #8469 from greg0ire/cs-20210209
CS batch 5/an estimated 30
2021-02-10 21:11:11 +01:00
Grégoire Paris
58c95a92d1 Manually fix cs 2021-02-09 22:58:05 +01:00
Grégoire Paris
4958180b02 Merge pull request #8468 from greg0ire/cs-20210208
CS batch 4/an estimated 30
2021-02-09 22:22:41 +01:00
Grégoire Paris
8312ff0cb5 Merge pull request #8353 from fezfez/patch-1
Add docs to export-ignore
2021-02-08 21:23:35 +01:00
Grégoire Paris
fb9b9b276e Manually fix cs 2021-02-08 13:53:04 +01:00
Grégoire Paris
792a9a9149 Merge pull request #8464 from greg0ire/cs-20210207
CS batch 3/many
2021-02-07 14:21:09 +01:00
Grégoire Paris
0f655f9fb6 Manually fix cs 2021-02-07 12:21:40 +01:00
Grégoire Paris
2d7acbd07f Merge pull request #8457 from greg0ire/cs-20210206
CS Batch 2/many
2021-02-06 12:22:10 +01:00
Grégoire Paris
b06679cc14 Manually fix cs 2021-02-06 11:44:32 +01:00
Julian Ullrich
2693a93aed fixed entity generation for numeric values (#8434)
* fixed entity generation for numeric values

* fixed entity generation for numeric values

Co-authored-by: julian <julian@ullrichmail.net>
2021-02-06 00:35:45 +01:00
Benjamin Eberlei
8724589c6e Housekeeping: Fix wrong typehint - Closes #8421 2021-02-06 00:23:45 +01:00
Grégoire Paris
424305ef38 Merge pull request #8455 from greg0ire/cs
Cs
2021-02-05 23:40:01 +01:00
Grégoire Paris
9d01f6a45c Run phpcbf after running git-phpcs
git-phpcs can publish comments to Github, that will be helpful.
phpcbf will still be helpful to ensure no one upgrades the coding
standard without also fixing issues that can be autofixed.
2021-02-05 21:39:13 +01:00
Grégoire Paris
7ed487b534 Manually fix CS 2021-02-05 21:38:33 +01:00
Grégoire Paris
40f3925589 Merge pull request #8144 from greg0ire/cs
Automated fixes with phpcbf + manual fixes
2021-02-05 08:44:58 +01:00
Alexander Schranz
f92c3dba32 Fix --complete flag in orm:ensure-production-settings command (#8426) 2021-02-01 22:08:04 +01:00
Grégoire Paris
bcbd4401b8 Ignore export directory 2021-01-30 23:50:15 +01:00
Grégoire Paris
d6aca8e146 Fix proxy file exclude pattern
__CG__ is a file prefix, not a directory
2021-01-30 23:45:46 +01:00
Grégoire Paris
8f1911a4fe Fix cs by hand 2021-01-30 23:29:40 +01:00
Grégoire Paris
7f30cd3102 Require doctrine/common ^3.0.3
That release comes with a fix for a bug that affects us since we are
using return type declarations for wakeUp() in proxyfied classes in on
of our tests.
2021-01-30 18:55:32 +01:00
Grégoire Paris
f01fe3e050 Fix or remove wrong assertions 2021-01-30 18:55:32 +01:00
Grégoire Paris
210c2ee6a4 Remove strict types 2021-01-30 18:55:32 +01:00
Grégoire Paris
497dfd1a84 Avoid covariant return types
It's not supported by PHP 7.2/7.3
2021-01-30 18:55:31 +01:00
Grégoire Paris
d9f0e2a27f Add exclude rules for tricky cases 2021-01-30 18:55:31 +01:00
Grégoire Paris
9a40ac6e2a Restore weird phpdoc
Tests do not pass when I format that phpdoc nicely.
2021-01-30 18:55:31 +01:00
Grégoire Paris
1687d9c479 Restore version annotation, but capitalized
@version is commonly used for svn ids and is forbidden
2021-01-30 18:55:31 +01:00
Gabriel Ostrolucký
1a46ed8901 Relax contract of EntityListenerResolver so it doesn't require class name (#8448)
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-01-30 13:37:26 +01:00
Grégoire Paris
36d0352c01 Add missing use statements 2021-01-30 11:21:44 +01:00
Grégoire Paris
15eacd787b Remove weird extra argument 2021-01-30 11:21:44 +01:00
Grégoire Paris
5b3f9bdd7b Fix type declarations 2021-01-30 11:21:44 +01:00
Grégoire Paris
e00dba94f4 Remove strict types 2021-01-30 11:21:44 +01:00
Grégoire Paris
ab0e4007a5 Use interface instead of concretion 2021-01-30 11:17:40 +01:00
Grégoire Paris
32266c54f9 Fix compatibility with parent signature 2021-01-30 11:17:39 +01:00
Grégoire Paris
dd2120cd41 Make default value compatible with phpdoc 2021-01-30 11:17:39 +01:00
Grégoire Paris
8991df0785 Add missing return types 2021-01-30 11:17:39 +01:00
Grégoire Paris
ca31923a39 Run phpcbf in the CI
There are still many CS issues to fix, but with this, we now know people
can run vendor/bin/phpcbf to fix their issues and only their issues.
2021-01-30 11:17:39 +01:00
Grégoire Paris
68bc00b6c6 Automatically fix CS 2021-01-30 10:58:42 +01:00
Grégoire Paris
5b55b8c6cf Disable rules that would result in BC-breaks 2021-01-29 23:21:12 +01:00
Grégoire Paris
10f381bc95 Restrict fixes to be compatible with PHP 7.2 2021-01-29 21:16:18 +01:00
Nikolay Gagarinov
40aa8fe5db update getting-started fix type, improve doc (#8440)
* update getting-started fix type, improve doc

* Update getting-started.rst
2021-01-26 21:40:41 +01:00
Simon Podlipsky
5801474ba3 Catch doctrine/persistence MappingException (#8264)
When driver chain is used doctrine/persistence MappingException is thrown instead of doctrine/orm MappingException
2021-01-11 09:07:06 +01:00
Claudio Zizza
9dbd960631 Update website config to current repository branches (#8420) 2021-01-11 09:06:06 +01:00
Grégoire Paris
544df89055 Use proper workflow name (#8418)
This must have been a copy/paste/adapt mistake.
2021-01-11 09:05:18 +01:00
azjezz
378944dd27 remove T from class metadata (#8398) 2020-12-19 20:48:16 +01:00
Benjamin Eberlei
8b749642cd [GH-8231] Bugfix: Missed dirty check synchronization check. (#8392)
When an entity with change tracking policy "deferred explicit" gets
removed, then persisted again, it is not schedulded for a dirty check
synchronization. This is not the case for entities that are persisted
and are already in the managed state.
2020-12-14 11:00:07 +01:00
Nic Wortel
277b53a970 Use the ramsey/composer-install action to install dependencies (#8388)
Follow-up of https://github.com/doctrine/.github/pull/16.
2020-12-10 20:03:47 +01:00
Benjamin Morel
2febb4509a Fix Psalm param (#8386) 2020-12-09 11:03:01 +01:00
Benjamin Eberlei
21d2c88013 [GH-7486] Bugfix: failing the command when clearing empty cache is wrong semantics. (#8376) 2020-12-06 22:00:00 +01:00
Vašek Henzl
e7d33eb1a9 Infer datetime_immutable DBAL type for \DateTimeImmutable instance parameters (#8328)
The support for passing \DateTimeImmutable instance as a query parameter has
been added to ORM in #1333 (the year 2015), a long time before immutable date
types (datetime_immutable etc) were introduced to DBAL in doctrine/dbal#2450
(2017).

Back then, it made sense to treat \DateTimeImmutable (or any
\DateTimeInterface) in the same way as \DateTime and infer parameter type as
datetime. However, when immutable date types were later added to DBAL, it
wasn't reflected anyhow in type inference in ORM and \DateTimeImmmutable
instances are still inferred as datetime DBAL type.

This PR fixes this IMO incorrect behaviour of
ParameterTypeInferer::inferType(): for a \DateTimeImmmutable parameter, it now
returns datetime_immutable DBAL type; for \DateTime or any other types
implementing \DateTimeInterface, it returns datetime DBAL type as it did
before.

This behaviour is in line with DateTimeImmutableType handling only
\DateTimeImmutable and DateTimeType handling any \DateTimeInterface.

Why? In most cases, it doesn't matter and datetime works for \DateTimeImmutable
parameters just fine. But it does matter if using custom implementation of
datetime_immutable type like UTCDateTimeImmutableType from
simpod/doctrine-utcdatetime. Then the broken type inference is revealed.

This is partially related to #6443, however, this PR isn't about custom DBAL
types but about correct type inference for build-in types.
2020-12-05 23:36:33 +01:00
Michel Hunziker
cab7a4558d Fix invalid psalm annotation (#8374) 2020-12-05 14:47:49 +01:00
Benjamin Eberlei
242cf1a33d Fix ambiguous case where an entity is also a Traversable (#8371)
* Fix ambiguous case where an entity is also a Traversable

* Address phpcs violations.

* Address phpcs violations.

* Address phpcs violations.

Co-authored-by: Laurent VOULLEMIER <laurent.voullemier@gmail.com>
2020-12-04 20:53:07 +01:00
Grégoire Paris
da225a0db8 Drop step that switches the release branch (#8372)
ORM is a repository where we use the stable branch as the default
branch, that step is not appropriate here.
2020-12-04 20:46:09 +01:00
Benjamin Eberlei
3ef5a30102 [GH-8366] Catch additional Persistence MappingException (#8370) 2020-12-04 20:16:50 +01:00
Grégoire Paris
418587bc25 Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-12-03 20:18:13 +01:00
Grégoire Paris
01187c9260 Remove trailing whitespaces (#8360)
Stylistically, it's not great to have them, but more importantly, the
latest symfony/yaml version has issues with trailing whitespaces.
2020-12-03 09:52:14 +01:00
Stéphane
35cf4810c1 Add docs to export-ignore 2020-11-27 18:50:57 +01:00
Benjamin Eberlei
404edd418b [GH-8229] Prevent Illegal Inheritance Override (#8348)
* [GH-8229] Prevent AttributeOverride on fields from entities, only allowed for MappedSuperclass

* [GH-8229] Prevent AssociationOverride on fields from entities, only allowed for MappedSuperclass

* Revert "Fix SQL alias generation regression for simple inheritance (#8329)"

This reverts commit f4ebded63c.

* [GH-8229] Finalize checks for illegal attribute/assocation overrides.

* [GH-8229] Revert ccae8f7176 PR #8234

* [GH-8229] Update documentation to clarify only mapped superclass or trait works with overrides

* [GH-8229] Fix style violations introduced by revert

* [GH-8229] Fix style violations introduced by revert

* [GH-8229] Temporarily disable the exception until 2.8.

* Make phpcs happy
2020-11-25 23:04:56 +01:00
Claudio Zizza
011d3c21eb Update functionality of code examples (#8336) 2020-11-24 22:39:42 +01:00
Benjamin Eberlei
3d46e07887 PHP8 Support (#8303)
* Update doctrine/dbal to 2.12 for PHP 8 support.

* Change Query\Parser::match to Query\Parser::matchToken including DQL functions.

* Fix phpunit constraint to 9.4, adjust @group usage to workaround PHPUnit bug.

* Fix PHPUnit API related changes.

* Add PHP 8 support for EntityGenerator namespace detection.

* Use new assertEqualsWithDetla for QueryDqlFunctionTest with date comparisons

* Replace ReflectionParameter::getClass usage with non-deprecated ::getType instead.

* Revert "Change Query\Parser::match to Query\Parser::matchToken including DQL functions."

This reverts commit 279070491d50deaa4d41e17b28bb5a68f5a22796.

* More matchToken => match reverts

* Housekeeping: phpcs

* Housekeeping: phpcs

* Housekeeping: phpcs

* Housekeeping: phpcs

* Add PHP 8 testrunner, update composer.json and small fix in OrmFunctionalTestCase for new PHPUnit behvaior

* Update doctrine/coding-standard to 8.x

* Update rule names for doctrine/coding-standard v8.0

* Update to Psalm 4.

* Not failOnWarning anymore.

* Fix phpcs

* fix phpcs

* remove 7.2 for now until we can support in DBAL.

* Relax doctrine/dbal requirement and add 7.2 CI support again.
2020-11-15 13:24:31 +01:00
Roma
b1ac293a50 Add missing backtick in rst markup (#8335) 2020-11-10 20:37:36 +01:00
Romain Grégoire
f4ebded63c Fix SQL alias generation regression for simple inheritance (#8329)
This fixes a regression from 099c5b42e1.
Without the fix, "where part" in SQL is generated with incorrect aliases.
See https://github.com/doctrine/orm/issues/8229#issuecomment-722942180.
2020-11-10 10:53:01 +01:00
Benjamin Eberlei
51bc596502 Update to Psalm 4. (#8332) 2020-11-08 10:38:21 +01:00
Grégoire Paris
95f1b48422 Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-11-07 20:19:45 +01:00
Grégoire Paris
385b5a2f80 Phpunit 8 (#8330)
* Revert to whitelist

coverage requires PHPunit 9, and we don't have that yet.

* Upgrade to PHPUnit 8

This unlocks PCOV usage for coverage

* Upload coverage files to Codecov
2020-11-07 19:41:15 +01:00
Benjamin Eberlei
f7d8b155db Merge branch '2.7' into 2.8.x 2020-11-07 18:37:53 +01:00
Benjamin Eberlei
fa6fe09647 Ignore composer.lock 2020-11-07 18:37:46 +01:00
Benjamin Eberlei
539ffea390 Merge 2.7 into 2.8.x 2020-11-07 18:30:32 +01:00
Benjamin Eberlei
c270eba678 Start moving travis phpunit runs to Github actions. (#8317)
* Move PHPUnit runs from Travis to Github Actions

This removes all artifacts used for TravisCI testing and replaces them
with the existing infrastructure for Github Actions from DBAL component.

In addition some test changes were needed and triggered larger Coding
Style cleanups in 3 test files.

* Remove composer.lock and improve naming in CI workflow.
2020-11-07 18:11:42 +01:00
Michael Käfer
2f0eb95c90 Patch 1 (#8325)
* Update outdated doc parts

- The cache implementation moved from `Common` to `doctrine/cache`
- APCu is mor appropiate nowadays I guess
- AbstractQuery::useResultCache() is deprecated since 2.7

* Fix wrong argument

* Fix wrong arguments and remove useless line
2020-10-31 12:13:48 +01:00
Grégoire Paris
b13b2e8bab Upgrade doctrine/coding-standard (#8321)
* Use a classname that exists

Doctrine\ORM\Mapping\TableGenerator does not exist, only
Doctrine\ORM\Id\TableGenerator does.

* Upgrade doctrine/coding-standard

That library has a dependency on another library that requires composer
plugin API v1. Updating both libs allow to use Composer v2.

* Account for doctrine/reflection deprecation
2020-10-28 11:14:10 +01:00
Simon Podlipsky
4bfc84f035 Rename getIterable() to toIterable() (part 2) (#8293) 2020-10-17 23:55:39 +02:00
Michael Voříšek
ca27cc3f72 Fix EOL of text files (#8310) 2020-10-17 19:04:42 +02:00
Mateusz Sip
53dc5b2ac3 Detect associations inside embeddables (#8291) 2020-10-17 18:49:16 +02:00
orklah
f1219f1418 Add psalm template support to several types (#8289) 2020-10-17 12:01:52 +02:00
Grégoire Paris
072066f746 Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-10-17 11:07:05 +02:00
Laurent VOULLEMIER
5fde5801c1 Fix many typos (#8299)
- Some uppercase letters were used in the middle of sentence
- Some dots were missing
- There was two sentences with wrong or missing words
2020-10-13 21:52:04 +02:00
Thomas Landauer
18d96fcc02 Update working-with-indexed-associations.rst (#8298)
* Update working-with-indexed-associations.rst

Fixing broken link

* Update docs/en/tutorials/working-with-indexed-associations.rst

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

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-10-12 21:27:18 +02:00
Benjamin Eberlei
4d2908a065 Change <phpunit verbose="true" /> to false for better readability of test output. 2020-10-11 19:14:47 +02:00
Benjamin Eberlei
8d250f5921 Use SHELL_VERBOSITY=3 instead of LOG_LEVEL=DEBUG 2020-10-11 12:03:57 +02:00
Benjamin Eberlei
59fd9b5ea7 Change LOG_LEVEL to debug should expose more info from laminas/automatic-releases. 2020-10-11 00:17:52 +02:00
Benjamin Eberlei
8fcc70cfbe Change LOG_LEVEL to debug should expose more info from laminas/automatic-releases. 2020-10-11 00:14:35 +02:00
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
Simon Podlipsky
f1365b78d5 Rename getIterable to toIterable (#8268) 2020-09-25 20:42:09 +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
60cd524443 Introduce getIterable() on AbstractQuery (#7885) 2020-08-14 11:12:40 +02:00
Simon Podlipsky
045d1f3bf2 Bump Doctrine CS to v6 (#8241) 2020-08-13 09:10:43 +02:00
Grégoire Paris
1ae6f18fe9 Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-08-12 22:26:19 +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
Zacharias Luiten
91b9dd90f4 Add DQL support for ORDER BY CASE (#8188) 2020-08-05 22:49:51 +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
Grégoire Paris
505d658e3d Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-06-21 13:50:48 +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
Grégoire Paris
bee8decd18 Require persistence 2 and common 3 (#8166)
This allows us to drop the autoload-calls-based BC layer.
2020-06-17 14:56:17 +02:00
Alexander Berl
93867f8d77 TASK: Replace "Blacklist" example with "Banlist" (#8174) 2020-06-08 23:06:53 +02:00
Laurent VOULLEMIER
6bce7e9cab Add iterable support for IN criterias (#8162) 2020-06-03 18:40:53 +02:00
Grégoire Paris
4d8418fe6f Merge remote-tracking branch 'origin/2.7' into drop-persistence-bc-layer 2020-06-02 18:40:48 +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
Benjamin Eberlei
850d57e791 [GH-8137] Update doctrine/inflector dependency to 1.4|2.0 (#8147)
* [GH-8137] Update doctrine/inflector dependency to 1.4|2.0 and resolve deprecations.

* [GH-8137] Address review comments

* Address phpcs issues.

* More CS

* Codingstyle
2020-05-17 19:58:02 +02:00
Grégoire Paris
c3dd71704b Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-05-16 15:14:51 +02:00
Grégoire Paris
6780a963f7 Migrate git-phpcs to Github actions (#8146) 2020-05-16 14:01:10 +02:00
Philippe Le Van (@plv)
0b305e5bd3 Add possibility to use sql comments in the DQL syntax (#8140) 2020-05-15 08:04:58 +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
Gabriel Birke
061207861b Improve CLI config documentation (#8130)
Change code examples for `cli-config.php` to use
`ConsoleRunner::createHelperSet` instead of constructing the helper set
array yourself.
Remove DBAL-specific documentation

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-05-11 21:43:26 +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
Grégoire Paris
3c91792dd8 Address deprecation about PHPUnit annotations (#8070)
These changes have been done using Rector, this might not result in the
best placement for method calls, but it is not worse than the current
situation.

I used the configuration documented at
b398e8740c/docs/HowItWorks.md (221-order-of-rectors)

Fixes #8069
2020-03-16 08:56:59 +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
Claudio Zizza
431d0a3c5e Remove ORM 2.0 version constraints from docs (#8002) 2020-03-06 21:47:40 +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
Soliman
1da002ca2f Throw OptimisticLockException when connection::commit() returns… (#7946)
* Throw OptimisticLockException when connection::commit() returns false

* Update unit tests

* Fix doctrine persistence version to avoid deprecations changes

* Apply changes from 2.8.x

* Update from 2.8.x
2020-02-29 23:06:47 +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
ef639d4de6 Remove nightly builds from .travis.yml 2020-02-15 15:34:05 +01:00
Benjamin Eberlei
31f4dd671a Merge remote-tracking branch 'origin/2.7' into 2.8.x 2020-02-13 21:31:29 +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
60c4867ed3 Merge branch 2.7 into 2.8.x 2020-02-12 23:42:36 +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
0ee1716b26 Merge branch 2.7 into 2.8.x 2020-02-12 23:38:27 +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
Claudio Zizza
a236a83fa8 Merge pull request #7993 from SenseException/readme2-8
Update version and links in readme
2020-01-20 11:14:33 +01:00
Claudio Zizza
37f1bd7606 Update version and links in readme 2020-01-17 21:42:59 +01:00
Grégoire Paris
af4cb282ba Merge pull request #7978 from alexeyshockov/patch-2
Stable PHP 7.4 in Travis
2020-01-17 07:49:48 +01:00
Benjamin Eberlei
ce4914ba0e Merge 2.7 to 2.8.x 2020-01-17 00:08:23 +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
Alexey Shokov
bdfd6c1677 Stable PHP 7.4 in Travis 2020-01-16 23:27:20 +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
8e0157d97d Merge branch '2.7' into 2.8.x 2020-01-15 22:57:06 +01:00
Benjamin Eberlei
a2f01f7ccc Allow everything from ocramius/package-versions ^1.0. 2020-01-15 22:56:08 +01:00
Benjamin Eberlei
1767f4b8e7 Merge branch '2.7' into 2.8.x 2020-01-15 22:02:55 +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
Benjamin Eberlei
ca95b0ee13 Merge branch '2.7' into 2.8.x 2020-01-08 19:39:17 +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
4aa09861dd Merge pull request #7941 from Grafikart/feat-typed-functions
Allow DQL functions to specify return type
2019-12-12 19:50:23 +01:00
Grafikart
24e9a7caaf Allow defining return types for DQL functions 2019-12-12 14:19:09 +01:00
Luís Cobucci
d90df59118 Merge pull request #7948 from beberlei/TravisSmokeTesting
Add stage that runs before Test to allow fast failures on Sqlite/phpcs
2019-12-12 11:54:41 +01:00
Benjamin Eberlei
f9103a7b41 Add another stage that runs before Test to allow fast failures on Sqlite, Quality + PHPCS-differ 2019-12-12 11:43:24 +01:00
Luís Cobucci
9891477094 Merge pull request #7928 from kokspflanze/2.7-patch-deprecated
Deprecate EntityRepository#clear()
2019-12-09 21:56:41 +01:00
kokspflanze
59e3a55110 Deprecate EntityRepository#clear() 2019-12-09 21:42:11 +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
ca38249f6c/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:

434820973c/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:

434820973c/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
Luís Cobucci
434820973c Bump up version 2018-11-21 00:46:46 +01:00
Luís Cobucci
41ff526921 Merge pull request #6830 from Tobion/fix-collation-foreign-key
fix applying column options on foreign key columns
2018-11-21 00:41:17 +01:00
Luís Cobucci
0be52b0087 Isolate entities used by the new test
To ensure we don't have any unintended side-effect.
2018-11-21 00:20:20 +01:00
Tobias Schultze
ee8dc496d9 Fix applying collation on foreign key columns 2018-11-21 00:20:15 +01:00
Luís Cobucci
f80656cddf Merge pull request #7317 from protecinnovations/fix/7316-xml-order-by-dir-many-to-many
[XML] Fix default value of many-to-many order-by to ASC
2018-11-20 13:11:22 +01:00
Alex Denvir
72121c01ec [XML] Fix default value of many-to-many order-by to ASC 2018-11-20 12:33:29 +01:00
Luís Cobucci
ac505390dd Merge pull request #7472 from seferov/patch-2
fix incorrect phpdoc typehint
2018-11-20 09:41:01 +01:00
Luís Cobucci
728e6e15c5 Merge pull request #7441 from asgrim/fix-getResult-type
$hydrationMode throughout can be a string as well as int (for custom modes)
2018-11-20 09:40:04 +01:00
Luís Cobucci
d21305378c Merge pull request #7471 from alcaeus/fix-unloaded-metadata-parameter-processing
Fix parameter value processing for objects with unloaded metadata
2018-11-15 11:34:31 +01:00
Andreas Braun
0552749059 Fix parameter value processing for objects with unloaded metadata 2018-11-15 11:21:05 +01:00
Farhad Safarov
fbd3fe95e4 fix incorrect phpdoc typehint 2018-11-13 13:01:10 +03:00
James Titcumb
c6d02daee0 $hydrationMode throughout can be a string as well as int (for custom modes) 2018-11-12 13:58:42 +00:00
Luís Cobucci
5208035003 Merge pull request #7444 from naitsirch/fix/issue6968
Fixed URLs of doctrine-mapping.xsd in docs
2018-11-12 11:40:01 +01:00
Luís Cobucci
d93956eff0 Use HTTPS endpoint for XML schema location 2018-11-12 11:29:32 +01:00
naitsirch
b3b06d3e7d Fixed URLs of doctrine-mapping.xsd in docs
Until now the references to the `doctrine-mapping.xsd` consisted of different URLs.

A grep of docs showed:
* /Users/robo/dev/php/Doctrine/doctrine-mapping.xsd
* http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd
* http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd
* https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd

Now it is used http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd everywhere.
2018-11-12 11:09:15 +01:00
Michael Moravec
427f815975 Merge pull request #7465 from unguul/patch-1
Fixes tiny typo in the 'Working with DateTime instances' documentation
2018-11-11 23:24:29 +01:00
Michael Moravec
bf601ce268 Merge pull request #7421 from seferov/patch-1
JIRA to Github issues on Limitations and Known Issues
2018-11-11 23:24:00 +01:00
Michael Moravec
8bfb363fcc Merge pull request #7434 from naitsirch/fix/doc-faq-public-property
Removed FAQ paragraph stating public variables are disallowed
2018-11-11 23:22:58 +01:00
Michael Moravec
ebf2630a66 Merge pull request #7435 from oguzdumanoglu/patch-2
Fix a typo on Documentation
2018-11-11 23:22:25 +01:00
Michael Moravec
9018955e1f Merge pull request #7412 from ThomasLandauer/patch-1
Some formatting improvements
2018-11-10 21:05:50 +01:00
Thomas Landauer
88d58ae0a3 Some formatting improvements 2018-11-10 20:45:03 +01:00
Michael Moravec
2fc99afd44 Merge pull request #7423 from ThomasLandauer/patch-2
Update association-mapping.rst
2018-11-10 20:40:44 +01:00
Michael Moravec
fa0885e25d Merge pull request #7374 from SenseException/deprecate-yaml-docs
Deprecation message in documentation for YAML
2018-11-10 20:33:51 +01:00
Alexandru Ungureanu
0e4a0108d2 Fixes small typo 2018-11-08 13:59:21 +02: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
Oguz Dumanoglu
58370256c0 Fix a typo
There was a typo in Working with Associations page.
2018-10-19 16:32:27 +02:00
naitsirch
d5364231c2 Removed FAQ paragraph stating public variables are disallowed
In #7427 @flaushi mentioned the outdated paragraph. This commit removes
this one.
2018-10-18 22:36:29 +02:00
Luís Cobucci
4df3a4d436 Merge pull request #7428 from Majkl578/php7.3
CI: Test against PHP 7.3
2018-10-14 09:39:26 +02:00
Michael Moravec
812989490c CI: Test against PHP 7.3 2018-10-13 20:33:26 +02:00
Thomas Landauer
892ef9edb7 Update association-mapping.rst
Added info about owning and inverse side.
2018-10-09 21:33:42 +02:00
Farhad Safarov
982782f8c9 JIRA to Github issues 2018-10-09 11:52:22 +03:00
Michael Moravec
7319f524a3 Merge pull request #7397 from eibt/patch-1
Update getting-started.rst
2018-09-23 07:04:34 +02:00
Michael Moravec
1d71fbf77b Merge pull request #7367 from timdev/fix/entitymanager-find-with-optimistic-lock-no-need-tx
Fix for BC break in 2.6.2 when calling EM::find() with LockMode::OPTIMISTIC outside of a TX
2018-09-23 06:43:26 +02:00
Ivan
7eacfec2c3 Fix typo in getting-started.rst 2018-09-23 06:39:11 +02:00
Michael Moravec
46f2a41cf7 Merge pull request #7377 from sserbin/fix-query-andx-doctype
Fix query andX doctype
2018-09-23 06:37:42 +02:00
Michael Moravec
fd2baf6f65 Merge pull request #7260 from stof/regression_commit_order
Fix the handling of circular references in the commit order calculator
2018-09-23 05:44:14 +02:00
Michael Moravec
c8bf06d549 Merge pull request #7401 from bobdenotter/patch-1
[docs] Fix docblock in `inheritance-mapping.rst`
2018-09-23 05:34:59 +02:00
Tim Lieberman
3acfa50214 Fix for BC break #7366 when calling EM::find() with LockMode::OPTIMISTIC outside of a TX 2018-09-23 05:33:05 +02:00
sserbin
3dbe205498 Query\Expr::andX(): added string as allowed parameter type 2018-09-23 05:23:49 +02:00
Michael Moravec
899cce8094 Merge pull request #7363 from philippe-unitiz/2.6
Fix compatibility with phan
2018-09-23 05:16:52 +02:00
Bob den Otter
7400d51444 Fix docblock in inheritance-mapping.rst 2018-09-23 05:12:55 +02:00
Michael Moravec
96c344d22b Merge pull request #7345 from guilliamxavier/improve-DOMDocument-construct
Correct DOMDocument constructor in test
2018-09-23 05:11:21 +02:00
Michael Moravec
f48d71ecd0 Merge pull request #7378 from BenMorel/patch-2
Typo fix
2018-09-23 05:05:58 +02:00
philippe-unitiz
d3acbbf79b Fix constructor argument type in Query\Base 2018-09-23 05:02:30 +02:00
philippe-unitiz
cb9ec8234b Fix multiline parameter phpDoc in Query\Expr
See https://github.com/phan/phan/issues/1897 (parser won't accept `@param` spanning over several lines)
2018-09-23 05:02:01 +02:00
Guilliam Xavier
47c72e583e correct load-only DOMDocument constructor in test 2018-09-23 04:52:52 +02:00
Christophe Coevoet
568c2d308c Fix the computation of commit order for circular dependencies
When finding a circular dependencies, we must ensure that all dependencies
of a node have been visited before adding it to the sorted list.
2018-09-20 12:13:25 +02:00
Christophe Coevoet
11a7f359d1 Add a unit test reproducing the commit order regression 2018-09-20 12:11:44 +02:00
Christophe Coevoet
145f1f5198 Add a test reproducing GH7259 2018-09-20 11:53:08 +02:00
Claudio Zizza
ff1df41485 Add deprecation note to getting-started chapter 2018-09-07 21:06:08 +02:00
Claudio Zizza
d36aec8fb7 Add deprecation message for YAML into docs 2018-08-30 23:24:30 +02:00
Benjamin Morel
2779b5ee91 Typo fix 2018-08-28 14:56:01 +02:00
Pierre-Louis FORT
32efbd3edd Handle removed parameters by tree walker in Paginator 2018-08-27 11:23:21 +02:00
Luís Cobucci
68718eac1b Merge pull request #7360 from lcobucci/fix-partial-reference-docblock
Document getPartialReference() properly
2018-08-19 16:25:51 +02:00
Luís Cobucci
7b64b4a207 Document getPartialReference() properly
According to the current implementation that method also returns `null`,
however the interface's documentation was incorrect.

Ref: https://github.com/doctrine/doctrine2/blob/v2.6.2/lib/Doctrine/ORM/EntityManager.php#L514-L516
2018-08-18 14:52:17 +02:00
Michael Moravec
f1143f591f Merge pull request #7325 from paxal/php73_compatible
Make code php 7.3 lint-compatible
2018-08-02 14:23:28 +02:00
Cyril PASCAL
07fc401d25 Make code php 7.3 lint-compatible 2018-07-26 14:32:52 +02:00
Luís Cobucci
96f166a7e9 Merge pull request #7307 from Majkl578/remaining-deprecations
Fix remaining usages of deprecated ClassLoader and Inflector from doctrine/common
2018-07-13 07:27:10 +02:00
Michael Moravec
f4b775323d Fix remaining usages of deprecated ClassLoader and Inflector from doctrine/common 2018-07-13 05:31:39 +02:00
Michael Moravec
43d308116d Bump version to 2.6.3-DEV 2018-07-12 23:24:26 +02:00
Michael Moravec
d2b4dd71d2 Preparing v2.6.2 release 2018-07-12 22:47:13 +02:00
Luís Cobucci
36e6a73d5b Merge pull request #7296 from Majkl578/fix/2.6/#7286
Fix #7286: StringPrimary no longer accepts aggregate functions as argument
2018-07-10 00:05:51 +02:00
Michael Moravec
e26158a45e Fix #7286: StringPrimary no longer accepts aggregate functions as argument 2018-07-09 19:12:39 +02:00
Marco Pivetta
3cfcd6a856 Merge pull request #7291 from Majkl578/fix/2.6/#7068
[2.6] Fix for #7068: EntityManager::find() with pessimistic lock should check for transaction
2018-07-03 09:40:48 +02:00
Michael Kühn
ff68806bfa Fix for #7068: EntityManager::find() with pessimistic lock should check for transaction 2018-07-03 03:00:58 +02:00
Michael Moravec
4192c3abf4 Merge pull request #7290 from Majkl578/dbal-2.8-tests-compat
Fix compatibility with DBAL 2.8 (doctrine/dbal#3157)
2018-07-03 02:58:02 +02:00
Michael Moravec
ac1e1c7d23 Fix compatibility with DBAL 2.8 where OFFSET 0 is no longer generated (doctrine/dbal#3157) 2018-07-03 02:14:23 +02:00
Luís Cobucci
9ab999618c Merge pull request #7276 from Majkl578/entityrepository-count-upgrade
Add UPGRADE note for EntityRepository::count()
2018-07-03 02:05:46 +02:00
Michael Moravec
f2666a472f Add UPGRADE note for EntityRepository::count() 2018-06-27 20:41:59 +02:00
Luís Cobucci
ceda5d3bc7 Merge pull request #7274 from Majkl578/non-deprecated-lexer-and-inflector
Use non-deprecated version of Lexer and Inflector
2018-06-25 23:56:32 +02:00
Michael Moravec
6d81d519b6 Use non-deprecated version of Lexer and Inflector 2018-06-25 14:20:52 +02:00
Marco Pivetta
88d1d79516 Merge pull request #7253 from JarJak/patch-2
Mention that Doctrine does not use Entities public API
2018-06-09 07:28:20 +02:00
Jarek Jakubowski
cfc6cfd1a3 Unnecessary newline removed, small improvements in text 2018-06-09 00:29:59 +02:00
Jarek Jakubowski
6b7d67b427 Add info about Doctrine not using constructor 2018-06-08 20:29:37 +02:00
Jarek Jakubowski
b6d08b15c0 Mention that Doctrine does not use Entities public API 2018-06-08 18:47:39 +02:00
Marco Pivetta
01f89a8cdc Merge pull request #7190 from Tobion/patch-1
Fix wrong type in phpdoc of AbstractIdGenerator
2018-04-13 16:29:25 +01:00
mikeSimonson
efd7a5dca6 Merge pull request #7146 from Awkan/fix/7141-xml-order-by-default-asc
[XML] Fix default value of one-to-many order-by to ASC
2018-04-12 22:29:41 +02:00
Tobias Schultze
7ba0290643 entity should be nullable as in master 2018-04-10 19:15:48 +02:00
Tobias Schultze
8ceb47178b Fix wrong type in phpdoc of AbstractIdGenerator
\Doctrine\ORM\Mapping\Entity is the annotation class which is not correct. The entity object itself is meant here as tests also assume see https://github.com/doctrine/doctrine2/blob/2.6/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php#L28

Found this when running phpstan on our code that used a custom generator.
2018-04-10 18:31:36 +02:00
Donovan Bourlard
2560d4f419 Fix default value of one-to-many order-by to ASC, #7141 2018-03-22 14:51:02 +01:00
Marco Pivetta
87ee409783 Merge pull request #7082 from mariusklocke/issue-7062
Add failing test for issue #7062
2018-02-27 08:30:56 +01:00
Luís Cobucci
d47c1f3e9b Fix basic entity persister type resolver
Which was using the wrong way to fetch the field type and using the
association type instead of the column type.
2018-02-26 14:39:06 +01:00
Marius Klocke
b952dac339 Add a failing test for issue 7062 2018-02-26 14:39:05 +01:00
Luís Cobucci
ffb7d4c79c Merge pull request #7093 from lcobucci/patch-association-identifier-not-quoted
Fix updating entities with quoted identifier association
2018-02-25 20:28:33 +01:00
Jan Langer
e68717b725 Fix updating entities with quoted identifier association 2018-02-25 20:10:18 +01:00
Luís Cobucci
30a063ef9d Merge pull request #6701 from vhenzl/pr/issue-6531-test
Add failing tests for #6531 

Fixes https://github.com/doctrine/doctrine2/issues/6043
Fixes https://github.com/doctrine/doctrine2/issues/6531
Fixes https://github.com/doctrine/doctrine2/issues/7002
Fixes https://github.com/doctrine/doctrine2/pull/7003
2018-02-19 23:17:19 +01:00
Nicolas FRANÇOIS
35c3669ebc Fix handling entities with post generated IDs as FK
This prevents a throw in UnitOfWork#addToIdentityMap because some fields
are null.
2018-02-19 23:05:13 +01:00
Vašek Henzl
23f4f03575 Add failing tests for #6531
Tests are based on examples from "Composite and Foreign Keys as Primary Key" tutorial:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html
2018-02-19 22:14:57 +01:00
Luís Cobucci
a912fc09be Add @group to delete query test 2018-02-19 22:04:28 +01:00
Marco Pivetta
a736a3713b Merge pull request #6988 from kbond/inheritance-issue
Inheritance middle-layer doesn't get hydrated
2018-02-19 12:13:08 +01:00
Luís Cobucci
f2da5bc93e Extract private method to retrieve discriminator values 2018-02-19 12:07:44 +01:00
Luís Cobucci
2905b435db Remove loose comparison on discriminator values
According to mapping drivers the discriminator values can always be
converted to strings so it's safe to assume that we can actually do a
strict comparison during hydration.
2018-02-19 12:07:43 +01:00
Toni Cornelissen
48ca6dbcec Use partial discriminator map on multi-inheritance
Hydrator was ignoring data from subclasses when using multiple
inheritance levels. With this patch it will now use the discriminator
values from all subclasses of the class being hydrated.
2018-02-19 12:07:42 +01:00
Kevin Bond
15a4302902 Inheritance middle-layer doesn't get hydrated with HYDRATE_OBJECT 2018-02-19 12:07:41 +01:00
Marco Pivetta
1f82a20312 Merge pull request #7077 from lcobucci/fix-delete-bc-break
Fix BC-break on delete without alias DQL
2018-02-19 11:32:46 +01:00
Luís Cobucci
fc943b70f6 Use early-returns to improve readability of the Parser 2018-02-19 00:53:42 +01:00
Luís Cobucci
f36470941c Fix BC-break on delete queries with nasty workaround
The `v2.5.x` series of the ORM allowed to have DELETE DQLs without using
an alias, even though it didn't follow the grammar rules of the parser.
We fixed that issue on `v2.6.0` however that was a BC-breaking change
and lots of people were relying on this faulty behaviour.

This workaround fixes the BC-break, without even trying to be elegant.
In `v2.7.0.` we should raise a deprecation notice to notify people that
we'll drop that "feature" in `v3.0`.
2018-02-19 00:53:36 +01:00
Carnage
ae6d80daab Adds sql generation test 2018-02-19 00:50:27 +01:00
Luís Cobucci
44e82e2720 Remove unused functions 2018-02-17 19:49:16 +01:00
Luís Cobucci
e94467d6da Fix incorrect value in L2C+lock test
Which was causing the optimistic lock to fail in MySQL since it was
trying to update the data with exact same value.
2018-02-17 19:46:22 +01:00
Luís Cobucci
794c7708e8 Merge branch 'backport/fix/l2c-version' into 2.6
Backporting https://github.com/doctrine/doctrine2/pull/7069
2018-02-17 18:09:39 +01:00
‘Andrey Lukin’
8e73926359 Add version fields into L2C data 2018-02-17 18:05:32 +01:00
‘Andrey Lukin’
8fc1d74820 Add test for L2C using optimistic locks
As explained in #7067, fields with `@ORM\Version` annotation were not
being added to L2C cached data.
2018-02-17 18:05:27 +01:00
Luís Cobucci
496c6a9f03 Merge branch 'backport/fix-date-issues-once-and-for-all' into 2.6
Backporting https://github.com/doctrine/doctrine2/pull/7055
2018-02-09 17:21:29 +01:00
Luís Cobucci
7873f700b0 Add missing tests for day calculation
For the DATE_SUB() and DATE_ADD() functions.
2018-02-09 17:21:06 +01:00
Luís Cobucci
46c0861f45 Fix date calculation in tests (again)
Now using PHP to calculate the expected date manipulation, keeping a day
as delta since PHP resets the hour when performing operations with
days/weeks/months/years.

February is a wonderful month, isn't it?
2018-02-09 17:21:06 +01:00
Luís Cobucci
5149c0ff25 Merge branch 'backport/fix/7031-tests-february' into 2.6
Backporting: https://github.com/doctrine/doctrine2/pull/7032
2018-02-02 09:07:25 +01:00
Michael Moravec
cf99d62472 QueryDqlFunctionTest: Increase delta for testDateAdd() to work in February 2018-02-02 08:59:35 +01:00
Luís Cobucci
5878797eae Merge pull request #6971 from rolando-caldas/master
Exception Call to undefined method Doctrine\Common\Cache\MemcachedCache::setMemcache()
2018-01-30 01:53:35 +01:00
Rolando Caldas
8c2d090dc8 Exception Call to undefined method Doctrine\Common\Cache\MemcachedCache::setMemcache()
When memcached extension is loaded Doctrine\ORM\Tools\Setup.php  calls to setMemcache method. The MemcachedCache class has the setMemcached method instead. Changed this call in Setup to setMemcached and $memcache to $memcached to keep the name like the extension
2018-01-30 01:38:56 +01:00
Luís Cobucci
3f772eac32 Merge pull request #7021 from lcobucci/fix-phpstan-check
Fix incorrect variable reference
2018-01-30 01:38:21 +01:00
Luís Cobucci
62c952d258 Fix wrong variable reference 2018-01-30 01:21:34 +01:00
Luís Cobucci
c2f698e56e Merge pull request #6997 from NicolaF/fix/fix-6991-2.6
ManyToManyPersister fails to remove join table entry if there is multiple join columns
2018-01-30 01:19:12 +01:00
Nicolas FRANÇOIS
40f2a3efba Add test case for many-to-many collection deletion, when owning side has a composite PK 2018-01-30 01:04:28 +01:00
Nicolas FRANÇOIS
333b9c0b99 Fix #6991: correctly resolve identifer values in ManyToManyPersister 2018-01-19 12:19:02 +01:00
Luís Cobucci
90d19b4131 Bumping development version to v2.6.1-DEV 2017-12-20 02:01:05 +01:00
1366 changed files with 41653 additions and 31474 deletions

55
.doctrine-project.json Normal file
View File

@@ -0,0 +1,55 @@
{
"active": true,
"name": "Object Relational Mapper",
"shortName": "ORM",
"slug": "orm",
"docsSlug": "doctrine-orm",
"versions": [
{
"name": "3.0",
"branchName": "3.0.x",
"slug": "latest",
"upcoming": true
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.7",
"branchName": "2.7",
"slug": "2.7",
"maintained": false
},
{
"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
}
]
}

5
.gitattributes vendored
View File

@@ -1,5 +1,7 @@
/tests export-ignore
/tools export-ignore
/docs export-ignore
/.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitmodules export-ignore
@@ -11,3 +13,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

39
.github/workflows/coding-standard.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: "Coding Standards"
on:
pull_request:
branches:
- "*.x"
push:
branches:
- "*.x"
jobs:
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-20.04"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
with:
dependency-versions: "highest"
# https://github.com/doctrine/.github/issues/3
- name: "Run PHP_CodeSniffer"
run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr"

View File

@@ -0,0 +1,254 @@
name: "Continuous Integration"
on:
pull_request:
push:
env:
fail-fast: true
jobs:
phpunit-smoke-check:
name: "PHPUnit with SQLite"
runs-on: "ubuntu-20.04"
strategy:
matrix:
php-version:
- "7.2"
- "7.3"
- "7.4"
- "8.0"
deps:
- "highest"
include:
- deps: "lowest"
php-version: "7.3"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
extensions: "pdo, pdo_sqlite"
coverage: "pcov"
ini-values: "zend.assertions=1"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
with:
dependency-versions: "${{ matrix.deps }}"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "phpunit-sqlite-${{ matrix.deps }}-${{ matrix.php-version }}-coverage"
path: "coverage*.xml"
phpunit-postgres:
name: "PHPUnit with PostgreSQL"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
postgres-version:
- "9.6"
- "13"
services:
postgres:
image: "postgres:${{ matrix.postgres-version }}"
env:
POSTGRES_PASSWORD: "postgres"
options: >-
--health-cmd "pg_isready"
ports:
- "5432:5432"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-coverage"
path: "coverage.xml"
phpunit-mariadb:
name: "PHPUnit with MariaDB"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
mariadb-version:
- "10.5"
extension:
- "mysqli"
- "pdo_mysql"
services:
mariadb:
image: "mariadb:${{ matrix.mariadb-version }}"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: "doctrine_tests"
options: >-
--health-cmd "mysqladmin ping --silent"
ports:
- "3306:3306"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
extensions: "${{ matrix.extension }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
path: "coverage.xml"
phpunit-mysql:
name: "PHPUnit with MySQL"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
mysql-version:
- "5.7"
- "8.0"
extension:
- "mysqli"
- "pdo_mysql"
services:
mysql:
image: "mysql:${{ matrix.mysql-version }}"
options: >-
--health-cmd "mysqladmin ping --silent"
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes
-e MYSQL_DATABASE=doctrine_tests
ports:
- "3306:3306"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
extensions: "${{ matrix.extension }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage files"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
path: "coverage*.xml"
upload_coverage:
name: "Upload coverage to Codecov"
runs-on: "ubuntu-20.04"
needs:
- "phpunit-smoke-check"
- "phpunit-postgres"
- "phpunit-mariadb"
- "phpunit-mysql"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Download coverage files"
uses: "actions/download-artifact@v2"
with:
path: "reports"
- name: "Upload to Codecov"
uses: "codecov/codecov-action@v1"
with:
directory: reports

View File

@@ -0,0 +1,46 @@
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 }}
"SHELL_VERBOSITY": "3"
- 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 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 }}

65
.github/workflows/static-analysis.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
name: "Static Analysis"
on:
pull_request:
branches:
- "*.x"
push:
branches:
- "*.x"
jobs:
static-analysis-phpstan:
name: "Static Analysis with PHPStan"
runs-on: "ubuntu-20.04"
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: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
with:
dependency-versions: "highest"
- name: "Run a static analysis with phpstan/phpstan"
run: "vendor/bin/phpstan analyse"
static-analysis-psalm:
name: "Static Analysis with Psalm"
runs-on: "ubuntu-20.04"
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: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
with:
dependency-versions: "highest"
- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"

3
.gitignore vendored
View File

@@ -12,6 +12,7 @@ lib/Doctrine/DBAL
.idea
*.iml
vendor/
composer.lock
/tests/Doctrine/Performance/history.db
/.phpcs-cache
composer.lock
/.phpunit.result.cache

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

View File

@@ -1,101 +0,0 @@
dist: trusty
sudo: false
language: php
php:
- 7.1
- 7.2
- nightly
env:
- DB=sqlite
- DB=mysql
- DB=pgsql
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
script:
- if [[ "$DB" == "mysql" || "$DB" == "mariadb" ]]; then mysql -e "CREATE SCHEMA doctrine_tests; GRANT ALL PRIVILEGES ON doctrine_tests.* to travis@'%'"; fi
- ENABLE_SECOND_LEVEL_CACHE=0 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml
- ENABLE_SECOND_LEVEL_CACHE=1 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --exclude-group performance,non-cacheable,locking_functional
jobs:
include:
- stage: Test
env: DB=mariadb
addons:
mariadb: 10.1
- stage: Test
env: DB=mysql MYSQL_VERSION=5.7
php: 7.1
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
env: DB=mysql MYSQL_VERSION=5.7
php: 7.2
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
env: DB=mysql MYSQL_VERSION=5.7
php: nightly
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
env: DB=sqlite DEPENDENCIES=low
install: travis_retry composer update --prefer-dist --prefer-lowest
- stage: Test
if: type = cron
env: DB=sqlite DEV_DEPENDENCIES
install:
- composer config minimum-stability dev
- travis_retry composer update --prefer-dist
- stage: Test
env: DB=sqlite COVERAGE
before_script:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,}
- 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
- stage: Code Quality
env: DB=none BENCHMARK
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
env: DB=none CODING_STANDARDS
php: nightly
script:
- ./vendor/bin/phpcs
allow_failures:
- php: nightly
cache:
directories:
- $HOME/.composer/cache

View File

@@ -6,30 +6,17 @@ Before we can merge your Pull-Request here are some guidelines that you need to
These guidelines exist not to annoy you, but to keep the code base clean,
unified and future proof.
## We only accept PRs to "master"
Doctrine has [general contributing guidelines][contributor workflow], make
sure you follow them.
Our branching strategy is "everything to master first", even
bugfixes and we then merge them into the stable branches. You should only
open pull requests against the master branch. Otherwise we cannot accept the PR.
There is one exception to the rule, when we merged a bug into some stable branches
we do occasionally accept pull requests that merge the same bug fix into earlier
branches.
[contributor workflow]: https://www.doctrine-project.org/contribute/index.html
## Coding Standard
We use PSR-1 and PSR-2:
This project follows [`doctrine/coding-standard`][coding standard homepage].
You may fix many some of the issues with `vendor/bin/phpcbf`.
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
with some exceptions/differences:
* Keep the nesting of control structures per method as small as possible
* Align equals (=) signs
* Add spaces between assignment, control and return statements
* Prefer early exit over nesting conditions
* Add spaces around a negation if condition ``if ( ! $cond)``
[coding standard homepage]: https://github.com/doctrine/coding-standard
## Unit-Tests
@@ -44,37 +31,31 @@ 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
```
To run the testsuite against another database, copy the ``phpunit.xml.dist``
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
take a look at the ``tests/travis`` folder for some examples. Then run:
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
vendor/bin/phpunit -c mysql.phpunit.xml
If you do not provide these parameters, the test suite will use an in-memory
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/2.8.x/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
example.
## Travis
We automatically run your pull request through [Travis CI](http://www.travis-ci.org)
against SQLite, MySQL and PostgreSQL. If you break the tests, we cannot merge your code,
so please make sure that your code is working before opening up a Pull-Request.
## Getting merged
Please allow us time to review your pull requests. We will give our best to review

View File

@@ -1,7 +1,7 @@
| [Master][Master] | [2.5][2.5] |
|:----------------:|:----------:|
| [![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] |
| [3.0.x][3.0] | [2.9.x][2.9] | [2.8.x][2.8] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.9 image]][2.9] | [![Build status][2.8 image]][2.8] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.9 coverage image]][2.9 coverage] | [![Coverage Status][2.8 coverage image]][2.8 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
@@ -13,14 +13,18 @@ without requiring unnecessary code duplication.
## More resources:
* [Website](http://www.doctrine-project.org)
* [Documentation](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
* [Documentation](https://www.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
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
[2.9 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.9.x
[2.9]: https://github.com/doctrine/orm/tree/2.9.x
[2.9 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.9.x/graph/badge.svg
[2.9 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.9.x
[2.8 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg
[2.8]: https://github.com/doctrine/orm/tree/2.8
[2.8 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.8.x/graph/badge.svg
[2.8 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.8.x

View File

@@ -10,8 +10,8 @@ we cannot protect you from SQL injection.
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)
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/security.html)
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/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

View File

@@ -1,5 +1,166 @@
# Upgrade to 2.8
## Minor BC BREAK: Failed commit now throw OptimisticLockException
Method `Doctrine\ORM\UnitOfWork#commit()` can throw an OptimisticLockException when a commit silently fails and returns false
since `Doctrine\DBAL\Connection#commit()` signature changed from returning void to boolean
## Deprecated: `Doctrine\ORM\AbstractQuery#iterator()`
The method `Doctrine\ORM\AbstractQuery#iterator()` is deprecated in favor of `Doctrine\ORM\AbstractQuery#toIterable()`.
Note that `toIterable()` yields results of the query, unlike `iterator()` which yielded each result wrapped into an array.
# 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
`Doctrine\ORM\EntityRepository::count()` has been added. This new method has different
signature than `Countable::count()` (required parameter) and therefore are not compatible.
If your repository implemented the `Countable` interface, you will have to use
`$repository->count([])` instead and not implement `Countable` interface anymore.
## Minor BC BREAK: `Doctrine\ORM\Tools\Console\ConsoleRunner` is now final
Since it's just an utilitarian class and should not be inherited.
@@ -13,13 +174,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
@@ -35,7 +196,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()`
@@ -290,17 +451,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
@@ -389,7 +550,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

View File

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

View File

@@ -1,9 +1,9 @@
@echo off
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\doctrine" %*
@echo off
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\doctrine" %*

View File

@@ -1,3 +0,0 @@
# Version class and file
project.version_class = Doctrine\\ORM\\Version
project.version_file = lib/Doctrine/ORM/Version.php

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
build.xml
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>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
>
<php>
<var name="db_driver" value="mysqli"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>
<var name="db_user" value="root" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
>
<php>
<var name="db_driver" value="pdo_mysql"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>
<var name="db_user" value="root" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
>
<php>
<var name="db_driver" value="pdo_pgsql"/>
<var name="db_host" value="localhost" />
<var name="db_user" value="postgres" />
<var name="db_password" value="postgres" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
>
<php>
<!-- use an in-memory sqlite database -->
<var name="db_driver" value="pdo_sqlite"/>
<var name="db_memory" value="true"/>
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

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"},
@@ -16,21 +16,27 @@
"sort-packages": true
},
"require": {
"php": "^7.1",
"php": "^7.2|^8.0",
"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.11.1",
"doctrine/cache": "^1.9.1",
"doctrine/collections": "^1.5",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.10.0",
"doctrine/event-manager": "^1.1",
"doctrine/inflector": "^1.4|^2.0",
"doctrine/instantiator": "^1.3",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^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": "^8.0",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^8.5|^9.4",
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "4.1.1"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
@@ -45,12 +51,7 @@
}
},
"bin": ["bin/doctrine"],
"extra": {
"branch-alias": {
"dev-master": "2.6.x-dev"
}
},
"archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
}
}

View File

@@ -1,4 +1,4 @@
The Doctrine2 documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
Creative Commons Legal Code

View File

@@ -7,4 +7,4 @@ rm build -Rf
sphinx-build en build
sphinx-build -b latex en build/pdf
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex

View File

@@ -1,2 +1,2 @@
#!/bin/bash
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments

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}
),
...
)

View File

@@ -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 */

View File

@@ -6,7 +6,7 @@ Aggregate Fields
You will often come across the requirement to display aggregate
values of data that can be computed by using the MIN, MAX, COUNT or
SUM SQL functions. For any ORM this is a tricky issue
traditionally. Doctrine 2 offers several ways to get access to
traditionally. Doctrine ORM offers several ways to get access to
these values and this article will describe all of them from
different perspectives.
@@ -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.
@@ -32,30 +32,39 @@ Our entities look like:
.. code-block:: php
<?php
namespace Bank\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity
* @ORM\Entity
*/
class Account
{
/** @Id @GeneratedValue @Column(type="integer") */
private $id;
/** @Column(type="string", unique=true) */
private $no;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
* @ORM\Column(type="string", unique=true)
*/
private $entries;
private string $no;
/**
* @Column(type="integer")
* @ORM\OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
*/
private $maxCredit = 0;
private array $entries;
public function __construct($no, $maxCredit = 0)
/**
* @ORM\Column(type="integer")
*/
private int $maxCredit = 0;
public function __construct(string $no, int $maxCredit = 0)
{
$this->no = $no;
$this->maxCredit = $maxCredit;
@@ -64,31 +73,35 @@ Our entities look like:
}
/**
* @Entity
* @ORM\Entity
*/
class Entry
{
/** @Id @GeneratedValue @Column(type="integer") */
private $id;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @ManyToOne(targetEntity="Account", inversedBy="entries")
* @ORM\ManyToOne(targetEntity="Account", inversedBy="entries")
*/
private $account;
private Account $account;
/**
* @Column(type="integer")
* @ORM\Column(type="integer")
*/
private $amount;
private int $amount;
public function __construct($account, $amount)
public function __construct(Account $account, int $amount)
{
$this->account = $account;
$this->amount = $amount;
// more stuff here, from/to whom, stated reason, execution date and such
}
public function getAmount()
public function getAmount(): Amount
{
return $this->amount;
}
@@ -146,12 +159,14 @@ collection, which means we can compute this value at runtime:
class Account
{
// .. previous code
public function getBalance()
public function getBalance(): int
{
$balance = 0;
foreach ($this->entries as $entry) {
$balance += $entry->getAmount();
}
return $balance;
}
}
@@ -175,13 +190,12 @@ relation with this method:
<?php
class Account
{
public function addEntry($amount)
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
return $e;
}
}
@@ -190,7 +204,10 @@ Now look at the following test-code for our entities:
.. code-block:: php
<?php
class AccountTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class AccountTest extends TestCase
{
public function testAddEntry()
{
@@ -208,7 +225,7 @@ Now look at the following test-code for our entities:
{
$account = new Account("123456", $maxCredit = 200);
$this->setExpectedException("Exception");
$this->expectException(Exception::class);
$account->addEntry(-1000);
}
}
@@ -219,9 +236,12 @@ To enforce our rule we can now implement the assertion in
.. code-block:: php
<?php
class Account
{
private function assertAcceptEntryAllowed($amount)
// .. previous code
private function assertAcceptEntryAllowed(int $amount): void
{
$futureBalance = $this->getBalance() + $amount;
$allowedMinimalBalance = ($this->maxCredit * -1);
@@ -266,23 +286,22 @@ entries collection) we want to add an aggregate field called
class Account
{
/**
* @Column(type="integer")
* @ORM\Column(type="integer")
*/
private $balance = 0;
private int $balance = 0;
public function getBalance()
public function getBalance(): int
{
return $this->balance;
}
public function addEntry($amount)
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
$this->balance += $amount;
return $e;
}
}
@@ -306,12 +325,15 @@ potentially lead to inconsistent state. See this example:
.. code-block:: php
<?php
use Bank\Entities\Account;
// The Account $accId has a balance of 0 and a max credit limit of 200:
// request 1 account
$account1 = $em->find('Bank\Entities\Account', $accId);
$account1 = $em->find(Account::class, $accId);
// request 2 account
$account2 = $em->find('Bank\Entities\Account', $accId);
$account2 = $em->find(Account::class, $accId);
$account1->addEntry(-200);
$account2->addEntry(-200);
@@ -322,7 +344,7 @@ The aggregate field ``Account::$balance`` is now -200, however the
SUM over all entries amounts yields -400. A violation of our max
credit rule.
You can use both optimistic or pessimistic locking to save-guard
You can use both optimistic or pessimistic locking to safe-guard
your aggregate fields against this kind of race-conditions. Reading
Eric Evans DDD carefully he mentions that the "Aggregate Root"
(Account in our example) needs a locking mechanism.
@@ -332,10 +354,14 @@ Optimistic locking is as easy as adding a version column:
.. code-block:: php
<?php
class Account
{
/** @Column(type="integer") @Version */
private $version;
/**
* @ORM\Column(type="integer")
* @ORM\Version
*/
private int $version;
}
The previous example would then throw an exception in the face of
@@ -349,9 +375,11 @@ the database using a FOR UPDATE.
.. code-block:: php
<?php
use Bank\Entities\Account;
use Doctrine\DBAL\LockMode;
$account = $em->find('Bank\Entities\Account', $accId, LockMode::PESSIMISTIC_READ);
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_READ);
Keeping Updates and Deletes in Sync
-----------------------------------
@@ -372,5 +400,3 @@ field that offers serious performance benefits over iterating all
the related objects that make up an aggregate value. Finally I
showed how you can ensure that your aggregate fields do not get out
of sync due to race-conditions and concurrent access.

View File

@@ -3,45 +3,45 @@ Persisting the Decorator Pattern
.. sectionauthor:: Chris Woodford <chris.woodford@gmail.com>
This recipe will show you a simple example of how you can use
Doctrine 2 to persist an implementation of the
This recipe will show you a simple example of how you can use
Doctrine ORM to persist an implementation of the
`Decorator Pattern <http://en.wikipedia.org/wiki/Decorator_pattern>`_
Component
---------
The ``Component`` class needs to be persisted, so it's going to
be an ``Entity``. As the top of the inheritance hierarchy, it's going
to have to define the persistent inheritance. For this example, we
will use Single Table Inheritance, but Class Table Inheritance
would work as well. In the discriminator map, we will define two
concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
The ``Component`` class needs to be persisted, so it's going to
be an ``Entity``. As the top of the inheritance hierarchy, it's going
to have to define the persistent inheritance. For this example, we
will use Single Table Inheritance, but Class Table Inheritance
would work as well. In the discriminator map, we will define two
concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
.. code-block:: php
<?php
namespace Test;
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"cc" = "Test\Component\ConcreteComponent",
* @DiscriminatorMap({"cc" = "Test\Component\ConcreteComponent",
"cd" = "Test\Decorator\ConcreteDecorator"})
*/
abstract class Component
{
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
/** @Column(type="string", nullable=true) */
protected $name;
/**
* Get id
* @return integer $id
@@ -50,7 +50,7 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
{
return $this->id;
}
/**
* Set name
* @param string $name
@@ -59,7 +59,7 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
{
$this->name = $name;
}
/**
* Get name
* @return string $name
@@ -68,33 +68,33 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
{
return $this->name;
}
}
ConcreteComponent
-----------------
The ``ConcreteComponent`` class is pretty simple and doesn't do much
more than extend the abstract ``Component`` class (only for the
The ``ConcreteComponent`` class is pretty simple and doesn't do much
more than extend the abstract ``Component`` class (only for the
purpose of keeping this example simple).
.. code-block:: php
<?php
namespace Test\Component;
use Test\Component;
/** @Entity */
class ConcreteComponent extends Component
{}
Decorator
---------
The ``Decorator`` class doesn't need to be persisted, but it does
need to define an association with a persisted ``Entity``. We can
The ``Decorator`` class doesn't need to be persisted, but it does
need to define an association with a persisted ``Entity``. We can
use a ``MappedSuperclass`` for this.
.. code-block:: php
@@ -102,17 +102,17 @@ use a ``MappedSuperclass`` for this.
<?php
namespace Test;
/** @MappedSuperclass */
abstract class Decorator extends Component
{
/**
* @OneToOne(targetEntity="Test\Component", cascade={"all"})
* @JoinColumn(name="decorates", referencedColumnName="id")
*/
protected $decorates;
/**
* initialize the decorator
* @param Component $c
@@ -121,7 +121,7 @@ use a ``MappedSuperclass`` for this.
{
$this->setDecorates($c);
}
/**
* (non-PHPdoc)
* @see Test.Component::getName()
@@ -130,7 +130,7 @@ use a ``MappedSuperclass`` for this.
{
return 'Decorated ' . $this->getDecorates()->getName();
}
/**
* the component being decorated
* @return Component
@@ -139,7 +139,7 @@ use a ``MappedSuperclass`` for this.
{
return $this->decorates;
}
/**
* sets the component being decorated
* @param Component $c
@@ -148,52 +148,52 @@ use a ``MappedSuperclass`` for this.
{
$this->decorates = $c;
}
}
All operations on the ``Decorator`` (i.e. persist, remove, etc) will
cascade from the ``Decorator`` to the ``Component``. This means that
when we persist a ``Decorator``, Doctrine will take care of
persisting the chain of decorated objects for us. A ``Decorator`` can
be treated exactly as a ``Component`` when it comes time to
All operations on the ``Decorator`` (i.e. persist, remove, etc) will
cascade from the ``Decorator`` to the ``Component``. This means that
when we persist a ``Decorator``, Doctrine will take care of
persisting the chain of decorated objects for us. A ``Decorator`` can
be treated exactly as a ``Component`` when it comes time to
persisting it.
The ``Decorator's`` constructor accepts an instance of a
``Component``, as defined by the ``Decorator`` pattern. The
setDecorates/getDecorates methods have been defined as protected to
hide the fact that a ``Decorator`` is decorating a ``Component`` and
keeps the ``Component`` interface and the ``Decorator`` interface
The ``Decorator's`` constructor accepts an instance of a
``Component``, as defined by the ``Decorator`` pattern. The
setDecorates/getDecorates methods have been defined as protected to
hide the fact that a ``Decorator`` is decorating a ``Component`` and
keeps the ``Component`` interface and the ``Decorator`` interface
identical.
To illustrate the intended result of the ``Decorator`` pattern, the
getName() method has been overridden to append a string to the
To illustrate the intended result of the ``Decorator`` pattern, the
getName() method has been overridden to append a string to the
``Component's`` getName() method.
ConcreteDecorator
-----------------
The final class required to complete a simple implementation of the
Decorator pattern is the ``ConcreteDecorator``. In order to further
illustrate how the ``Decorator`` can alter data as it moves through
the chain of decoration, a new field, "special", has been added to
this class. The getName() has been overridden and appends the value
of the getSpecial() method to its return value.
The final class required to complete a simple implementation of the
Decorator pattern is the ``ConcreteDecorator``. In order to further
illustrate how the ``Decorator`` can alter data as it moves through
the chain of decoration, a new field, "special", has been added to
this class. The getName() has been overridden and appends the value
of the getSpecial() method to its return value.
.. code-block:: php
<?php
namespace Test\Decorator;
use Test\Decorator;
/** @Entity */
class ConcreteDecorator extends Decorator
{
/** @Column(type="string", nullable=true) */
protected $special;
/**
* Set special
* @param string $special
@@ -202,7 +202,7 @@ of the getSpecial() method to its return value.
{
$this->special = $special;
}
/**
* Get special
* @return string $special
@@ -211,7 +211,7 @@ of the getSpecial() method to its return value.
{
return $this->special;
}
/**
* (non-PHPdoc)
* @see Test.Component::getName()
@@ -219,55 +219,55 @@ of the getSpecial() method to its return value.
public function getName()
{
return '[' . $this->getSpecial()
. '] ' . parent::getName();
. '] ' . parent::getName();
}
}
Examples
--------
Here is an example of how to persist and retrieve your decorated
Here is an example of how to persist and retrieve your decorated
objects
.. code-block:: php
<?php
use Test\Component\ConcreteComponent,
Test\Decorator\ConcreteDecorator;
// assumes Doctrine 2 is configured and an instance of
// assumes Doctrine ORM is configured and an instance of
// an EntityManager is available as $em
// create a new concrete component
$c = new ConcreteComponent();
$c->setName('Test Component 1');
$em->persist($c); // assigned unique ID = 1
// create a new concrete decorator
$c = new ConcreteComponent();
$c->setName('Test Component 2');
$d = new ConcreteDecorator($c);
$d->setSpecial('Really');
$em->persist($d);
$em->persist($d);
// assigns c as unique ID = 2, and d as unique ID = 3
$em->flush();
$c = $em->find('Test\Component', 1);
$d = $em->find('Test\Component', 3);
echo get_class($c);
// prints: Test\Component\ConcreteComponent
echo $c->getName();
// prints: Test Component 1
echo get_class($d)
// prints: Test Component 1
echo get_class($d)
// prints: Test\Component\ConcreteDecorator
echo $d->getName();
// prints: [Really] Decorated Test Component 2

View File

@@ -1,4 +1,4 @@
Extending DQL in Doctrine 2: Custom AST Walkers
Extending DQL in Doctrine ORM: Custom AST Walkers
===============================================
.. sectionauthor:: Benjamin Eberlei <kontakt@beberlei.de>
@@ -12,7 +12,7 @@ the Doctrine ORM.
In Doctrine 1 the DQL language was not implemented using a real
parser. This made modifications of the DQL by the user impossible.
Doctrine 2 in contrast has a real parser for the DQL language,
Doctrine ORM in contrast has a real parser for the DQL language,
which transforms the DQL statement into an
`Abstract Syntax Tree <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_
and generates the appropriate SQL statement for it. Since this
@@ -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

View File

@@ -10,7 +10,7 @@ change it during the life of your project. This decision for a
specific vendor potentially allows you to make use of powerful SQL
features that are unique to the vendor.
It is worth to mention that Doctrine 2 also allows you to handwrite
It is worth to mention that Doctrine ORM also allows you to handwrite
your SQL instead of extending the DQL parser. Extending DQL is sort of an
advanced extension point. You can map arbitrary SQL to your objects
and gain access to vendor specific functionalities using the
@@ -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:
@@ -240,12 +240,12 @@ functionalities in DQL, we would be excited to see user extensions
that add vendor specific function packages, for example more math
functions, XML + GIS Support, Hashing functions and so on.
For 2.0 we will come with the current set of functions, however for
For ORM we will come with the current set of functions, however for
a future version we will re-evaluate if we can abstract even more
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>`_.

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

View File

@@ -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
{

View File

@@ -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:

View File

@@ -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!

View File

@@ -1,12 +1,12 @@
Mysql Enums
===========
The type system of Doctrine 2 consists of flyweights, which means there is only
The type system of Doctrine ORM consists of flyweights, which means there is only
one instance of any given type. Additionally types do not contain state. Both
assumptions make it rather complicated to work with the Enum Type of MySQL that
is used quite a lot by developers.
When using Enums with a non-tweaked Doctrine 2 application you will get
When using Enums with a non-tweaked Doctrine ORM application you will get
errors from the Schema-Tool commands due to the unknown database type "enum".
By default Doctrine does not map the MySQL enum type to a Doctrine type.
This is because Enums contain state (their allowed values) and Doctrine

View File

@@ -1,13 +1,11 @@
Keeping your Modules independent
=================================
.. versionadded:: 2.2
One of the goals of using modules is to create discrete units of functionality
that do not have many (if any) dependencies, allowing you to use that
functionality in other applications without including unnecessary items.
Doctrine 2.2 includes a new utility called the ``ResolveTargetEntityListener``,
Doctrine ORM includes a new utility called the ``ResolveTargetEntityListener``,
that functions by intercepting certain calls inside Doctrine and rewrite
targetEntity parameters in your metadata mapping at runtime. It means that
in your bundle you are able to use an interface or abstract class in your

View File

@@ -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
@@ -30,7 +30,7 @@ highly uncomfortable because of the following:
every panel-type? This wouldn't be flexible. You might be tempted
to add an AbstractPanelEntity and an AbstractBlockEntity that use
class inheritance. Your page could then only confer to the
AbstractPanelType and Doctrine 2 would do the rest for you, i.e.
AbstractPanelType and Doctrine ORM would do the rest for you, i.e.
load the right entities. But - you'll for sure have lots of panels
and blocks, and even worse, you'd have to edit the discriminator
map *manually* every time you or another developer implements a new
@@ -152,7 +152,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
/**
* This var contains the classname of the strategy
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine 2)
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine ORM)
*
* This is a doctrine field, so make sure that you use an @column annotation or setup your
* yaml or xml files correctly
@@ -161,7 +161,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
protected $strategyClassName;
/**
* This var contains an instance of $this->blockStrategy. Will not be persisted by Doctrine 2.
* This var contains an instance of $this->blockStrategy. Will not be persisted by Doctrine ORM.
*
* @var BlockStrategyInterface
*/
@@ -199,7 +199,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
$strategy->setBlockEntity($this);
}
Now, the important point is that $strategyClassName is a Doctrine 2
Now, the important point is that $strategyClassName is a Doctrine ORM
field, i.e. Doctrine will persist this value. This is only the
class name of your strategy and not an instance!

View File

@@ -3,7 +3,7 @@ Validation of Entities
.. sectionauthor:: Benjamin Eberlei <kontakt@beberlei.de>
Doctrine 2 does not ship with any internal validators, the reason
Doctrine ORM does not ship with any internal validators, the reason
being that we think all the frameworks out there already ship with
quite decent ones that can be integrated into your Domain easily.
What we offer are hooks to execute any kind of validation.
@@ -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`

View File

@@ -1,9 +1,9 @@
Working with DateTime Instances
===============================
There are many nitty gritty details when working with PHPs DateTime instances. You have know their inner
There are many nitty gritty details when working with PHPs DateTime instances. You have to know their inner
workings pretty well not to make mistakes with date handling. This cookbook entry holds several
interesting pieces of information on how to work with PHP DateTime instances in Doctrine 2.
interesting pieces of information on how to work with PHP DateTime instances in ORM.
DateTime changes are detected by Reference
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -58,7 +58,7 @@ Handling different Timezones with the DateTime Type
If you first come across the requirement to save different timezones you may be still optimistic about how
to manage this mess,
however let me crush your expectations fast. There is not a single database out there (supported by Doctrine 2)
however let me crush your expectations fast. There is not a single database out there (supported by Doctrine ORM)
that supports timezones correctly. Correctly here means that you can cover all the use-cases that
can come up with timezones. If you don't believe me you should read up on `Storing DateTime
in Databases <http://derickrethans.nl/storing-date-time-in-database.html>`_.
@@ -67,7 +67,7 @@ The problem is simple. Not a single database vendor saves the timezone, only the
However with frequent daylight saving and political timezone changes you can have a UTC offset that moves
in different offset directions depending on the real location.
The solution for this dilemma is simple. Don't use timezones with DateTime and Doctrine 2. However there is a workaround
The solution for this dilemma is simple. Don't use timezones with DateTime and Doctrine ORM. However there is a workaround
that even allows correct date-time handling with timezones:
1. Always convert any DateTime instance to UTC.
@@ -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

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>`

View File

@@ -1,113 +1,113 @@
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -11,15 +11,15 @@ steps of configuration.
<?php
use Doctrine\ORM\EntityManager,
Doctrine\ORM\Configuration;
// ...
if ($applicationMode == "development") {
$cache = new \Doctrine\Common\Cache\ArrayCache;
} else {
$cache = new \Doctrine\Common\Cache\ApcCache;
}
$config = new Configuration;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
@@ -27,18 +27,18 @@ steps of configuration.
$config->setQueryCacheImpl($cache);
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');
if ($applicationMode == "development") {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
$connectionOptions = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
$em = EntityManager::create($connectionOptions, $config);
.. note::
@@ -259,7 +259,7 @@ In a production environment, it is highly recommended to use
AUTOGENERATE_NEVER to allow for optimal performances. The other
options are interesting in development environment.
Before v2.4, ``setAutoGenerateProxyClasses`` would accept a boolean
``setAutoGenerateProxyClasses`` can accept a boolean
value. This is still possible, ``FALSE`` being equivalent to
AUTOGENERATE_NEVER and ``TRUE`` to AUTOGENERATE_ALWAYS.
@@ -292,14 +292,14 @@ 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
-------------
A proxy object is an object that is put in place or used instead of
the "real" object. A proxy object can add behavior to the object
being proxied without that object being aware of it. In Doctrine 2,
being proxied without that object being aware of it. In ORM,
proxy objects are used to realize several features but mainly for
transparent lazy-loading.
@@ -309,7 +309,7 @@ of the objects. This is an essential property as without it there
would always be fragile partial objects at the outer edges of your
object graph.
Doctrine 2 implements a variant of the proxy pattern where it
Doctrine ORM implements a variant of the proxy pattern where it
generates classes that extend your entity classes and adds
lazy-loading capabilities to them. Doctrine can then give you an
instance of such a proxy class whenever you request an object of
@@ -411,7 +411,7 @@ be found.
Multiple Metadata Sources
-------------------------
When using different components using Doctrine 2 you may end up
When using different components using Doctrine ORM you may end up
with them using two different metadata drivers, for example XML and
YAML. You can use the DriverChain Metadata implementations to
aggregate these drivers based on namespaces:

View File

@@ -5,29 +5,29 @@ You've probably used docblock annotations in some form already,
most likely to provide documentation metadata for a tool like
``PHPDocumentor`` (@author, @link, ...). Docblock annotations are a
tool to embed metadata inside the documentation section which can
then be processed by some tool. Doctrine 2 generalizes the concept
then be processed by some tool. Doctrine ORM generalizes the concept
of docblock annotations so that they can be used for any kind of
metadata and so that it is easy to define new docblock annotations.
In order to allow more involved annotation values and to reduce the
chances of clashes with other docblock annotations, the Doctrine 2
chances of clashes with other docblock annotations, the Doctrine ORM
docblock annotations feature an alternative syntax that is heavily
inspired by the Annotation syntax introduced in Java 5.
The implementation of these enhanced docblock annotations is
located in the ``Doctrine\Common\Annotations`` namespace and
therefore part of the Common package. Doctrine 2 docblock
therefore part of the Common package. Doctrine ORM docblock
annotations support namespaces and nested annotations among other
things. The Doctrine 2 ORM defines its own set of docblock
things. The Doctrine ORM ORM defines its own set of docblock
annotations for supplying object-relational mapping metadata.
.. note::
If you're not comfortable with the concept of docblock
annotations, don't worry, as mentioned earlier Doctrine 2 provides
annotations, don't worry, as mentioned earlier Doctrine ORM provides
XML and YAML alternatives and you could easily implement your own
favourite mechanism for defining ORM metadata.
In this chapter a reference of every Doctrine 2 Annotation is given
In this chapter a reference of every Doctrine ORM Annotation is given
with short explanations on their context and usage.
Index
@@ -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;
@@ -213,7 +213,7 @@ Optional attributes:
~~~~~~~~~~~~~~~~~~~~~
The Change Tracking Policy annotation allows to specify how the
Doctrine 2 UnitOfWork should detect changes in properties of
Doctrine ORM UnitOfWork should detect changes in properties of
entities during flush. By default each entity is checked according
to a deferred implicit strategy, which means upon flush UnitOfWork
compares all the properties of an entity to a previously stored
@@ -254,7 +254,7 @@ Example:
<?php
/**
* @Id
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="CUSTOM")
* @CustomIdGenerator(class="My\Namespace\MyIdGenerator")
@@ -388,7 +388,7 @@ Optional attributes:
EntityRepository. Use of repositories for entities is encouraged to keep
specialized DQL and SQL operations separated from the Model/Domain
Layer.
- **readOnly**: (>= 2.1) Specifies that this entity is marked as read only and not
- **readOnly**: Specifies that this entity is marked as read only and not
considered for change-tracking. Entities of this type can be persisted
and removed though.
@@ -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.
@@ -817,7 +812,7 @@ The @MappedSuperclass annotation cannot be used in conjunction with
Optional attributes:
- **repositoryClass**: (>= 2.2) Specifies the FQCN of a subclass of the EntityRepository.
- **repositoryClass**: Specifies the FQCN of a subclass of the EntityRepository.
That will be inherited for all subclasses of that Mapped Superclass.
Example:
@@ -1236,7 +1231,7 @@ Optional attributes:
- **indexes**: Array of @Index annotations
- **uniqueConstraints**: Array of @UniqueConstraint annotations.
- **schema**: (>= 2.5) Name of the schema the table lies in.
- **schema**: Name of the schema the table lies in.
Example:

View File

@@ -2,29 +2,29 @@ Architecture
============
This chapter gives an overview of the overall architecture,
terminology and constraints of Doctrine 2. It is recommended to
terminology and constraints of Doctrine ORM. It is recommended to
read this chapter carefully.
Using an Object-Relational Mapper
---------------------------------
As the term ORM already hints at, Doctrine 2 aims to simplify the
As the term ORM already hints at, Doctrine ORM aims to simplify the
translation between database rows and the PHP object model. The
primary use case for Doctrine are therefore applications that
utilize the Object-Oriented Programming Paradigm. For applications
that do not primarily work with objects Doctrine 2 is not suited very
that do not primarily work with objects Doctrine ORM is not suited very
well.
Requirements
------------
Doctrine 2 requires a minimum of PHP 5.4. For greatly improved
Doctrine ORM requires a minimum of PHP 7.1. For greatly improved
performance it is also recommended that you use APC with PHP.
Doctrine 2 Packages
Doctrine ORM Packages
-------------------
Doctrine 2 is divided into three main packages.
Doctrine ORM is divided into three main packages.
- Common
- DBAL (includes Common)
@@ -166,8 +166,8 @@ did not find a way yet, if you did, please contact us).
The EntityManager
~~~~~~~~~~~~~~~~~
The ``EntityManager`` class is a central access point to the ORM
functionality provided by Doctrine 2. The ``EntityManager`` API is
The ``EntityManager`` class is a central access point to the
functionality provided by Doctrine ORM. The ``EntityManager`` API is
used to manage the persistence of your objects and to query for
persistent objects.

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")
*/
@@ -313,8 +313,8 @@ One-To-Many, Bidirectional
--------------------------
A one-to-many association has to be bidirectional, unless you are using a
join table. This is because the many side in a one-to-many association holds
the foreign key, making it the owning side. Doctrine needs the many side
join table. This is because the "many" side in a one-to-many association holds
the foreign key, making it the owning side. Doctrine needs the "many" side
defined in order to understand the association.
This bidirectional mapping requires the ``mappedBy`` attribute on the
@@ -335,7 +335,7 @@ bidirectional many-to-one.
{
// ...
/**
* One Product has Many Features.
* One product has many features. This is the inverse side.
* @OneToMany(targetEntity="Feature", mappedBy="product")
*/
private $features;
@@ -351,7 +351,7 @@ bidirectional many-to-one.
{
// ...
/**
* Many Features have One Product.
* Many features have one product. This is the owning side.
* @ManyToOne(targetEntity="Product", inversedBy="features")
* @JoinColumn(name="product_id", referencedColumnName="id")
*/

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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -423,7 +423,7 @@ performance of Doctrine. The allocationSize specifies by how much
values the sequence is incremented whenever the next value is
retrieved. If this is larger than 1 (one) Doctrine can generate
identifier values for the allocationSizes amount of entities. In
the above example with ``allocationSize=100`` Doctrine 2 would only
the above example with ``allocationSize=100`` Doctrine ORM would only
need to access the sequence once to generate the identifiers for
100 new entities.
@@ -451,7 +451,7 @@ need to access the sequence once to generate the identifiers for
Composite Keys
~~~~~~~~~~~~~~
With Doctrine 2 you can use composite primary keys, using ``@Id`` on more then
With Doctrine ORM you can use composite primary keys, using ``@Id`` on more then
one column. Some restrictions exist opposed to using a single identifier in
this case: The use of the ``@GeneratedValue`` annotation is not supported,
which means you can only use composite keys if you generate the primary key
@@ -484,15 +484,11 @@ according to the used database platform.
.. _reference-basic-mapping-custom-mapping-types:
.. versionadded: 2.3
For more control over column quoting the ``Doctrine\ORM\Mapping\QuoteStrategy`` interface
was introduced in 2.3. It is invoked for every column, table, alias and other
was introduced in ORM. It is invoked for every column, table, alias and other
SQL names. You can implement the QuoteStrategy and set it by calling
``Doctrine\ORM\Configuration#setQuoteStrategy()``.
.. versionadded: 2.4
The ANSI Quote Strategy was added, which assumes quoting is not necessary for any SQL name.
You can use it with the following code:

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
------------
@@ -66,7 +75,7 @@ Iterating results
~~~~~~~~~~~~~~~~~
An alternative solution for bulk updates is to use the
``Query#iterate()`` facility to iterate over the query results step
``Query#toIterable()`` facility to iterate over the query results step
by step instead of loading the whole result into memory at once.
The following example shows how to do this, combining the iteration
with the batching strategy that was already used for bulk inserts:
@@ -75,11 +84,9 @@ 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) {
$user = $row[0];
foreach ($q->toIterable() as $user) {
$user->increaseCredit();
$user->calculateNewBonuses();
if (($i % $batchSize) === 0) {
@@ -128,7 +135,7 @@ Iterating results
~~~~~~~~~~~~~~~~~
An alternative solution for bulk deletes is to use the
``Query#iterate()`` facility to iterate over the query results step
``Query#toIterable()`` facility to iterate over the query results step
by step instead of loading the whole result into memory at once.
The following example shows how to do this:
@@ -136,11 +143,10 @@ 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) {
$em->remove($row[0]);
foreach($q->toIterable() as $row) {
$em->remove($row);
if (($i % $batchSize) === 0) {
$em->flush(); // Executes all deletions.
$em->clear(); // Detaches all objects from Doctrine!
@@ -159,20 +165,18 @@ The following example shows how to do this:
Iterating Large Results for Data-Processing
-------------------------------------------
You can use the ``iterate()`` method just to iterate over a large
result and no UPDATE or DELETE intention. The ``IterableResult``
instance returned from ``$query->iterate()`` implements the
Iterator interface so you can process a large result without memory
You can use the ``toIterable()`` method just to iterate over a large
result and no UPDATE or DELETE intention. ``$query->toIterable()`` returns ``iterable``
so you can process a large result without memory
problems using the following approach:
.. code-block:: php
<?php
$q = $this->_em->createQuery('select u from MyProject\Model\User u');
$iterableResult = $q->iterate();
foreach ($iterableResult as $row) {
// do stuff with the data in the row, $row[0] is always the object
foreach ($q->toIterable() as $row) {
// do stuff with the data in the row
// detach from Doctrine, so that it can be Garbage-Collected immediately
$this->_em->detach($row[0]);
}

View File

@@ -1,8 +1,8 @@
Caching
=======
Doctrine provides cache drivers in the ``Common`` package for some
of the most popular caching implementations such as APC, Memcache
Doctrine provides cache drivers in the ``doctrine/cache`` package for some
of the most popular caching implementations such as APCu, Memcache
and Xcache. We also provide an ``ArrayCache`` driver which stores
the data in a PHP array. Obviously, when using ``ArrayCache``, the
cache does not persist between requests, but this is useful for
@@ -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/2.8.x/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.
@@ -327,7 +306,7 @@ the result cache.
<?php
$query = $em->createQuery('select u from \Entities\User u');
$query->useResultCache(true);
$query->enableResultCache();
You can also configure an individual query to use a different
result cache driver.
@@ -335,18 +314,21 @@ result cache driver.
.. code-block:: php
<?php
$query->setResultCacheDriver(new \Doctrine\Common\Cache\ApcuCache());
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$query->setResultCacheDriver($cacheDriver);
.. note::
Setting the result cache driver on the query will
automatically enable the result cache for the query. If you want to
disable it pass false to ``useResultCache()``.
disable it use ``disableResultCache()``.
::
<?php
$query->useResultCache(false);
$query->disableResultCache();
If you want to set the time the cache has to live you can use the
@@ -367,12 +349,12 @@ yourself with the ``setResultCacheId()`` method.
$query->setResultCacheId('my_custom_id');
You can also set the lifetime and cache ID by passing the values as
the second and third argument to ``useResultCache()``.
the first and second argument to ``enableResultCache()``.
.. code-block:: php
<?php
$query->useResultCache(true, 3600, 'my_custom_id');
$query->enableResultCache(3600, 'my_custom_id');
Metadata Cache
~~~~~~~~~~~~~~
@@ -387,7 +369,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 +409,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
--------------

View File

@@ -30,7 +30,7 @@ Deferred Explicit
The deferred explicit policy is similar to the deferred implicit
policy in that it detects changes through a property-by-property
comparison at commit time. The difference is that Doctrine 2 only
comparison at commit time. The difference is that Doctrine ORM only
considers entities that have been explicitly marked for change detection
through a call to EntityManager#persist(entity) or through a save
cascade. All other entities are skipped. This policy therefore
@@ -71,8 +71,8 @@ follows:
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged,
Doctrine\Persistence\PropertyChangedListener;
/**
* @Entity

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::
@@ -116,8 +112,6 @@ You need to register your applications EntityManager to the console tool
to make use of the tasks by creating a ``cli-config.php`` file with the
following content:
On Doctrine 2.4 and above:
.. code-block:: php
<?php
@@ -130,19 +124,3 @@ On Doctrine 2.4 and above:
$entityManager = GetEntityManager();
return ConsoleRunner::createHelperSet($entityManager);
On Doctrine 2.3 and below:
.. code-block:: php
<?php
// cli-config.php
require_once 'my_bootstrap.php';
// Any way to access the EntityManager from your application
$em = GetMyEntityManager();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));

View File

@@ -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
@@ -458,8 +458,6 @@ Get all users that have no phonenumber
Get all instances of a specific type, for use with inheritance
hierarchies:
.. versionadded:: 2.1
.. code-block:: php
<?php
@@ -469,29 +467,25 @@ hierarchies:
Get all users visible on a given website that have chosen certain gender:
.. versionadded:: 2.2
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u FROM User u WHERE u.gender IN (SELECT IDENTITY(agl.gender) FROM Site s JOIN s.activeGenderList agl WHERE s.id = ?1)');
.. versionadded:: 2.4
Starting with 2.4, the IDENTITY() DQL function also works for composite primary keys:
The IDENTITY() DQL function also works for composite primary keys
.. code-block:: php
<?php
$query = $em->createQuery("SELECT IDENTITY(c.location, 'latitude') AS latitude, IDENTITY(c.location, 'longitude') AS longitude FROM Checkpoint c WHERE c.user = ?1");
Joins between entities without associations were not possible until version
2.4, where you can generate an arbitrary join with the following syntax:
Joins between entities without associations are available,
where you can generate an arbitrary join with the following syntax:
.. 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
@@ -534,8 +528,6 @@ You use the partial syntax when joining as well:
"NEW" Operator Syntax
^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 2.4
Using the ``NEW`` operator you can construct Data Transfer Objects (DTOs) directly from DQL queries.
- When using ``SELECT NEW`` you don't need to specify a mapped entity.
@@ -657,6 +649,16 @@ The same restrictions apply for the reference of related entities.
of the query. Additionally Deletes of specified entities are *NOT*
cascaded to related entities even if specified in the metadata.
Comments in queries
-------------------
We can use comments with the SQL syntax of comments.
.. code-block:: sql
SELECT u FROM MyProject\Model\User u
-- my comment
WHERE u.age > 20 -- comment at the end of a line
Functions, Operators, Aggregates
--------------------------------
@@ -691,8 +693,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
@@ -900,7 +902,7 @@ Class Table Inheritance
is an inheritance mapping strategy where each class in a hierarchy
is mapped to several tables: its own table and the tables of all
parent classes. The table of a child class is linked to the table
of a parent class through a foreign key constraint. Doctrine 2
of a parent class through a foreign key constraint. Doctrine ORM
implements this strategy through the use of a discriminator column
in the topmost table of the hierarchy because this is the easiest
way to achieve polymorphic queries with Class Table Inheritance.
@@ -996,8 +998,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 +1175,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 +1455,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.

View File

@@ -1,7 +1,7 @@
Events
======
Doctrine 2 features a lightweight event system that is part of the
Doctrine ORM features a lightweight event system that is part of the
Common package. Doctrine uses it to dispatch system events, mainly
:ref:`lifecycle events <reference-events-lifecycle-events>`.
You can also use it for your own custom events.
@@ -70,7 +70,7 @@ method.
<?php
$evm->removeEventListener(array(self::preFoo, self::postFoo), $this);
The Doctrine 2 event system also has a simple concept of event
The Doctrine ORM event system also has a simple concept of event
subscribers. We can define a simple ``TestEventSubscriber`` class
which implements the ``\Doctrine\Common\EventSubscriber`` interface
and implements a ``getSubscribedEvents()`` method which returns an
@@ -124,7 +124,7 @@ Now you can test the ``$eventSubscriber`` instance to see if the
Naming convention
~~~~~~~~~~~~~~~~~
Events being used with the Doctrine 2 EventManager are best named
Events being used with the Doctrine ORM EventManager are best named
with camelcase and the value of the corresponding constant should
be the name of the constant itself, even with spelling. This has
several reasons:
@@ -145,61 +145,65 @@ 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::
Note that, when using ``Doctrine\ORM\AbstractQuery#iterate()``, ``postLoad``
Note that, when using ``Doctrine\ORM\AbstractQuery#toIterable()``, ``postLoad``
events will be executed immediately after objects are being hydrated, and therefore
associations are not guaranteed to be initialized. It is not safe to combine
usage of ``Doctrine\ORM\AbstractQuery#iterate()`` and ``postLoad`` event
usage of ``Doctrine\ORM\AbstractQuery#toIterable()`` and ``postLoad`` event
handlers.
.. 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.
@@ -217,18 +221,18 @@ These can be hooked into by two different types of event
listeners:
- Lifecycle Callbacks are methods on the entity classes that are
called when the event is triggered. As of v2.4 they receive some kind
called when the event is triggered. They receive some kind
of ``EventArgs`` instance.
- 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
@@ -323,7 +332,7 @@ XML would look something like this:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
/Users/robo/dev/php/Doctrine/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="User">
@@ -374,9 +383,7 @@ defined on your ``User`` model.
Lifecycle Callbacks Event Argument
-----------------------------------
.. versionadded:: 2.4
Since 2.4 the triggered event is given to the lifecycle-callback.
The triggered event is also given to the lifecycle-callback.
With the additional argument you have access to the
``EntityManager`` and ``UnitOfWork`` APIs inside these callback methods.
@@ -405,9 +412,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 +425,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 +447,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 +503,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 +555,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 +588,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 +737,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.
@@ -751,8 +759,6 @@ EntityManager.
Entity listeners
----------------
.. versionadded:: 2.4
An entity listener is a lifecycle listener class used for an entity.
- The entity listener's mapping may be applied to an entity class or mapped superclass.
@@ -985,4 +991,3 @@ process and manipulate the instance.
}
}

View File

@@ -21,12 +21,6 @@ created database tables and columns.
Entity Classes
--------------
I access a variable and its null, what is wrong?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If this variable is a public variable then you are violating one of the criteria for entities.
All properties have to be protected or private for the proxy object pattern to work.
How can I add default values to a column?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -86,7 +80,7 @@ You can solve this exception by:
How can I filter an association?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Natively you can't filter associations in 2.0 and 2.1. You should use DQL queries to query for the filtered set of entities.
You should use DQL queries to query for the filtered set of entities.
I call clear() on a One-To-Many collection but the entities are not deleted
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -104,7 +98,7 @@ How can I add columns to a many-to-many table?
The many-to-many association is only supporting foreign keys in the table definition
To work with many-to-many tables containing extra columns you have to use the
foreign keys as primary keys feature of Doctrine introduced in version 2.1.
foreign keys as primary keys feature of Doctrine ORM.
See :doc:`the tutorial on composite primary keys for more information<../tutorials/composite-primary-keys>`.
@@ -134,10 +128,10 @@ See the previous question for a solution to this task.
Inheritance
-----------
Can I use Inheritance with Doctrine 2?
Can I use Inheritance with Doctrine ORM?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Yes, you can use Single- or Joined-Table Inheritance in Doctrine 2.
Yes, you can use Single- or Joined-Table Inheritance in ORM.
See the documentation chapter on :doc:`inheritance mapping <inheritance-mapping>` for
the details.
@@ -204,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?
----------------------------------

View File

@@ -1,9 +1,7 @@
Filters
=======
.. versionadded:: 2.2
Doctrine 2.2 features a filter system that allows the developer to add SQL to
Doctrine ORM features a filter system that allows the developer to add SQL to
the conditional clauses of queries, regardless the place where the SQL is
generated (e.g. from a DQL query, or by loading associated entities).
@@ -39,7 +37,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

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
--------------------------------
@@ -36,12 +43,14 @@ in scenarios where data is loaded for read-only purposes.
Read-Only Entities
------------------
Starting with Doctrine 2.1 you can mark entities as read only (See metadata mapping
You can mark entities as read only (See metadata mapping
references for details). This means that the entity marked as read only is never considered
for updates, which means when you call flush on the EntityManager these entities are skipped
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
------------------------

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.
@@ -185,7 +185,7 @@ Class Table Inheritance
is an inheritance mapping strategy where each class in a hierarchy
is mapped to several tables: its own table and the tables of all
parent classes. The table of a child class is linked to the table
of a parent class through a foreign key constraint. Doctrine 2
of a parent class through a foreign key constraint. Doctrine ORM
implements this strategy through the use of a discriminator column
in the topmost table of the hierarchy because this is the easiest
way to achieve polymorphic queries with Class Table Inheritance.
@@ -289,9 +289,15 @@ column and cascading on delete.
Overrides
---------
Used to override a mapping for an entity field or relationship.
May be applied to an entity that extends a mapped superclass
to override a relationship or field mapping defined by the mapped superclass.
Used to override a mapping for an entity field or relationship. Can only be
applied to an entity that extends a mapped superclass or uses a trait to
override a relationship or field mapping defined by the mapped superclass or
trait.
It is not possible to override attributes or associations in entity to entity
inheritance scenarios, because this can cause unforseen edge case behavior and
increases complexity in ORM internal classes.
Association Override
@@ -493,7 +499,7 @@ Could be used by an entity that extends a mapped superclass to override a field
* column=@Column(
* name = "guest_id",
* type = "integer",
length = 140
* length = 140
* )
* ),
* @AttributeOverride(name="name",
@@ -501,7 +507,7 @@ Could be used by an entity that extends a mapped superclass to override a field
* name = "guest_name",
* nullable = false,
* unique = true,
length = 240
* length = 240
* )
* )
* })
@@ -584,7 +590,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
--------------

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>`_.

View File

@@ -6,7 +6,7 @@ Therefore we think it is very important to be honest about the
current limitations to our users. Much like every other piece of
software Doctrine2 is not perfect and far from feature complete.
This section should give you an overview of current limitations of
Doctrine 2 as well as critical known issues that you should know
Doctrine ORM as well as critical known issues that you should know
about.
Current Limitations
@@ -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 <http://www.doctrine-project.org/jira/browse/DDC-298>`_.
`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 <http://www.doctrine-project.org/jira/browse/DDC-875>`_ Merge can sometimes add the same entity twice into a collection
- `DDC-763 <http://www.doctrine-project.org/jira/browse/DDC-763>`_ 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 <http://www.doctrine-project.org/jira/browse/DDC-668>`_
- `Evaluate possible ways in which stored-procedures can be used <http://www.doctrine-project.org/jira/browse/DDC-445>`_
- `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 <http://www.doctrine-project.org/jira/browse/DDC-213>`_
`Ticket DDC-213 <https://github.com/doctrine/orm/issues/2817>`_
Mapping many tables to one entity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -107,7 +107,7 @@ to the same entity.
Behaviors
~~~~~~~~~
Doctrine 2 will **never** include a behavior system like Doctrine 1
Doctrine ORM will **never** include a behavior system like Doctrine 1
in the core library. We don't think behaviors add more value than
they cost pain and debugging hell. Please see the many different
blog posts we have written on this topics:
@@ -115,10 +115,9 @@ blog posts we have written on this topics:
- `Doctrine2 "Behaviors" in a Nutshell <http://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html>`_
- `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 ORM Behavioral Extensions <http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
Doctrine 2 has enough hooks and extension points so that **you** can
Doctrine ORM has enough hooks and extension points so that **you** can
add whatever you want on top of it. None of this will ever become
core functionality of Doctrine2 however, you will have to rely on
third party extensions for magical behaviors.
@@ -127,9 +126,9 @@ Nested Set
~~~~~~~~~~
NestedSet was offered as a behavior in Doctrine 1 and will not be
included in the core of Doctrine 2. However there are already two
included in the core of Doctrine ORM. However there are already two
extensions out there that offer support for Nested Set with
Doctrine 2:
ORM:
- `Doctrine2 Hierarchical-Structural Behavior <http://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
@@ -144,17 +143,15 @@ 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 the Open Bugs on Jira for more details on `bugs, improvement and feature
requests
<http://www.doctrine-project.org/jira/secure/IssueNavigator.jspa?reset=true&mode=hide&pid=10032&resolution=-1&sorter/field=updated&sorter/order=DESC>`_.
See bugs, improvement and feature requests on `Github issues <https://github.com/doctrine/orm/issues>`_.
Identifier Quoting and Legacy Databases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For compatibility reasons between all the supported vendors and
edge case problems Doctrine 2 does **NOT** do automatic identifier
edge case problems Doctrine ORM does **NOT** do automatic identifier
quoting. This can lead to problems when trying to get
legacy-databases to work with Doctrine 2.
legacy-databases to work with Doctrine ORM.
- You can quote column-names as described in the

View File

@@ -147,7 +147,7 @@ ClassMetadata
-------------
The last piece you need to know and understand about metadata in
Doctrine 2 is the API of the ``ClassMetadata`` classes. You need to
Doctrine ORM is the API of the ``ClassMetadata`` classes. You need to
be familiar with them in order to implement your own drivers but
more importantly to retrieve mapping information for a certain
entity when needed.

View File

@@ -1,12 +1,14 @@
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.

View File

@@ -80,9 +80,7 @@ with inheritance hierarchies.
The builder extends the ``ResultSetMapping`` class and as such has all the functionality of it as well.
.. versionadded:: 2.4
Starting with Doctrine ORM 2.4 you can generate the ``SELECT`` clause
The ``SELECT`` clause can be generated
from a ``ResultSetMappingBuilder``. You can either cast the builder
object to ``(string)`` and the DQL aliases are used as SQL table aliases
or use the ``generateSelectClause($tableAliases)`` method and pass
@@ -92,7 +90,7 @@ a mapping from DQL alias (key) to SQL alias (value)
<?php
$selectClause = $builder->generateSelectClause(array(
$selectClause = $rsm->generateSelectClause(array(
'u' => 't1',
'g' => 't2'
));

View File

@@ -1,7 +1,7 @@
PHP Mapping
===========
Doctrine 2 also allows you to provide the ORM metadata in the form
Doctrine ORM also allows you to provide the ORM metadata in the form
of plain PHP code using the ``ClassMetadata`` API. You can write
the code in PHP files or inside of a static function named
``loadMetadata($class)`` on the entity class itself.

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:
@@ -257,10 +277,17 @@ following syntax:
.. code-block:: php
<?php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query\Parameter;
// $qb instanceof QueryBuilder
// Query here...
$qb->setParameters(array(1 => 'value for ?1', 2 => 'value for ?2'));
$qb->setParameters(new ArrayCollection([
new Parameter('1', 'value for ?1'),
new Parameter('2', 'value for ?2')
]));
Getting already bound parameters is easy - simply use the above
mentioned syntax with "getParameter()" or "getParameters()":
@@ -334,6 +361,7 @@ a querybuilder instance into a Query object:
// Execute Query
$result = $query->getResult();
$iterableResult = $query->toIterable();
$single = $query->getSingleResult();
$array = $query->getArrayResult();
$scalar = $query->getScalarResult();
@@ -502,7 +530,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 +604,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'));

View File

@@ -77,11 +77,10 @@ A query region might be something like :
Cache Regions
-------------
``Doctrine\ORM\Cache\Region\DefaultRegion`` It's the default implementation.
``Doctrine\ORM\Cache\Region\DefaultRegion`` is the default implementation.
A simplest cache region compatible with all doctrine-cache drivers but does not support locking.
``Doctrine\ORM\Cache\Region`` and ``Doctrine\ORM\Cache\ConcurrentRegion``
Defines contracts that should be implemented by a cache provider.
define contracts that should be implemented by a cache provider.
It allows you to provide your own cache implementation that might take advantage of specific cache driver.
@@ -91,13 +90,10 @@ If you want to support locking for ``READ_WRITE`` strategies you should implemen
Cache region
~~~~~~~~~~~~
Defines a contract for accessing a particular region.
``Doctrine\ORM\Cache\Region`` defines a contract for accessing a particular
cache region.
``Doctrine\ORM\Cache\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
~~~~~~~~~~~~~~~~~~~~~~~
@@ -107,11 +103,9 @@ By default, Doctrine provides a very simple implementation based on file locks `
If you want to use an ``READ_WRITE`` cache, you should consider providing your own cache region.
``Doctrine\ORM\Cache\ConcurrentRegion``
``Doctrine\ORM\Cache\ConcurrentRegion`` defines a contract for concurrently managed data region.
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 +114,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:
@@ -177,7 +171,7 @@ Doctrine allows you to specify configurations and some points of extension for t
Enable Second Level Cache
~~~~~~~~~~~~~~~~~~~~~~~~~
To enable the second-level-cache, you should provide a cache factory
To enable the second-level-cache, you should provide a cache factory.
``\Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
.. code-block:: php
@@ -203,13 +197,18 @@ Cache Factory is the main point of extension.
It allows you to provide a specific implementation of the following components :
* ``QueryCache`` Store and retrieve query cache results.
* ``CachedEntityPersister`` Store and retrieve entity results.
* ``CachedCollectionPersister`` Store and retrieve query results.
* ``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
``QueryCache``
stores and retrieves query cache results.
``CachedEntityPersister``
stores and retrieves entity results.
``CachedCollectionPersister``
stores and retrieves query results.
``EntityHydrator``
transforms entities into a cache entries and cache entries into entities
``CollectionHydrator``
transforms collections into cache entries and cache entries into collections
`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
~~~~~~~~~~~~~~~
@@ -225,8 +224,8 @@ To specify a default lifetime for all regions or specify a different lifetime fo
$regionConfig = $cacheConfig->getRegionsConfiguration();
// Cache Region lifetime
$regionConfig->setLifetime('my_entity_region', 3600); // Time to live for a specific region; In seconds
$regionConfig->setDefaultLifetime(7200); // Default time to live; In seconds
$regionConfig->setLifetime('my_entity_region', 3600); // Time to live for a specific region (in seconds)
$regionConfig->setDefaultLifetime(7200); // Default time to live (in seconds)
Cache Log
@@ -267,18 +266,22 @@ By providing a cache logger you should be able to get information about all cach
// Get the total number of cached entries *not* found in all regions.
$logger->getMissCount();
If you want to get more information you should implement ``\Doctrine\ORM\Cache\Logging\CacheLogger``.
and collect all information you want.
If you want to get more information you should implement
``\Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
all the 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
-----------------------
* Entity cache configuration allows you to define the caching strategy and region for an entity.
* ``usage`` Specifies the caching strategy: ``READ_ONLY``, ``NONSTRICT_READ_WRITE``, ``READ_WRITE``. see :ref:`reference-second-level-cache-mode`
* ``region`` Optional value that specifies the name of the second level cache region.
* ``usage`` specifies the caching strategy: ``READ_ONLY``,
``NONSTRICT_READ_WRITE``, ``READ_WRITE``.
See :ref:`reference-second-level-cache-mode`.
* ``region`` is an optional value that specifies the name of the second
level cache region.
.. configuration-block::
@@ -310,7 +313,7 @@ Entity cache definition
.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Country">
<cache usage="READ_ONLY" region="my_entity_region" />
<id name="id" type="integer" column="id">
@@ -386,7 +389,7 @@ It caches the primary keys of association and cache each element will be cached
.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="State">
<cache usage="NONSTRICT_READ_WRITE" />
@@ -579,7 +582,8 @@ The Cache Mode controls how a particular query interacts with the second-level c
DELETE / UPDATE queries
~~~~~~~~~~~~~~~~~~~~~~~
DQL UPDATE / DELETE statements are ported directly into a database and bypass the second-level cache,
DQL UPDATE / DELETE statements are ported directly into a database and bypass
the second-level cache.
Entities that are already cached will NOT be invalidated.
However the cached data could be evicted using the cache API or an special query hint.
@@ -622,7 +626,7 @@ Using the repository query cache
--------------------------------
As well as ``Query Cache`` all persister queries store only identifier values for an individual query.
All persister use a single timestamps cache region keeps track of the last update for each persister,
All persisters use a single timestamp cache region to keep track of the last update for each persister,
When a query is loaded from cache, the timestamp region is checked for the last update for that persister.
Using the last update timestamps as part of the query key invalidate the cache key when an update occurs.
@@ -641,7 +645,7 @@ Using the last update timestamps as part of the query key invalidate the cache k
$em->clear();
// Reload from database.
// At this point the query cache key if not logger valid, the select goes straight
// At this point the query cache key is no longer valid, the select goes straight to the database
$entities = $em->getRepository('Entity\Country')->findAll();
Cache API
@@ -728,4 +732,5 @@ Paginator
~~~~~~~~~
Count queries generated by ``Doctrine\ORM\Tools\Pagination\Paginator`` are not cached by second-level cache.
Although entities and query result are cached count queries will hit the database every time.
Although entities and query result are cached, count queries will hit the
database every time.

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

View File

@@ -5,7 +5,7 @@ Doctrine Console
----------------
The Doctrine Console is a Command Line Interface tool for simplifying common
administration tasks during the development of a project that uses Doctrine 2.
administration tasks during the development of a project that uses ORM.
Take a look at the :doc:`Installation and Configuration <configuration>`
chapter for more information how to setup the console command.
@@ -27,64 +27,34 @@ Configuration
~~~~~~~~~~~~~
Whenever the ``doctrine`` command line tool is invoked, it can
access all Commands that were registered by developer. There is no
access all Commands that were registered by a developer. There is no
auto-detection mechanism at work. The Doctrine binary
already registers all the commands that currently ship with
Doctrine DBAL and ORM. If you want to use additional commands you
have to register them yourself.
All the commands of the Doctrine Console require access to the ``EntityManager``
or ``DBAL`` Connection. You have to inject them into the console application
using so called Helper-Sets. This requires either the ``db``
or the ``em`` helpers to be defined in order to work correctly.
All the commands of the Doctrine Console require access to the
``EntityManager``. You have to inject it into the console application with
``ConsoleRunner::createHelperSet``. Whenever you invoke the Doctrine
binary, it searches the current directory for the file ``cli-config.php``.
This file contains the project-specific configuration.
Whenever you invoke the Doctrine binary the current folder is searched for a
``cli-config.php`` file. This file contains the project specific configuration:
Here is an example of a the project-specific ``cli-config.php``:
.. code-block:: php
<?php
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($conn)
));
$cli->setHelperSet($helperSet);
use Doctrine\ORM\Tools\Console\ConsoleRunner;
When dealing with the ORM package, the EntityManagerHelper is
required:
// replace this with the path to your own project bootstrap file.
require_once 'bootstrap.php';
.. code-block:: php
// replace with mechanism to retrieve EntityManager in your app
$entityManager = GetEntityManager();
<?php
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));
$cli->setHelperSet($helperSet);
return ConsoleRunner::createHelperSet($entityManager);
The HelperSet instance has to be generated in a separate file (i.e.
``cli-config.php``) that contains typical Doctrine bootstrap code
and predefines the needed HelperSet attributes mentioned above. A
sample ``cli-config.php`` file looks as follows:
.. code-block:: php
<?php
// cli-config.php
require_once 'my_bootstrap.php';
// Any way to access the EntityManager from your application
$em = GetMyEntityManager();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));
It is important to define a correct HelperSet that Doctrine binary
script will ultimately use. The Doctrine Binary will automatically
find the first instance of HelperSet in the global variable
namespace and use this.
.. note::
.. note::
You have to adjust this snippet for your specific application or framework
and use their facilities to access the Doctrine EntityManager and
@@ -252,15 +222,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
-----------------
@@ -384,7 +345,7 @@ First you need to retrieve the metadata instances with the
$em->getConnection()->getSchemaManager()
)
);
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
$cmf->setEntityManager($em);
$metadata = $cmf->getAllMetadata();
@@ -421,7 +382,7 @@ You can also reverse engineer a database using the
Runtime vs Development Mapping Validation
-----------------------------------------
For performance reasons Doctrine 2 has to skip some of the
For performance reasons Doctrine ORM has to skip some of the
necessary validation of metadata mappings. You have to execute
this validation in your development workflow to verify the
associations are correctly defined.
@@ -526,4 +487,3 @@ HelperSet, like it is described in the configuration section.
// Runs console application
$cli->run();

View File

@@ -16,13 +16,13 @@ transaction. Without any explicit transaction demarcation from your
side, this quickly results in poor performance because transactions
are not cheap.
For the most part, Doctrine 2 already takes care of proper
For the most part, Doctrine ORM already takes care of proper
transaction demarcation for you: All the write operations
(INSERT/UPDATE/DELETE) are queued until ``EntityManager#flush()``
is invoked which wraps all of these changes in a single
transaction.
However, Doctrine 2 also allows (and encourages) you to take over
However, Doctrine ORM also allows (and encourages) you to take over
and control transaction demarcation yourself.
These are two ways to deal with transactions when using the
@@ -154,7 +154,7 @@ occurred you should do that with a new ``EntityManager``.
Locking Support
---------------
Doctrine 2 offers support for Pessimistic- and Optimistic-locking
Doctrine ORM offers support for Pessimistic- and Optimistic-locking
strategies natively. This allows to take very fine-grained control
over what kind of locking is required for your Entities in your
application.
@@ -367,7 +367,7 @@ And the change headline action (POST Request):
Pessimistic Locking
~~~~~~~~~~~~~~~~~~~
Doctrine 2 supports Pessimistic Locking at the database level. No
Doctrine ORM supports Pessimistic Locking at the database level. No
attempt is being made to implement pessimistic locking inside
Doctrine, rather vendor-specific and ANSI-SQL commands are used to
acquire row-level locks. Every Entity can be part of a pessimistic
@@ -376,11 +376,11 @@ lock, there is no special metadata required to use this feature.
However for Pessimistic Locking to work you have to disable the
Auto-Commit Mode of your Database and start a transaction around
your pessimistic lock use-case using the "Approach 2: Explicit
Transaction Demarcation" described above. Doctrine 2 will throw an
Transaction Demarcation" described above. Doctrine ORM will throw an
Exception if you attempt to acquire an pessimistic lock and no
transaction is running.
Doctrine 2 currently supports two pessimistic lock modes:
Doctrine ORM currently supports two pessimistic lock modes:
- Pessimistic Write

View File

@@ -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.

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

View File

@@ -15,7 +15,7 @@ with associations in Doctrine:
removed, not the entity itself. A collection of entities always
only represents the association to the containing entities, not the
entity itself.
- When a bidirectional assocation is updated, Doctrine only checks
- When a bidirectional association is updated, Doctrine only checks
on one of both sides for these changes. This is called the :doc:`owning side <unitofwork-associations>`
of the association.
- A property with a reference to many entities has to be instances of the
@@ -407,7 +407,7 @@ There are two approaches to handle this problem in your code:
Transitive persistence / Cascade Operations
-------------------------------------------
Doctrine 2 provides a mechanism for transitive persistence through cascading of certain operations.
Doctrine ORM provides a mechanism for transitive persistence through cascading of certain operations.
Each association to another entity or a collection of
entities can be configured to automatically cascade the following operations to the associated entities:
``persist``, ``remove``, ``merge``, ``detach``, ``refresh`` or ``all``.
@@ -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)``

View File

@@ -25,6 +25,13 @@ Work that have not yet been persisted are lost.
Not calling ``EntityManager#flush()`` will lead to all changes
during that request being lost.
.. note::
Doctrine does NEVER touch the public API of methods in your entity
classes (like getters and setters) nor the constructor method.
Instead, it uses reflection to get/set data from/to your entity objects.
When Doctrine fetches data from DB and saves it back,
any code put in your get/set methods won't be implicitly taken into account.
Entities and the Identity Map
-----------------------------
@@ -41,12 +48,12 @@ headline "Hello World" with the ID 1234:
<?php
$article = $entityManager->find('CMS\Article', 1234);
$article->setHeadline('Hello World dude!');
$article2 = $entityManager->find('CMS\Article', 1234);
echo $article2->getHeadline();
In this case the Article is accessed from the entity manager twice,
but modified in between. Doctrine 2 realizes this and will only
but modified in between. Doctrine ORM realizes this and will only
ever give you access to one instance of the Article with ID 1234,
no matter how often do you retrieve it from the EntityManager and
even no matter what kind of Query method you are using (find,
@@ -93,25 +100,25 @@ from newly opened EntityManager.
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column(type="string") */
private $headline;
/** @ManyToOne(targetEntity="User") */
private $author;
/** @OneToMany(targetEntity="Comment", mappedBy="article") */
private $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
public function getAuthor() { return $this->author; }
public function getComments() { return $this->comments; }
}
$article = $em->find('Article', 1);
This code only retrieves the ``Article`` instance with id 1 executing
@@ -132,22 +139,22 @@ your code. See the following code:
<?php
$article = $em->find('Article', 1);
// accessing a method of the user instance triggers the lazy-load
echo "Author: " . $article->getAuthor()->getName() . "\n";
// Lazy Loading Proxies pass instanceof tests:
if ($article->getAuthor() instanceof User) {
// a User Proxy is a generated "UserProxy" class
}
// accessing the comments as an iterator triggers the lazy-load
// retrieving ALL the comments of this article from the database
// using a single SELECT statement
foreach ($article->getComments() as $comment) {
echo $comment->getText() . "\n\n";
}
// Article::$comments passes instanceof tests for the Collection interface
// But it will NOT pass for the ArrayCollection interface
if ($article->getComments() instanceof \Doctrine\Common\Collections\Collection) {
@@ -167,7 +174,7 @@ methods along the lines of the ``getName()`` method shown below:
{
// lazy loading code
}
public function getName()
{
$this->_load();
@@ -238,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
-----------------
@@ -262,7 +275,7 @@ which means that its persistent state will be deleted once
for and appear in query and collection results. See
the section on :ref:`Database and UnitOfWork Out-Of-Sync <workingobjects_database_uow_outofsync>`
for more information.
Example:
@@ -279,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.
@@ -305,10 +318,10 @@ Deleting an object with all its associated objects can be achieved
in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine 2
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
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
@@ -323,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
------------------
@@ -350,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
@@ -416,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
@@ -633,7 +653,7 @@ just created via the "new" operator).
Querying
--------
Doctrine 2 provides the following ways, in increasing level of
Doctrine ORM provides the following ways, in increasing level of
power and flexibility, to query for persistent objects. You should
always start with the simplest one that suits your needs.
@@ -680,13 +700,13 @@ methods on a repository as follows:
<?php
// $em instanceof EntityManager
// All users that are 20 years old
$users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
// All users that are 20 years old and have a surname of 'Miller'
$users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
// A single user by its nickname
$user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
@@ -722,7 +742,7 @@ examples are equivalent:
<?php
// A single user by its nickname
$user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
// A single user by its nickname (__call magic)
$user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb');
@@ -737,8 +757,6 @@ Additionally, you can just count the result of the provided conditions when you
By Criteria
~~~~~~~~~~~
.. versionadded:: 2.3
The Repository implement the ``Doctrine\Common\Collections\Selectable``
interface. That means you can build ``Doctrine\Common\Collections\Criteria``
and pass them to the ``matching($criteria)`` method.
@@ -780,7 +798,7 @@ A DQL query is represented by an instance of the
<?php
// $em instanceof EntityManager
// All users with an age between 20 and 30 (inclusive).
$q = $em->createQuery("select u from MyDomain\Model\User u where u.age >= 20 and u.age <= 30");
$users = $q->getResult();
@@ -793,7 +811,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>`.
@@ -823,18 +843,18 @@ in a central location.
<?php
namespace MyDomain\Model;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="MyDomain\Model\UserRepository")
*/
class User
{
}
class UserRepository extends EntityRepository
{
public function getAllAdminUsers()
@@ -850,7 +870,7 @@ You can access your repository now by calling:
<?php
// $em instanceof EntityManager
$admins = $em->getRepository('MyDomain\Model\User')->getAllAdminUsers();

View File

@@ -7,10 +7,8 @@ form of XML documents.
The XML driver is backed by an XML Schema document that describes
the structure of a mapping document. The most recent version of the
XML Schema document is available online at
`http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd <http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd>`_.
In order to point to the latest version of the document of a
particular stable release branch, just append the release number,
i.e.: doctrine-mapping-2.0.xsd The most convenient way to work with
`https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd <https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd>`_.
The most convenient way to work with
XML mapping files is to use an IDE/editor that can provide
code-completion based on such an XML Schema document. The following
is an outline of a XML mapping document with the proper xmlns/xsi
@@ -21,7 +19,7 @@ setup for the latest code in trunk.
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
...
@@ -107,7 +105,7 @@ of several common elements:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
@@ -208,10 +206,10 @@ Optional attributes:
- **inheritance-type** - The type of inheritance, defaults to none. A
more detailed description follows in the
*Defining Inheritance Mappings* section.
- **read-only** - (>= 2.1) Specifies that this entity is marked as read only and not
- **read-only** - Specifies that this entity is marked as read only and not
considered for change-tracking. Entities of this type can be persisted
and removed though.
- **schema** - (>= 2.5) The schema the table lies in, for platforms that support schemas
- **schema** - The schema the table lies in, for platforms that support schemas
Defining Fields
~~~~~~~~~~~~~~~
@@ -293,7 +291,7 @@ Defining Identity and Generator Strategies
An entity has to have at least one ``<id />`` element. For
composite keys you can specify more than one id-element, however
surrogate keys are recommended for use with Doctrine 2. The Id
surrogate keys are recommended for use with Doctrine ORM. The Id
field allows to define properties of the identifier and allows a
subset of the ``<field />`` element attributes:
@@ -768,7 +766,7 @@ entity relationship. You can define this in XML with the "association-key" attri
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Application\Model\ArticleAttribute">
<id name="article" association-key="true" />

View File

@@ -1,6 +1,10 @@
YAML Mapping
============
.. note::
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.
The YAML mapping driver enables you to provide the ORM metadata in
form of YAML documents.

83
docs/en/sidebar.rst Normal file
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

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

View File

@@ -1,11 +1,9 @@
Composite and Foreign Keys as Primary Key
=========================================
.. versionadded:: 2.1
Doctrine 2 supports composite primary keys natively. Composite keys are a very powerful relational database concept
and we took good care to make sure Doctrine 2 supports as many of the composite primary key use-cases.
For Doctrine 2.0 composite keys of primitive data-types are supported, for Doctrine 2.1 even foreign keys as
Doctrine ORM supports composite primary keys natively. Composite keys are a very powerful relational database concept
and we took good care to make sure Doctrine ORM supports as many of the composite primary key use-cases.
For Doctrine ORM composite keys of primitive data-types are supported, even foreign keys as
primary keys are supported.
This tutorial shows how the semantics of composite primary keys work and how they map to the database.
@@ -19,7 +17,7 @@ the ID fields have to have their values set before you call ``EntityManager#pers
Primitive Types only
~~~~~~~~~~~~~~~~~~~~
Even in version 2.0 you can have composite keys as long as they only consist of the primitive types
You can have composite keys as long as they only consist of the primitive types
``integer`` and ``string``. Suppose you want to create a database of cars and use the model-name
and year of production as primary keys:
@@ -63,7 +61,7 @@ and year of production as primary keys:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="VehicleCatalogue\Model\Car">
<id field="name" type="string" />
@@ -120,10 +118,6 @@ and to ``year`` to the related entities.
Identity through foreign Entities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
Identity through foreign entities is only supported with Doctrine 2.1
There are tons of use-cases where the identity of an Entity should be determined by the entity
of one or many parent entities.
@@ -203,7 +197,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Application\Model\ArticleAttribute">
<id name="article" association-key="true" />

View File

@@ -5,19 +5,19 @@ Extra Lazy Associations
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
In Doctrine ORM 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
of entities.
With Doctrine 2.1 a feature called **Extra Lazy** is introduced for associations. Associations
Doctrine ORM includes a feature called **Extra Lazy** for associations. Associations
are marked as **Lazy** by default, which means the whole collection object for an association is populated
the first time its accessed. If you mark an association as extra lazy the following methods on collections
can be called without triggering a full load of the collection:
- ``Collection#contains($entity)``
- ``Collection#containsKey($key)`` (available with Doctrine 2.5)
- ``Collection#containsKey($key)``
- ``Collection#count()``
- ``Collection#get($key)`` (available with Doctrine 2.4)
- ``Collection#get($key)``
- ``Collection#slice($offset, $length = null)``
For each of the above methods the following semantics apply:
@@ -25,7 +25,7 @@ For each of the above methods the following semantics apply:
- For each call, if the Collection is not yet loaded, issue a straight SELECT statement against the database.
- For each call, if the collection is already loaded, fallback to the default functionality for lazy collections. No additional SELECT statements are executed.
Additionally even with Doctrine 2.0 the following methods do not trigger the collection load:
Additionally even with Doctrine ORM the following methods do not trigger the collection load:
- ``Collection#add($entity)``
- ``Collection#offsetSet($key, $entity)`` - ArrayAccess with no specific key ``$coll[] = $entity``, it does
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -65,7 +74,7 @@ switch to extra lazy as shown in these examples:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\Models\CMS\CmsGroup">
<!-- ... -->

View File

@@ -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::
@@ -20,8 +20,7 @@ development is said to use the *Database First* approach to Doctrine.
In this workflow you would modify the database schema first and then
regenerate the PHP code to use with this schema. You need a flexible
code-generator for this task and up to Doctrine 2.2, the code generator hasn't
been flexible enough to achieve this.
code-generator for this task.
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
allow you to do *Database First* development.

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.

View File

@@ -19,21 +19,15 @@ 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>`_.
.. note::
This tutorial assumes you work with **Doctrine 2.4** and above.
Some of the code will not work with lower versions.
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 ORM 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 +56,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,21 +67,21 @@ 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
-------------
Create a new empty folder for this tutorial project, for example
``doctrine2-tutorial`` and create a new file ``composer.json`` with
the following contents:
``doctrine2-tutorial`` and create a new file ``composer.json`` inside
that directory with the following contents:
::
{
"require": {
"doctrine/orm": "2.4.*",
"doctrine/orm": "^2.6.2",
"symfony/yaml": "2.*"
},
"autoload": {
@@ -103,25 +97,28 @@ Install Doctrine using the Composer Dependency Management tool, by calling:
$ composer install
This will install the packages Doctrine Common, Doctrine DBAL, Doctrine ORM,
Symfony YAML and Symfony Console into the `vendor` directory. The Symfony
dependencies are not required by Doctrine but will be used in this tutorial.
into the ``vendor`` directory.
Add the following directories:
::
doctrine2-tutorial
|-- config
| |-- xml
| `-- xml
| `-- yaml
`-- src
.. note::
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.
Obtaining the EntityManager
---------------------------
Doctrine's public interface is through the ``EntityManager``. This class
provides access points to the complete lifecycle management for your entities,
and transforms entities from and back to persistence. You have to
configure and create it to use your entities with Doctrine 2. I
configure and create it to use your entities with Doctrine ORM. I
will show the configuration steps and then discuss them step by
step:
@@ -131,26 +128,37 @@ step:
// bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
require_once "vendor/autoload.php";
// 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);
// database configuration parameters
$conn = array(
'driver' => 'pdo_sqlite',
'path' => __DIR__ . '/db.sqlite',
);
// obtaining the entity manager
$entityManager = EntityManager::create($conn, $config);
The require_once statement sets up the class autoloading for Doctrine and
.. note::
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.
The second block consists of the instantiation of the ORM
@@ -162,7 +170,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.
@@ -173,30 +181,29 @@ Generating the Database Schema
Doctrine has a command-line interface that allows you to access the SchemaTool,
a component that can generate a relational database schema based entirely on the
defined entity classes and their metadata. For this tool to work, a
cli-config.php file must exist in the project root directory:
``cli-config.php`` file must exist in the project root directory:
.. code-block:: php
<?php
// cli-config.php
require_once "bootstrap.php";
return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
Change into your project directory and call the Doctrine command-line tool:
Now call the Doctrine command-line tool:
::
$ cd project/
$ vendor/bin/doctrine orm:schema-tool:create
Since we haven't added any entity metadata in `src` yet, you'll see a message
Since we haven't added any entity metadata in ``src`` yet, you'll see a message
stating "No Metadata Classes to process." In the next section, we'll create a
Product entity along with the corresponding metadata, and run this command again.
Note that as you modify your entities' metadata during the development process,
you'll need to update your database schema to stay in sync with the metadata.
You can rasily recreate the database using the following commands:
You can easily recreate the database using the following commands:
::
@@ -209,8 +216,8 @@ Or you can use the update functionality:
$ vendor/bin/doctrine orm:schema-tool:update --force
The updating of databases uses a Diff Algorithm for a given
Database Schema. This is a cornerstone of the ``Doctrine\DBAL`` package,
The updating of databases uses a diff algorithm for a given
database schema. This is a cornerstone of the ``Doctrine\DBAL`` package,
which can even be used without the Doctrine ORM package.
Starting with the Product Entity
@@ -250,16 +257,16 @@ entity definition:
}
}
When creating entity classes, all of the fields should be protected or private
(not public), with getter and setter methods for each one (except $id).
When creating entity classes, all of the fields should be ``protected`` or ``private``
(not ``public``), with getter and setter methods for each one (except ``$id``).
The use of mutators allows Doctrine to hook into calls which
manipulate the entities in ways that it could not if you just
manipulate the entities in ways that it could not if you just
directly set the values with ``entity#field = foo;``
The id field has no setter since, generally speaking, your code
should not set this value since it represents a database id value.
(Note that Doctrine itself can still set the value using the
Reflection API instead of a defined setter function)
The id field has no setter since, generally speaking, your code
should not set this value since it represents a database id value.
(Note that Doctrine itself can still set the value using the
Reflection API instead of a defined setter function.)
The next step for persistence with Doctrine is to describe the
structure of the ``Product`` entity to Doctrine using a metadata
@@ -278,14 +285,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)
@@ -297,7 +314,7 @@ but you only need to choose one.
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Product" table="products">
<id name="id" type="integer">
@@ -308,6 +325,10 @@ but you only need to choose one.
</entity>
</doctrine-mapping>
.. note::
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.
.. code-block:: yaml
# config/yaml/Product.dcm.yml
@@ -323,8 +344,8 @@ but you only need to choose one.
name:
type: string
The top-level ``entity`` definition tag specifies information about
the class and table-name. The primitive type ``Product#name`` is
The top-level ``entity`` definition specifies information about
the class and table name. The primitive type ``Product#name`` is
defined as a ``field`` attribute. The ``id`` property is defined with
the ``id`` tag. It has a ``generator`` tag nested inside, which
specifies that the primary key generation mechanism should automatically
@@ -458,28 +479,37 @@ 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\Entity
* @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;
@@ -524,18 +554,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;
@@ -569,7 +606,7 @@ foreign keys through their own identities.
For every foreign key you either have a Doctrine ManyToOne or OneToOne
association. On the inverse sides of these foreign keys you can have
OneToMany associations. Obviously you can have ManyToMany associations
that connect two tables with each other through a join table with
that connect two tables with each other through a join table with
two foreign keys.
Now that you know the basics about references in Doctrine, we can extend the
@@ -625,12 +662,12 @@ domain model to match the requirements:
Lazy load proxies always contain an instance of
Doctrine's EntityManager and all its dependencies. Therefore a
var\_dump() will possibly dump a very large recursive structure
``var_dump()`` will possibly dump a very large recursive structure
which is impossible to render and read. You have to use
``Doctrine\Common\Util\Debug::dump()`` to restrict the dumping to a
human readable level. Additionally you should be aware that dumping
the EntityManager to a Browser may take several minutes, and the
Debug::dump() method just ignores any occurrences of it in Proxy
``Debug::dump()`` method just ignores any occurrences of it in Proxy
instances.
Because we only work with collections for the references we must be
@@ -638,8 +675,8 @@ careful to implement a bidirectional reference in the domain model.
The concept of owning or inverse side of a relation is central to
this notion and should always be kept in mind. The following
assumptions are made about relations and have to be followed to be
able to work with Doctrine 2. These assumptions are not unique to
Doctrine 2 but are best practices in handling database relations
able to work with Doctrine ORM. These assumptions are not unique to
Doctrine ORM but are best practices in handling database relations
and Object-Relational Mapping.
- In a one-to-one relation, the entity holding the foreign key of
@@ -765,7 +802,7 @@ the database that points from Bugs to Products.
{
// ... (previous code)
protected $products = null;
protected $products;
public function assignToProduct(Product $product)
{
@@ -787,41 +824,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)
@@ -833,7 +879,7 @@ the ``Product`` before:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Bug" table="bugs">
<id name="id" type="integer">
@@ -851,6 +897,10 @@ the ``Product`` before:
</entity>
</doctrine-mapping>
.. note::
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.
.. code-block:: yaml
# config/yaml/Bug.dcm.yml
@@ -882,8 +932,8 @@ the ``Product`` before:
Here we have the entity, id and primitive type definitions.
For the "created" field we have used the ``datetime`` type,
which translates the YYYY-mm-dd HH:mm:ss database format
For the "created" field we have used the ``datetime`` type,
which translates the YYYY-mm-dd HH:mm:ss database format
into a PHP DateTime instance and back.
After the field definitions, the two qualified references to the
@@ -911,34 +961,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)
}
@@ -949,7 +1005,7 @@ Finally, we'll add metadata mappings for the ``User`` entity.
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="User" table="users">
<id name="id" type="integer">
@@ -963,6 +1019,10 @@ Finally, we'll add metadata mappings for the ``User`` entity.
</entity>
</doctrine-mapping>
.. note::
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.
.. code-block:: yaml
# config/yaml/User.dcm.yml
@@ -1145,17 +1205,16 @@ 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.
As a last resort you can still use Native SQL and a description of the
result set to retrieve entities from the database. DQL boils down to a
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
Native SQL you could even use stored procedures for data retrieval, or
make use of advanced non-portable database queries like PostgreSql's
result set to retrieve entities from the database. DQL boils down to a
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
Native SQL you could even use stored procedures for data retrieval, or
make use of advanced non-portable database queries like PostgreSql's
recursive queries.
@@ -1168,7 +1227,7 @@ objects only from Doctrine however. For a simple list view like the
previous one we only need read access to our entities and can
switch the hydration from objects to simple PHP arrays instead.
Hydration can be an expensive process so only retrieving what you need can
Hydration can be an expensive process so only retrieving what you need can
yield considerable performance benefits for read-only requests.
Implementing the same list view as before using array hydration we
@@ -1472,9 +1531,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
{
@@ -1486,13 +1548,17 @@ we have to adjust the metadata slightly.
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Bug" table="bugs" repository-class="BugRepository">
</entity>
</doctrine-mapping>
.. note::
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.
.. code-block:: yaml
Bug:

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

View File

@@ -1,9 +1,7 @@
Pagination
==========
.. versionadded:: 2.2
Starting with version 2.2 Doctrine ships with a Paginator for DQL queries. It
Doctrine ORM ships with a Paginator for DQL queries. It
has a very simple API and implements the SPL interfaces ``Countable`` and
``IteratorAggregate``.

View File

@@ -1,13 +1,9 @@
Working with Indexed Associations
=================================
.. note::
This feature is available from version 2.1 of Doctrine.
Doctrine 2 collections are modelled after PHPs native arrays. PHP arrays are an ordered hashmap, but in
Doctrine ORM collections are modelled after PHPs native arrays. PHP arrays are an ordered hashmap, but in
the first version of Doctrine keys retrieved from the database were always numerical unless ``INDEX BY``
was used. Starting with Doctrine 2.1 you can index your collections by a value in the related entity.
was used. You can index your collections by a value in the related entity.
This is a first step towards full ordered hashmap support through the Doctrine ORM.
The feature works like an implicit ``INDEX BY`` for the selected association but has several
downsides also:
@@ -107,7 +103,7 @@ The code and mappings for the Market entity looks like this:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\Models\StockExchange\Market">
<id name="id" type="integer">
@@ -193,7 +189,7 @@ here are the code and mappings for it:
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\Models\StockExchange\Stock">
<id name="id" type="integer">
@@ -291,6 +287,5 @@ Outlook into the Future
~~~~~~~~~~~~~~~~~~~~~~~
For the inverse side of a many-to-many associations there will be a way to persist the keys and the order
as a third and fourth parameter into the join table. This feature is discussed in `DDC-213 <http://www.doctrine-project.org/jira/browse/DDC-213>`_
as a third and fourth parameter into the join table. This feature is discussed in `#2817 <https://github.com/doctrine/orm/issues/2817>`_
This feature cannot be implemented for one-to-many associations, because they are never the owning side.

View File

@@ -1,4 +1,5 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -19,24 +20,43 @@
namespace Doctrine\ORM;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Collections\Collection;
use Countable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\ORM\Cache\Logging\CacheLogger;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\ORM\Cache\TimestampCacheKey;
use Doctrine\ORM\Internal\Hydration\IterableResult;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\MappingException;
use Traversable;
use function array_map;
use function array_shift;
use function count;
use function is_array;
use function is_numeric;
use function is_object;
use function is_scalar;
use function iterator_count;
use function iterator_to_array;
use function ksort;
use function reset;
use function serialize;
use function sha1;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
*
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
abstract class AbstractQuery
{
@@ -45,39 +65,40 @@ abstract class AbstractQuery
/**
* Hydrates an object graph. This is the default behavior.
*/
const HYDRATE_OBJECT = 1;
public const HYDRATE_OBJECT = 1;
/**
* Hydrates an array graph.
*/
const HYDRATE_ARRAY = 2;
public const HYDRATE_ARRAY = 2;
/**
* Hydrates a flat, rectangular result set with scalar values.
*/
const HYDRATE_SCALAR = 3;
public const HYDRATE_SCALAR = 3;
/**
* Hydrates a single scalar value.
*/
const HYDRATE_SINGLE_SCALAR = 4;
public const HYDRATE_SINGLE_SCALAR = 4;
/**
* Very simple object hydrator (optimized for performance).
*/
const HYDRATE_SIMPLEOBJECT = 5;
public const HYDRATE_SIMPLEOBJECT = 5;
/**
* The parameter map of this query.
*
* @var \Doctrine\Common\Collections\ArrayCollection
* @var ArrayCollection|Parameter[]
* @psalm-var ArrayCollection<int, Parameter>
*/
protected $parameters;
/**
* The user-specified ResultSetMapping to use.
*
* @var \Doctrine\ORM\Query\ResultSetMapping
* @var ResultSetMapping
*/
protected $_resultSetMapping;
@@ -91,44 +112,38 @@ abstract class AbstractQuery
/**
* The map of query hints.
*
* @var array
* @psalm-var array<string, mixed>
*/
protected $_hints = [];
/**
* The hydration mode.
*
* @var integer
* @var string|int
*/
protected $_hydrationMode = self::HYDRATE_OBJECT;
/**
* @var \Doctrine\DBAL\Cache\QueryCacheProfile
*/
/** @var QueryCacheProfile */
protected $_queryCacheProfile;
/**
* Whether or not expire the result cache.
*
* @var boolean
* @var bool
*/
protected $_expireResultCache = false;
/**
* @var \Doctrine\DBAL\Cache\QueryCacheProfile
*/
/** @var QueryCacheProfile */
protected $_hydrationCacheProfile;
/**
* Whether to use second level cache, if available.
*
* @var boolean
* @var bool
*/
protected $cacheable = false;
/**
* @var boolean
*/
/** @var bool */
protected $hasCache = false;
/**
@@ -141,31 +156,25 @@ abstract class AbstractQuery
/**
* Second level query cache mode.
*
* @var integer|null
* @var int|null
*/
protected $cacheMode;
/**
* @var \Doctrine\ORM\Cache\Logging\CacheLogger|null
*/
/** @var CacheLogger|null */
protected $cacheLogger;
/**
* @var integer
*/
/** @var int */
protected $lifetime = 0;
/**
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
* @param \Doctrine\ORM\EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->_em = $em;
$this->parameters = new ArrayCollection();
$this->_hints = $em->getConfiguration()->getDefaultQueryHints();
$this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
$this->_em = $em;
$this->parameters = new ArrayCollection();
$this->_hints = $em->getConfiguration()->getDefaultQueryHints();
$this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
if ($this->hasCache) {
$this->cacheLogger = $em->getConfiguration()
@@ -177,19 +186,19 @@ abstract class AbstractQuery
/**
* Enable/disable second level query (result) caching for this query.
*
* @param boolean $cacheable
* @param bool $cacheable
*
* @return static This query instance.
*/
public function setCacheable($cacheable)
{
$this->cacheable = (boolean) $cacheable;
$this->cacheable = (bool) $cacheable;
return $this;
}
/**
* @return boolean TRUE if the query results are enable for second level cache, FALSE otherwise.
* @return bool TRUE if the query results are enable for second level cache, FALSE otherwise.
*/
public function isCacheable()
{
@@ -209,17 +218,17 @@ abstract class AbstractQuery
}
/**
* Obtain the name of the second level query cache region in which query results will be stored
*
* @return string|null The cache region name; NULL indicates the default region.
*/
* Obtain the name of the second level query cache region in which query results will be stored
*
* @return string|null The cache region name; NULL indicates the default region.
*/
public function getCacheRegion()
{
return $this->cacheRegion;
}
/**
* @return boolean TRUE if the query cache and second level cache are enabled, FALSE otherwise.
* @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise.
*/
protected function isCacheEnabled()
{
@@ -227,7 +236,7 @@ abstract class AbstractQuery
}
/**
* @return integer
* @return int
*/
public function getLifetime()
{
@@ -237,19 +246,19 @@ abstract class AbstractQuery
/**
* Sets the life-time for this query into second level cache.
*
* @param integer $lifetime
* @param int $lifetime
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setLifetime($lifetime)
{
$this->lifetime = (integer) $lifetime;
$this->lifetime = (int) $lifetime;
return $this;
}
/**
* @return integer
* @return int
*/
public function getCacheMode()
{
@@ -257,13 +266,13 @@ abstract class AbstractQuery
}
/**
* @param integer $cacheMode
* @param int $cacheMode
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setCacheMode($cacheMode)
{
$this->cacheMode = (integer) $cacheMode;
$this->cacheMode = (int) $cacheMode;
return $this;
}
@@ -280,7 +289,7 @@ abstract class AbstractQuery
/**
* Retrieves the associated EntityManager of this Query instance.
*
* @return \Doctrine\ORM\EntityManager
* @return EntityManager
*/
public function getEntityManager()
{
@@ -304,7 +313,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()
{
@@ -320,11 +329,13 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
$key = Query\Parameter::normalizeName($key);
$filteredParameters = $this->parameters->filter(
function (Query\Parameter $parameter) use ($key) : bool {
static function (Query\Parameter $parameter) use ($key): bool {
$parameterName = $parameter->getName();
return $key === $parameterName || (string) $key === (string) $parameterName;
return $key === $parameterName;
}
);
@@ -334,14 +345,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) {
@@ -387,9 +401,11 @@ abstract class AbstractQuery
*
* @param mixed $value
*
* @return array|string
* @return mixed[]|string|int|float|bool
*
* @throws \Doctrine\ORM\ORMInvalidArgumentException
* @throws ORMInvalidArgumentException
*
* @psalm-return array|scalar
*/
public function processParameterValue($value)
{
@@ -398,28 +414,71 @@ abstract class AbstractQuery
}
if ($value instanceof Collection) {
$value = $value->toArray();
$value = iterator_to_array($value);
}
if (is_array($value)) {
foreach ($value as $key => $paramValue) {
$paramValue = $this->processParameterValue($paramValue);
$value[$key] = is_array($paramValue) ? reset($paramValue) : $paramValue;
}
$value = $this->processArrayParameterValue($value);
return $value;
}
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
if ($value instanceof Mapping\ClassMetadata) {
return $value->name;
}
if (! is_object($value)) {
return $value;
}
try {
$value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);
if ($value === null) {
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
}
} catch (MappingException | ORMMappingException $e) {
/* Silence any mapping exceptions. These can occur if the object in
question is not a mapped entity, in which case we just don't do
any preparation on the value.
Depending on MappingDriver, either MappingException or
ORMMappingException is thrown. */
$value = $this->potentiallyProcessIterable($value);
}
if ($value instanceof Mapping\ClassMetadata) {
return $value->name;
return $value;
}
/**
* If no mapping is detected, trying to resolve the value as a Traversable
*
* @param mixed $value
*
* @return mixed
*/
private function potentiallyProcessIterable($value)
{
if ($value instanceof Traversable) {
$value = iterator_to_array($value);
$value = $this->processArrayParameterValue($value);
}
return $value;
}
/**
* Process a parameter value which was previously identified as an array
*
* @param mixed[] $value
*
* @return mixed[]
*/
private function processArrayParameterValue(array $value): array
{
foreach ($value as $key => $paramValue) {
$paramValue = $this->processParameterValue($paramValue);
$value[$key] = is_array($paramValue) ? reset($paramValue) : $paramValue;
}
return $value;
@@ -428,8 +487,6 @@ abstract class AbstractQuery
/**
* Sets the ResultSetMapping that should be used for hydration.
*
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
*
* @return static This query instance.
*/
public function setResultSetMapping(Query\ResultSetMapping $rsm)
@@ -443,7 +500,7 @@ abstract class AbstractQuery
/**
* Gets the ResultSetMapping used for hydration.
*
* @return \Doctrine\ORM\Query\ResultSetMapping
* @return ResultSetMapping
*/
protected function getResultSetMapping()
{
@@ -453,17 +510,15 @@ abstract class AbstractQuery
/**
* Allows to translate entity namespaces to full qualified names.
*
* @param Query\ResultSetMapping $rsm
*
* @return void
*/
private function translateNamespaces(Query\ResultSetMapping $rsm)
{
$translate = function ($alias) {
$translate = function ($alias): string {
return $this->_em->getClassMetadata($alias)->getName();
};
$rsm->aliasMap = array_map($translate, $rsm->aliasMap);
$rsm->aliasMap = array_map($translate, $rsm->aliasMap);
$rsm->declaringClasses = array_map($translate, $rsm->declaringClasses);
}
@@ -479,21 +534,19 @@ abstract class AbstractQuery
* some form of caching with UnitOfWork registration you should use
* {@see AbstractQuery::setResultCacheProfile()}.
*
* @return static This query instance.
*
* @example
* $lifetime = 100;
* $resultKey = "abc";
* $query->setHydrationCacheProfile(new QueryCacheProfile());
* $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey));
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
*
* @return static This query instance.
*/
public function setHydrationCacheProfile(QueryCacheProfile $profile = null)
public function setHydrationCacheProfile(?QueryCacheProfile $profile = null)
{
if ($profile !== null && ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_hydrationCacheProfile = $profile;
@@ -502,7 +555,7 @@ abstract class AbstractQuery
}
/**
* @return \Doctrine\DBAL\Cache\QueryCacheProfile
* @return QueryCacheProfile
*/
public function getHydrationCacheProfile()
{
@@ -515,15 +568,13 @@ abstract class AbstractQuery
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
*
* @return static This query instance.
*/
public function setResultCacheProfile(QueryCacheProfile $profile = null)
public function setResultCacheProfile(?QueryCacheProfile $profile = null)
{
if ($profile !== null && ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
$profile = $profile->setResultCacheDriver($resultCacheDriver);
}
$this->_queryCacheProfile = $profile;
@@ -573,21 +624,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;
@@ -596,13 +671,13 @@ 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.
*/
public function setResultCacheLifetime($lifetime)
{
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
$lifetime = $lifetime !== null ? (int) $lifetime : 0;
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setLifetime($lifetime)
@@ -616,7 +691,7 @@ abstract class AbstractQuery
*
* @deprecated
*
* @return integer
* @return int
*/
public function getResultCacheLifetime()
{
@@ -626,7 +701,7 @@ abstract class AbstractQuery
/**
* Defines if the result cache is active or not.
*
* @param boolean $expire Whether or not to force resultset cache expiration.
* @param bool $expire Whether or not to force resultset cache expiration.
*
* @return static This query instance.
*/
@@ -640,7 +715,7 @@ abstract class AbstractQuery
/**
* Retrieves if the resultset cache is active or not.
*
* @return boolean
* @return bool
*/
public function getExpireResultCache()
{
@@ -680,8 +755,8 @@ abstract class AbstractQuery
/**
* Defines the processing mode to be used during hydration / result set transformation.
*
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @param string|int $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
*
* @return static This query instance.
*/
@@ -695,7 +770,7 @@ abstract class AbstractQuery
/**
* Gets the hydration mode currently used by the query.
*
* @return integer
* @return string|int
*/
public function getHydrationMode()
{
@@ -707,7 +782,7 @@ abstract class AbstractQuery
*
* Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
*
* @param int $hydrationMode
* @param string|int $hydrationMode
*
* @return mixed
*/
@@ -721,7 +796,7 @@ abstract class AbstractQuery
*
* Alias for execute(null, HYDRATE_ARRAY).
*
* @return array
* @return mixed[]
*/
public function getArrayResult()
{
@@ -733,7 +808,7 @@ abstract class AbstractQuery
*
* Alias for execute(null, HYDRATE_SCALAR).
*
* @return array
* @return mixed[]
*/
public function getScalarResult()
{
@@ -743,7 +818,7 @@ abstract class AbstractQuery
/**
* Get exactly one result or null.
*
* @param int $hydrationMode
* @param string|int $hydrationMode
*
* @return mixed
*
@@ -757,17 +832,16 @@ abstract class AbstractQuery
return null;
}
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
return null;
}
if ( ! is_array($result)) {
if (! is_array($result)) {
return $result;
}
if (count($result) > 1) {
throw new NonUniqueResultException;
throw new NonUniqueResultException();
}
return array_shift($result);
@@ -781,7 +855,7 @@ abstract class AbstractQuery
* If the result is not unique, a NonUniqueResultException is thrown.
* If there is no result, a NoResultException is thrown.
*
* @param integer $hydrationMode
* @param string|int $hydrationMode
*
* @return mixed
*
@@ -793,15 +867,15 @@ abstract class AbstractQuery
$result = $this->execute(null, $hydrationMode);
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
throw new NoResultException;
throw new NoResultException();
}
if ( ! is_array($result)) {
if (! is_array($result)) {
return $result;
}
if (count($result) > 1) {
throw new NonUniqueResultException;
throw new NonUniqueResultException();
}
return array_shift($result);
@@ -812,8 +886,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()
@@ -845,7 +920,7 @@ abstract class AbstractQuery
*/
public function getHint($name)
{
return isset($this->_hints[$name]) ? $this->_hints[$name] : false;
return $this->_hints[$name] ?? false;
}
/**
@@ -863,7 +938,7 @@ abstract class AbstractQuery
/**
* Return the key value map of query hints that are currently set.
*
* @return array
* @return array<string,mixed>
*/
public function getHints()
{
@@ -874,18 +949,25 @@ abstract class AbstractQuery
* Executes the query and returns an IterableResult that can be used to incrementally
* iterate over the result.
*
* @param ArrayCollection|array|null $parameters The query parameters.
* @param integer|null $hydrationMode The hydration mode to use.
* @deprecated
*
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
* @param ArrayCollection|mixed[]|null $parameters The query parameters.
* @param string|int|null $hydrationMode The hydration mode to use.
*
* @return IterableResult
*/
public function iterate($parameters = null, $hydrationMode = null)
{
@trigger_error(
'Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0. Use toIterable() instead.',
E_USER_DEPRECATED
);
if ($hydrationMode !== null) {
$this->setHydrationMode($hydrationMode);
}
if ( ! empty($parameters)) {
if (! empty($parameters)) {
$this->setParameters($parameters);
}
@@ -895,11 +977,44 @@ abstract class AbstractQuery
return $this->_em->newHydrator($this->_hydrationMode)->iterate($stmt, $rsm, $this->_hints);
}
/**
* Executes the query and returns an iterable that can be used to incrementally
* iterate over the result.
*
* @param ArrayCollection|mixed[] $parameters The query parameters.
* @param string|int|null $hydrationMode The hydration mode to use.
*
* @return iterable<mixed>
*/
public function toIterable(iterable $parameters = [], $hydrationMode = null): iterable
{
if ($hydrationMode !== null) {
$this->setHydrationMode($hydrationMode);
}
if (
($this->isCountable($parameters) && count($parameters) !== 0)
|| ($parameters instanceof Traversable && iterator_count($parameters) !== 0)
) {
$this->setParameters($parameters);
}
$rsm = $this->getResultSetMapping();
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
throw QueryException::iterateWithMixedResultNotAllowed();
}
$stmt = $this->_doExecute();
return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints);
}
/**
* Executes the query.
*
* @param ArrayCollection|array|null $parameters Query parameters.
* @param integer|null $hydrationMode Processing mode to be used during the hydration process.
* @param ArrayCollection|mixed[]|null $parameters Query parameters.
* @param string|int|null $hydrationMode Processing mode to be used during the hydration process.
*
* @return mixed
*/
@@ -915,8 +1030,8 @@ abstract class AbstractQuery
/**
* Execute query ignoring second level cache.
*
* @param ArrayCollection|array|null $parameters
* @param integer|null $hydrationMode
* @param ArrayCollection|mixed[]|null $parameters
* @param string|int|null $hydrationMode
*
* @return mixed
*/
@@ -926,14 +1041,15 @@ abstract class AbstractQuery
$this->setHydrationMode($hydrationMode);
}
if ( ! empty($parameters)) {
if (! empty($parameters)) {
$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();
@@ -943,11 +1059,11 @@ abstract class AbstractQuery
return $result[$realCacheKey];
}
if ( ! $result) {
if (! $result) {
$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());
@@ -973,8 +1089,8 @@ abstract class AbstractQuery
/**
* Load from second level cache or executes the query and put into cache.
*
* @param ArrayCollection|array|null $parameters
* @param integer|null $hydrationMode
* @param ArrayCollection|mixed[]|null $parameters
* @param string|int|null $hydrationMode
*
* @return mixed
*/
@@ -989,7 +1105,7 @@ abstract class AbstractQuery
$this->getTimestampKey()
);
$result = $queryCache->get($queryKey, $rsm, $this->_hints);
$result = $queryCache->get($queryKey, $rsm, $this->_hints);
if ($result !== null) {
if ($this->cacheLogger) {
@@ -1014,7 +1130,7 @@ abstract class AbstractQuery
}
/**
* @return \Doctrine\ORM\Cache\TimestampCacheKey|null
* @return TimestampCacheKey|null
*/
private function getTimestampKey()
{
@@ -1034,7 +1150,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()
{
@@ -1087,7 +1203,7 @@ abstract class AbstractQuery
/**
* Executes the query and returns a the resulting Statement object.
*
* @return \Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
* @return Statement The executed database statement that holds the results.
*/
abstract protected function _doExecute();
@@ -1113,10 +1229,12 @@ abstract class AbstractQuery
{
$query = $this->getSQL();
$hints = $this->getHints();
$params = array_map(function(Parameter $parameter) {
$params = array_map(function (Parameter $parameter) {
$value = $parameter->getValue();
// Small optimization
// Does not invoke processParameterValue for scalar values
if (is_scalar($value = $parameter->getValue())) {
// Does not invoke processParameterValue for scalar value
if (is_scalar($value)) {
return $value;
}
@@ -1127,4 +1245,10 @@ abstract class AbstractQuery
return sha1($query . '-' . serialize($params) . '-' . serialize($hints));
}
/** @param iterable<mixed> $subject */
private function isCountable(iterable $subject): bool
{
return $subject instanceof Countable || is_array($subject);
}
}

View File

@@ -20,44 +20,44 @@
namespace Doctrine\ORM;
use Doctrine\ORM\Cache\QueryCache;
use Doctrine\ORM\Cache\Region;
/**
* Provides an API for querying/managing the second level cache regions.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface Cache
{
const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
public const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
public const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
/**
* May read items from the cache, but will not add items.
*/
const MODE_GET = 1;
public const MODE_GET = 1;
/**
* Will never read items from the cache,
* but will add items to the cache as it reads them from the database.
*/
const MODE_PUT = 2;
public const MODE_PUT = 2;
/**
* May read items from the cache, and add items to the cache.
*/
const MODE_NORMAL = 3;
public const MODE_NORMAL = 3;
/**
* The query will never read items from the cache,
* but will refresh items to the cache as it reads them from the database.
*/
const MODE_REFRESH = 4;
public const MODE_REFRESH = 4;
/**
* @param string $className The entity class.
*
* @return \Doctrine\ORM\Cache\Region|null
* @return Region|null
*/
public function getEntityCacheRegion($className);
@@ -65,7 +65,7 @@ interface Cache
* @param string $className The entity class.
* @param string $association The field name that represents the association.
*
* @return \Doctrine\ORM\Cache\Region|null
* @return Region|null
*/
public function getCollectionCacheRegion($className, $association);
@@ -75,7 +75,7 @@ interface Cache
* @param string $className The entity class.
* @param mixed $identifier The entity identifier
*
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
* @return bool true if the underlying cache contains corresponding data; false otherwise.
*/
public function containsEntity($className, $identifier);
@@ -112,7 +112,7 @@ interface Cache
* @param string $association The field name that represents the association.
* @param mixed $ownerIdentifier The identifier of the owning entity.
*
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
* @return bool true if the underlying cache contains corresponding data; false otherwise.
*/
public function containsCollection($className, $association, $ownerIdentifier);
@@ -149,7 +149,7 @@ interface Cache
*
* @param string $regionName The cache name given to the query.
*
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
* @return bool true if the underlying cache contains corresponding data; false otherwise.
*/
public function containsQuery($regionName);
@@ -172,7 +172,7 @@ interface Cache
*
* @param string|null $regionName Query cache region name, or default query cache if the region name is NULL.
*
* @return \Doctrine\ORM\Cache\QueryCache The Query Cache associated with the region name.
* @return QueryCache The Query Cache associated with the region name.
*/
public function getQueryCache($regionName = null);
}

View File

@@ -22,16 +22,13 @@ namespace Doctrine\ORM\Cache;
/**
* Association cache entry
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class AssociationCacheEntry implements CacheEntry
{
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
*
* @var array The entity identifier
* @var array<string, mixed> The entity identifier
*/
public $identifier;
@@ -43,13 +40,13 @@ class AssociationCacheEntry implements CacheEntry
public $class;
/**
* @param string $class The entity class.
* @param array $identifier The entity identifier.
* @param string $class The entity class.
* @param array<string, mixed> $identifier The entity identifier.
*/
public function __construct($class, array $identifier)
{
$this->class = $class;
$this->identifier = $identifier;
$this->class = $class;
$this->identifier = $identifier;
}
/**
@@ -57,7 +54,7 @@ class AssociationCacheEntry implements CacheEntry
*
* This method allow Doctrine\Common\Cache\PhpFileCache compatibility
*
* @param array $values array containing property values
* @param array<string, mixed> $values array containing property values
*
* @return AssociationCacheEntry
*/

View File

@@ -24,34 +24,23 @@ use Doctrine\ORM\Cache\Logging\CacheLogger;
/**
* Configuration container for second-level cache.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class CacheConfiguration
{
/**
* @var \Doctrine\ORM\Cache\CacheFactory|null
*/
/** @var CacheFactory|null */
private $cacheFactory;
/**
* @var \Doctrine\ORM\Cache\RegionsConfiguration|null
*/
/** @var RegionsConfiguration|null */
private $regionsConfig;
/**
* @var \Doctrine\ORM\Cache\Logging\CacheLogger|null
*/
/** @var CacheLogger|null */
private $cacheLogger;
/**
* @var \Doctrine\ORM\Cache\QueryCacheValidator|null
*/
/** @var QueryCacheValidator|null */
private $queryValidator;
/**
* @return \Doctrine\ORM\Cache\CacheFactory|null
* @return CacheFactory|null
*/
public function getCacheFactory()
{
@@ -59,8 +48,6 @@ class CacheConfiguration
}
/**
* @param \Doctrine\ORM\Cache\CacheFactory $factory
*
* @return void
*/
public function setCacheFactory(CacheFactory $factory)
@@ -69,23 +56,20 @@ class CacheConfiguration
}
/**
* @return \Doctrine\ORM\Cache\Logging\CacheLogger|null
* @return CacheLogger|null
*/
public function getCacheLogger()
{
return $this->cacheLogger;
}
/**
* @param \Doctrine\ORM\Cache\Logging\CacheLogger $logger
*/
public function setCacheLogger(CacheLogger $logger)
{
$this->cacheLogger = $logger;
}
/**
* @return \Doctrine\ORM\Cache\RegionsConfiguration
* @return RegionsConfiguration
*/
public function getRegionsConfiguration()
{
@@ -96,16 +80,13 @@ class CacheConfiguration
return $this->regionsConfig;
}
/**
* @param \Doctrine\ORM\Cache\RegionsConfiguration $regionsConfig
*/
public function setRegionsConfiguration(RegionsConfiguration $regionsConfig)
{
$this->regionsConfig = $regionsConfig;
}
/**
* @return \Doctrine\ORM\Cache\QueryCacheValidator
* @return QueryCacheValidator
*/
public function getQueryValidator()
{
@@ -118,9 +99,6 @@ class CacheConfiguration
return $this->queryValidator;
}
/**
* @param \Doctrine\ORM\Cache\QueryCacheValidator $validator
*/
public function setQueryValidator(QueryCacheValidator $validator)
{
$this->queryValidator = $validator;

View File

@@ -26,11 +26,7 @@ namespace Doctrine\ORM\Cache;
* <b>IMPORTANT NOTE:</b>
*
* Fields of classes that implement CacheEntry are public for performance reason.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface CacheEntry
{
}

View File

@@ -1,4 +1,5 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -21,11 +22,10 @@ namespace Doctrine\ORM\Cache;
use Doctrine\ORM\ORMException;
use function sprintf;
/**
* Exception for cache.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class CacheException extends ORMException
{
@@ -33,7 +33,7 @@ class CacheException extends ORMException
* @param string $sourceEntity
* @param string $fieldName
*
* @return \Doctrine\ORM\Cache\CacheException
* @return CacheException
*/
public static function updateReadOnlyCollection($sourceEntity, $fieldName)
{
@@ -43,7 +43,7 @@ class CacheException extends ORMException
/**
* @param string $entityName
*
* @return \Doctrine\ORM\Cache\CacheException
* @return CacheException
*/
public static function updateReadOnlyEntity($entityName)
{
@@ -53,7 +53,7 @@ class CacheException extends ORMException
/**
* @param string $entityName
*
* @return \Doctrine\ORM\Cache\CacheException
* @return CacheException
*/
public static function nonCacheableEntity($entityName)
{

View File

@@ -20,93 +20,91 @@
namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
/**
* Contract for building second level cache regions components.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface CacheFactory
{
/**
* Build an entity persister for the given entity metadata.
*
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister The entity persister that will be cached.
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param EntityManagerInterface $em The entity manager.
* @param EntityPersister $persister The entity persister that will be cached.
* @param ClassMetadata $metadata The entity metadata.
*
* @return \Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister
* @return CachedEntityPersister
*/
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata);
/**
* Build a collection persister for the given relation mapping.
*
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
* @param \Doctrine\ORM\Persisters\Collection\CollectionPersister $persister The collection persister that will be cached.
* @param array $mapping The association mapping.
* @param EntityManagerInterface $em The entity manager.
* @param CollectionPersister $persister The collection persister that will be cached.
* @param mixed[] $mapping The association mapping.
*
* @return \Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister
* @return CachedCollectionPersister
*/
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping);
/**
* Build a query cache based on the given region name
*
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
* @param string $regionName The region name.
* @param EntityManagerInterface $em The Entity manager.
* @param string $regionName The region name.
*
* @return \Doctrine\ORM\Cache\QueryCache The built query cache.
* @return QueryCache The built query cache.
*/
public function buildQueryCache(EntityManagerInterface $em, $regionName = null);
/**
* Build an entity hydrator
*
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param EntityManagerInterface $em The Entity manager.
* @param ClassMetadata $metadata The entity metadata.
*
* @return \Doctrine\ORM\Cache\EntityHydrator The built entity hydrator.
* @return EntityHydrator The built entity hydrator.
*/
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata);
/**
* Build a collection hydrator
*
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
* @param array $mapping The association mapping.
* @param EntityManagerInterface $em The Entity manager.
* @param mixed[] $mapping The association mapping.
*
* @return \Doctrine\ORM\Cache\CollectionHydrator The built collection hydrator.
* @return CollectionHydrator The built collection hydrator.
*/
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping);
/**
* Build a cache region
*
* @param array $cache The cache configuration.
* @param array<string,mixed> $cache The cache configuration.
*
* @return \Doctrine\ORM\Cache\Region The cache region.
* @return Region The cache region.
*/
public function getRegion(array $cache);
/**
* Build timestamp cache region
*
* @return \Doctrine\ORM\Cache\TimestampRegion The timestamp region.
* @return TimestampRegion The timestamp region.
*/
public function getTimestampRegion();
/**
* Build \Doctrine\ORM\Cache
*
* @param EntityManagerInterface $entityManager
*
* @return \Doctrine\ORM\Cache
* @return Cache
*/
public function createCache(EntityManagerInterface $entityManager);
}

View File

@@ -23,9 +23,6 @@ namespace Doctrine\ORM\Cache;
/**
* Defines entity / collection / query key to be stored in the cache region.
* Allows multiple roles to be stored in the same cache region.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
abstract class CacheKey
{

View File

@@ -22,9 +22,6 @@ namespace Doctrine\ORM\Cache;
/**
* Collection cache entry
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class CollectionCacheEntry implements CacheEntry
{
@@ -48,7 +45,7 @@ class CollectionCacheEntry implements CacheEntry
*
* This method allows for Doctrine\Common\Cache\PhpFileCache compatibility
*
* @param array $values array containing property values
* @param array<string, mixed> $values array containing property values
*
* @return CollectionCacheEntry
*/

View File

@@ -20,18 +20,20 @@
namespace Doctrine\ORM\Cache;
use function implode;
use function ksort;
use function str_replace;
use function strtolower;
/**
* Defines entity collection roles to be stored in the cache region.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class CollectionCacheKey extends CacheKey
{
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
*
* @var array The owner entity identifier
* @var array<string, mixed> The owner entity identifier
*/
public $ownerIdentifier;
@@ -50,17 +52,17 @@ class CollectionCacheKey extends CacheKey
public $association;
/**
* @param string $entityClass The entity class.
* @param string $association The field name that represents the association.
* @param array $ownerIdentifier The identifier of the owning entity.
* @param string $entityClass The entity class.
* @param string $association The field name that represents the association.
* @param array<string, mixed> $ownerIdentifier The identifier of the owning entity.
*/
public function __construct($entityClass, $association, array $ownerIdentifier)
{
ksort($ownerIdentifier);
$this->ownerIdentifier = $ownerIdentifier;
$this->entityClass = (string) $entityClass;
$this->association = (string) $association;
$this->hash = str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association;
$this->ownerIdentifier = $ownerIdentifier;
$this->entityClass = (string) $entityClass;
$this->association = (string) $association;
$this->hash = str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association;
}
}

View File

@@ -20,33 +20,31 @@
namespace Doctrine\ORM\Cache;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
/**
* Hydrator cache entry for collections
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface CollectionHydrator
{
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cached collection key.
* @param array|\Doctrine\Common\Collections\Collection $collection The collection.
* @param ClassMetadata $metadata The entity metadata.
* @param CollectionCacheKey $key The cached collection key.
* @param mixed[]|Collection $collection The collection.
*
* @return \Doctrine\ORM\Cache\CollectionCacheEntry
* @return CollectionCacheEntry
*/
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection);
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The owning entity metadata.
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cached collection key.
* @param \Doctrine\ORM\Cache\CollectionCacheEntry $entry The cached collection entry.
* @param \Doctrine\ORM\PersistentCollection $collection The collection to load the cache into.
* @param ClassMetadata $metadata The owning entity metadata.
* @param CollectionCacheKey $key The cached collection key.
* @param CollectionCacheEntry $entry The cached collection entry.
* @param PersistentCollection $collection The collection to load the cache into.
*
* @return array
* @return mixed[]
*/
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection);
}

View File

@@ -26,32 +26,29 @@ namespace Doctrine\ORM\Cache;
*
* When a entry is locked another process should not be able to read or write the entry.
* All evict operation should not consider locks, even though an entry is locked evict should be able to delete the entry and its lock.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface ConcurrentRegion extends Region
{
/**
* Attempts to read lock the mapping for the given key.
*
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to lock.
* @param CacheKey $key The key of the item to lock.
*
* @return \Doctrine\ORM\Cache\Lock A lock instance or NULL if the lock already exists.
* @return Lock A lock instance or NULL if the lock already exists.
*
* @throws \Doctrine\ORM\Cache\LockException Indicates a problem accessing the region.
* @throws LockException Indicates a problem accessing the region.
*/
public function lock(CacheKey $key);
/**
* Attempts to read unlock the mapping for the given key.
*
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to unlock.
* @param \Doctrine\ORM\Cache\Lock $lock The lock previously obtained from {@link readLock}
* @param CacheKey $key The key of the item to unlock.
* @param Lock $lock The lock previously obtained from {@link readLock}
*
* @return void
*
* @throws \Doctrine\ORM\Cache\LockException Indicates a problem accessing the region.
* @throws LockException Indicates a problem accessing the region.
*/
public function unlock(CacheKey $key, Lock $lock);
}

View File

@@ -20,49 +20,37 @@
namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMInvalidArgumentException;
use Doctrine\ORM\UnitOfWork;
use function is_array;
use function is_object;
/**
* Provides an API for querying/managing the second level cache regions.
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultCache implements Cache
{
/**
* @var \Doctrine\ORM\EntityManagerInterface
*/
/** @var EntityManagerInterface */
private $em;
/**
* @var \Doctrine\ORM\UnitOfWork
*/
/** @var UnitOfWork */
private $uow;
/**
* @var \Doctrine\ORM\Cache\CacheFactory
*/
/** @var CacheFactory */
private $cacheFactory;
/**
* @var \Doctrine\ORM\Cache\QueryCache[]
*/
/** @var QueryCache[] */
private $queryCaches = [];
/**
* @var \Doctrine\ORM\Cache\QueryCache
*/
/** @var QueryCache */
private $defaultQueryCache;
/**
* {@inheritdoc}
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
@@ -80,7 +68,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return null;
}
@@ -95,7 +83,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return null;
}
@@ -107,10 +95,10 @@ class DefaultCache implements Cache
*/
public function containsEntity($className, $identifier)
{
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return false;
}
@@ -125,7 +113,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return;
}
@@ -140,7 +128,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return;
}
@@ -157,7 +145,7 @@ class DefaultCache implements Cache
foreach ($metadatas as $metadata) {
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
continue;
}
@@ -173,7 +161,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return false;
}
@@ -188,7 +176,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return;
}
@@ -203,7 +191,7 @@ class DefaultCache implements Cache
$metadata = $this->em->getClassMetadata($className);
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
return;
}
@@ -218,16 +206,14 @@ class DefaultCache implements Cache
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
foreach ($metadatas as $metadata) {
foreach ($metadata->associationMappings as $association) {
if ( ! $association['type'] & ClassMetadata::TO_MANY) {
if (! $association['type'] & ClassMetadata::TO_MANY) {
continue;
}
$persister = $this->uow->getCollectionPersister($association);
if ( ! ($persister instanceof CachedPersister)) {
if (! ($persister instanceof CachedPersister)) {
continue;
}
@@ -282,7 +268,7 @@ class DefaultCache implements Cache
$this->defaultQueryCache = $this->cacheFactory->buildQueryCache($this->em);
}
if ( ! isset($this->queryCaches[$regionName])) {
if (! isset($this->queryCaches[$regionName])) {
$this->queryCaches[$regionName] = $this->cacheFactory->buildQueryCache($this->em, $regionName);
}
@@ -290,14 +276,14 @@ class DefaultCache implements Cache
}
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param mixed $identifier The entity identifier.
*
* @return \Doctrine\ORM\Cache\EntityCacheKey
*/
* @param ClassMetadata $metadata The entity metadata.
* @param mixed $identifier The entity identifier.
*
* @return EntityCacheKey
*/
private function buildEntityCacheKey(ClassMetadata $metadata, $identifier)
{
if ( ! is_array($identifier)) {
if (! is_array($identifier)) {
$identifier = $this->toIdentifierArray($metadata, $identifier);
}
@@ -305,15 +291,15 @@ class DefaultCache implements Cache
}
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param string $association The field name that represents the association.
* @param mixed $ownerIdentifier The identifier of the owning entity.
* @param ClassMetadata $metadata The entity metadata.
* @param string $association The field name that represents the association.
* @param mixed $ownerIdentifier The identifier of the owning entity.
*
* @return \Doctrine\ORM\Cache\CollectionCacheKey
* @return CollectionCacheKey
*/
private function buildCollectionCacheKey(ClassMetadata $metadata, $association, $ownerIdentifier)
{
if ( ! is_array($ownerIdentifier)) {
if (! is_array($ownerIdentifier)) {
$ownerIdentifier = $this->toIdentifierArray($metadata, $ownerIdentifier);
}
@@ -321,10 +307,10 @@ class DefaultCache implements Cache
}
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
* @param mixed $identifier The entity identifier.
* @param ClassMetadata $metadata The entity metadata.
* @param mixed $identifier The entity identifier.
*
* @return array
* @return array<string, mixed>
*/
private function toIdentifierArray(ClassMetadata $metadata, $identifier)
{
@@ -338,5 +324,4 @@ class DefaultCache implements Cache
return [$metadata->identifier[0] => $identifier];
}
}

View File

@@ -38,42 +38,30 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use InvalidArgumentException;
use LogicException;
use function sprintf;
use const DIRECTORY_SEPARATOR;
/**
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultCacheFactory implements CacheFactory
{
/**
* @var CacheAdapter
*/
/** @var CacheAdapter */
private $cache;
/**
* @var \Doctrine\ORM\Cache\RegionsConfiguration
*/
/** @var RegionsConfiguration */
private $regionsConfig;
/**
* @var \Doctrine\ORM\Cache\TimestampRegion|null
*/
/** @var TimestampRegion|null */
private $timestampRegion;
/**
* @var \Doctrine\ORM\Cache\Region[]
*/
/** @var Region[] */
private $regions = [];
/**
* @var string|null
*/
/** @var string|null */
private $fileLockRegionDirectory;
/**
* @param RegionsConfiguration $cacheConfig
* @param CacheAdapter $cache
*/
public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
{
$this->cache = $cache;
@@ -96,17 +84,11 @@ class DefaultCacheFactory implements CacheFactory
return $this->fileLockRegionDirectory;
}
/**
* @param \Doctrine\ORM\Cache\Region $region
*/
public function setRegion(Region $region)
{
$this->regions[$region->getName()] = $region;
}
/**
* @param \Doctrine\ORM\Cache\TimestampRegion $region
*/
public function setTimestampRegion(TimestampRegion $region)
{
$this->timestampRegion = $region;
@@ -117,8 +99,8 @@ class DefaultCacheFactory implements CacheFactory
*/
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
{
$region = $this->getRegion($metadata->cache);
$usage = $metadata->cache['usage'];
$region = $this->getRegion($metadata->cache);
$usage = $metadata->cache['usage'];
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);
@@ -132,7 +114,7 @@ class DefaultCacheFactory implements CacheFactory
return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
}
throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
}
/**
@@ -140,8 +122,8 @@ class DefaultCacheFactory implements CacheFactory
*/
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
{
$usage = $mapping['cache']['usage'];
$region = $this->getRegion($mapping['cache']);
$usage = $mapping['cache']['usage'];
$region = $this->getRegion($mapping['cache']);
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping);
@@ -155,7 +137,7 @@ class DefaultCacheFactory implements CacheFactory
return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
}
throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
}
/**
@@ -168,7 +150,7 @@ class DefaultCacheFactory implements CacheFactory
$this->getRegion(
[
'region' => $regionName ?: Cache::DEFAULT_QUERY_REGION_NAME,
'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE
'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE,
]
)
);
@@ -203,17 +185,16 @@ class DefaultCacheFactory implements CacheFactory
$cacheAdapter = $this->createRegionCache($name);
$lifetime = $this->regionsConfig->getLifetime($cache['region']);
$region = ($cacheAdapter instanceof MultiGetCache)
$region = $cacheAdapter instanceof MultiGetCache
? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
: new DefaultRegion($name, $cacheAdapter, $lifetime);
if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
if (
'' === $this->fileLockRegionDirectory ||
null === $this->fileLockRegionDirectory
$this->fileLockRegionDirectory === '' ||
$this->fileLockRegionDirectory === null
) {
throw new \LogicException(
throw new LogicException(
'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' .
'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). '
);
@@ -235,13 +216,13 @@ class DefaultCacheFactory implements CacheFactory
{
$cacheAdapter = clone $this->cache;
if (!$cacheAdapter instanceof CacheProvider) {
if (! $cacheAdapter instanceof CacheProvider) {
return $cacheAdapter;
}
$namespace = $cacheAdapter->getNamespace();
if ('' !== $namespace) {
if ($namespace !== '') {
$namespace .= ':';
}

View File

@@ -20,36 +20,32 @@
namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Query;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use function array_walk;
use function assert;
/**
* Default hydrator cache for collections
*
* @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultCollectionHydrator implements CollectionHydrator
{
/**
* @var \Doctrine\ORM\EntityManagerInterface
*/
/** @var EntityManagerInterface */
private $em;
/**
* @var \Doctrine\ORM\UnitOfWork
*/
/** @var UnitOfWork */
private $uow;
/**
* @var array
*/
/** @var array<string,mixed> */
private static $hints = [Query::HINT_CACHE_ENABLED => true];
/**
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
* @param EntityManagerInterface $em The entity manager.
*/
public function __construct(EntityManagerInterface $em)
{
@@ -77,23 +73,23 @@ class DefaultCollectionHydrator implements CollectionHydrator
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
{
$assoc = $metadata->associationMappings[$key->association];
/* @var $targetPersister \Doctrine\ORM\Cache\Persister\CachedPersister */
$targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
$targetRegion = $targetPersister->getCacheRegion();
$list = [];
assert($targetPersister instanceof CachedPersister);
$targetRegion = $targetPersister->getCacheRegion();
$list = [];
/** @var EntityCacheEntry[]|null $entityEntries */
$entityEntries = $targetRegion->getMultiple($entry);
if ($entityEntries === null) {
return null;
}
/* @var $entityEntries \Doctrine\ORM\Cache\EntityCacheEntry[] */
foreach ($entityEntries as $index => $entityEntry) {
$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
}
array_walk($list, function($entity, $index) use ($collection) {
array_walk($list, static function ($entity, $index) use ($collection) {
$collection->hydrateSet($index, $entity);
});

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