-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix parameter value processing for objects with unloaded metadata #7471
Fix parameter value processing for objects with unloaded metadata #7471
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some tiny things 👍
This was the PHPBench report but it's not much relevant since that bit is not covered: 24 subjects, 240 iterations, 24 revs, 0 rejects, 0 failures, 0 warnings
- (best [mean mode] worst) = 370.000 [39,908.388 39,463.004] 450.000 (μs)
+ (best [mean mode] worst) = 361.000 [39,836.125 39,382.889] 563.000 (μs)
- ⅀T: 9,578,013.000μs μSD/r 1,161.745μs μRSD/r: 5.875%
+ ⅀T: 9,560,670.000μs μSD/r 1,335.070μs μRSD/r: 5.475%
- suite: 133f079af8e76a725b3ce35962ff28c7851c24f3, date: 2018-11-13, stime: 10:34:20
+ suite: 133f079e185b4011810cb48680765ebf38c321c3, date: 2018-11-13, stime: 10:36:57
+-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+
| benchmark | subject | mem_peak | best | mean | mode | worst | stdev | rstdev | diff |
+-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+
- | SimpleInsertPerformanceBench | benchHydration | 20,343,704b | 262,975.000μs | 271,148.300μs | 270,203.227μs | 276,966.000μs | 4,075.729μs | 1.50% | 667.85x |
+ | SimpleInsertPerformanceBench | benchHydration | 20,343,704b | 269,992.000μs | 278,530.300μs | 275,499.687μs | 292,689.000μs | 7,040.146μs | 2.53% | 677.19x |
- | SimpleHydrationBench | benchHydration | 67,667,720b | 132,631.000μs | 136,102.900μs | 134,341.123μs | 141,458.000μs | 2,834.684μs | 2.08% | 335.23x |
+ | SimpleHydrationBench | benchHydration | 67,667,720b | 133,249.000μs | 142,360.300μs | 141,051.824μs | 158,326.000μs | 6,311.889μs | 4.43% | 346.12x |
- | MixedQueryFetchJoinFullObjectHydrationPerformanceBench | benchHydration | 17,732,512b | 43,909.000μs | 45,938.900μs | 44,994.566μs | 48,775.000μs | 1,657.508μs | 3.61% | 113.15x |
+ | MixedQueryFetchJoinFullObjectHydrationPerformanceBench | benchHydration | 17,732,408b | 43,624.000μs | 46,903.700μs | 45,546.769μs | 52,319.000μs | 2,578.879μs | 5.50% | 114.04x |
- | SimpleQueryPartialObjectHydrationPerformanceBench | benchHydration | 25,305,536b | 45,104.000μs | 47,931.300μs | 46,234.548μs | 56,894.000μs | 3,508.759μs | 7.32% | 118.06x |
+ | SimpleQueryPartialObjectHydrationPerformanceBench | benchHydration | 25,305,432b | 46,920.000μs | 49,631.300μs | 49,180.235μs | 53,714.000μs | 1,779.756μs | 3.59% | 120.67x |
- | SimpleQueryScalarHydrationPerformanceBench | benchHydration | 14,337,104b | 15,268.000μs | 16,512.400μs | 16,114.051μs | 18,995.000μs | 1,040.037μs | 6.30% | 40.67x |
+ | SimpleQueryScalarHydrationPerformanceBench | benchHydration | 14,337,104b | 14,850.000μs | 16,111.500μs | 15,718.751μs | 20,012.000μs | 1,390.834μs | 8.63% | 39.17x |
- | SingleTableInheritanceHydrationPerformanceBench | benchHydrateFixContracts | 6,363,736b | 1,718.000μs | 1,784.700μs | 1,754.564μs | 1,891.000μs | 51.852μs | 2.91% | 4.40x |
+ | SingleTableInheritanceHydrationPerformanceBench | benchHydrateFixContracts | 6,363,736b | 1,724.000μs | 1,869.800μs | 1,851.573μs | 2,134.000μs | 109.495μs | 5.86% | 4.55x |
- | SingleTableInheritanceHydrationPerformanceBench | benchHydrateFlexContracts | 6,501,880b | 2,107.000μs | 2,282.500μs | 2,161.462μs | 3,372.000μs | 364.587μs | 15.97% | 5.62x |
+ | SingleTableInheritanceHydrationPerformanceBench | benchHydrateFlexContracts | 6,501,776b | 2,110.000μs | 2,326.600μs | 2,176.536μs | 2,960.000μs | 270.234μs | 11.61% | 5.66x |
- | SingleTableInheritanceHydrationPerformanceBench | benchHydrateUltraContracts | 6,368,440b | 1,843.000μs | 1,976.300μs | 1,917.980μs | 2,238.000μs | 129.170μs | 6.54% | 4.87x |
+ | SingleTableInheritanceHydrationPerformanceBench | benchHydrateUltraContracts | 6,368,336b | 1,796.000μs | 1,842.900μs | 1,813.178μs | 1,929.000μs | 43.441μs | 2.36% | 4.48x |
- | SingleTableInheritanceHydrationPerformanceBench | benchHydrateAllContracts | 6,588,232b | 2,499.000μs | 2,682.500μs | 2,616.534μs | 3,269.000μs | 208.184μs | 7.76% | 6.61x |
+ | SingleTableInheritanceHydrationPerformanceBench | benchHydrateAllContracts | 6,588,128b | 2,532.000μs | 2,769.000μs | 2,621.636μs | 3,226.000μs | 231.238μs | 8.35% | 6.73x |
- | SingleTableInheritanceInsertPerformanceBench | benchInsertFixContracts | 5,937,680b | 3,629.000μs | 3,862.100μs | 3,764.526μs | 4,746.000μs | 312.493μs | 8.09% | 9.51x |
+ | SingleTableInheritanceInsertPerformanceBench | benchInsertFixContracts | 5,937,680b | 3,560.000μs | 3,767.100μs | 3,728.082μs | 3,969.000μs | 118.555μs | 3.15% | 9.16x |
- | SingleTableInheritanceInsertPerformanceBench | benchInsertFlexContracts | 5,950,472b | 3,829.000μs | 4,250.100μs | 3,996.123μs | 5,537.000μs | 531.776μs | 12.51% | 10.47x |
+ | SingleTableInheritanceInsertPerformanceBench | benchInsertFlexContracts | 5,950,472b | 3,644.000μs | 3,787.300μs | 3,743.315μs | 3,934.000μs | 87.044μs | 2.30% | 9.21x |
- | SingleTableInheritanceInsertPerformanceBench | benchInsertUltraContracts | 5,996,000b | 3,885.000μs | 4,271.500μs | 4,079.004μs | 5,434.000μs | 444.057μs | 10.40% | 10.52x |
+ | SingleTableInheritanceInsertPerformanceBench | benchInsertUltraContracts | 5,996,000b | 3,660.000μs | 3,836.700μs | 3,728.689μs | 4,128.000μs | 145.543μs | 3.79% | 9.33x |
- | SingleTableInheritanceInsertPerformanceBench | benchInsertAllContracts | 6,342,696b | 5,409.000μs | 5,712.300μs | 5,597.472μs | 6,192.000μs | 254.228μs | 4.45% | 14.07x |
+ | SingleTableInheritanceInsertPerformanceBench | benchInsertAllContracts | 6,342,696b | 4,952.000μs | 5,249.600μs | 5,084.094μs | 6,202.000μs | 369.274μs | 7.03% | 12.76x |
- | SimpleQueryArrayHydrationPerformanceBench | benchHydration | 14,071,568b | 24,375.000μs | 26,385.600μs | 25,465.411μs | 32,335.000μs | 2,298.519μs | 8.71% | 64.99x |
+ | SimpleQueryArrayHydrationPerformanceBench | benchHydration | 14,071,568b | 23,559.000μs | 24,327.500μs | 23,941.935μs | 26,005.000μs | 749.271μs | 3.08% | 59.15x |
- | MixedQueryFetchJoinPartialObjectHydrationPerformanceBench | benchHydration | 11,838,584b | 25,009.000μs | 26,833.900μs | 26,635.149μs | 28,892.000μs | 1,032.904μs | 3.85% | 66.09x |
+ | MixedQueryFetchJoinPartialObjectHydrationPerformanceBench | benchHydration | 11,838,480b | 25,895.000μs | 26,653.500μs | 26,537.241μs | 28,190.000μs | 574.283μs | 2.15% | 64.80x |
- | SimpleQueryFullObjectHydrationPerformanceBench | benchHydration | 62,116,592b | 145,482.000μs | 149,224.200μs | 148,192.372μs | 152,407.000μs | 2,294.034μs | 1.54% | 367.55x |
+ | SimpleQueryFullObjectHydrationPerformanceBench | benchHydration | 62,116,488b | 138,155.000μs | 143,178.600μs | 142,548.703μs | 148,454.000μs | 3,421.227μs | 2.39% | 348.11x |
- | MixedQueryFetchJoinArrayHydrationPerformanceBench | benchHydration | 31,152,520b | 47,166.000μs | 48,191.100μs | 47,810.384μs | 49,910.000μs | 861.185μs | 1.79% | 118.70x |
+ | MixedQueryFetchJoinArrayHydrationPerformanceBench | benchHydration | 31,152,520b | 42,573.000μs | 44,350.600μs | 43,558.933μs | 50,699.000μs | 2,271.497μs | 5.12% | 107.83x |
- | UnitOfWorkComputeChangesBench | benchChangeSetComputation | 4,891,920b | 793.000μs | 819.800μs | 805.945μs | 856.000μs | 23.151μs | 2.82% | 2.02x |
+ | UnitOfWorkComputeChangesBench | benchChangeSetComputation | 4,891,920b | 721.000μs | 790.400μs | 774.605μs | 977.000μs | 69.230μs | 8.76% | 1.92x |
- | ProxyInitializationTimeBench | benchCmsUserInitialization | 16,826,024b | 35,593.000μs | 36,650.200μs | 36,714.742μs | 37,523.000μs | 484.413μs | 1.32% | 90.27x |
+ | ProxyInitializationTimeBench | benchCmsUserInitialization | 16,826,024b | 31,842.000μs | 33,874.300μs | 33,847.315μs | 36,278.000μs | 1,169.117μs | 3.45% | 82.36x |
- | ProxyInitializationTimeBench | benchCmsEmployeeInitialization | 16,826,024b | 5,880.000μs | 6,717.000μs | 6,852.634μs | 7,296.000μs | 389.934μs | 5.81% | 16.54x |
+ | ProxyInitializationTimeBench | benchCmsEmployeeInitialization | 16,826,024b | 6,034.000μs | 6,536.100μs | 6,271.213μs | 7,928.000μs | 554.531μs | 8.48% | 15.89x |
- | ProxyInitializationTimeBench | benchInitializationOfAlreadyInitializedCmsUsers | 16,826,048b | 441.000μs | 492.800μs | 465.845μs | 625.000μs | 54.834μs | 11.13% | 1.21x |
+ | ProxyInitializationTimeBench | benchInitializationOfAlreadyInitializedCmsUsers | 16,826,048b | 456.000μs | 508.600μs | 506.673μs | 563.000μs | 29.114μs | 5.72% | 1.24x |
- | ProxyInitializationTimeBench | benchInitializationOfAlreadyInitializedCmsEmployees | 16,826,048b | 370.000μs | 406.000μs | 391.292μs | 450.000μs | 26.866μs | 6.62% | 1.00x |
+ | ProxyInitializationTimeBench | benchInitializationOfAlreadyInitializedCmsEmployees | 16,826,048b | 361.000μs | 411.300μs | 386.550μs | 633.000μs | 75.777μs | 18.42% | 1.00x |
- | ProxyInstantiationTimeBench | benchCmsUserInstantiation | 4,828,112b | 65,987.000μs | 68,989.800μs | 67,795.219μs | 79,987.000μs | 3,798.960μs | 5.51% | 169.93x |
+ | ProxyInstantiationTimeBench | benchCmsUserInstantiation | 4,828,112b | 65,510.000μs | 66,710.400μs | 65,979.785μs | 69,511.000μs | 1,285.225μs | 1.93% | 162.19x |
- | ProxyInstantiationTimeBench | benchCmsEmployeeInstantiation | 4,558,264b | 47,301.000μs | 48,635.100μs | 48,207.912μs | 51,673.000μs | 1,204.027μs | 2.48% | 119.79x |
+ | ProxyInstantiationTimeBench | benchCmsEmployeeInstantiation | 4,558,264b | 47,777.000μs | 49,739.600μs | 49,092.022μs | 51,925.000μs | 1,366.084μs | 2.75% | 120.93x |
+-----------------------------------------------------------+-----------------------------------------------------+-------------+---------------+---------------+---------------+---------------+-------------+--------+---------+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides existing feedback, this looks good! 👍
Build failures are due to MySQL not being installed at the moment... |
@alcaeus failing steps re-executed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alcaeus this is perfect now, I've addressed the minor CS things and we're good to go. Thanks for squashing this 🐛
@alcaeus 🚢 |
When no class schema can be found in `loadMetaDataForClass`, a Doctrine `MappingException` is now thrown. This makes our code work nicely with the change in doctrine/orm#7471 that otherwise leads to errors like this as of ORM 2.6.3: ``` FlowAnnotationDriver.php: No class schema found for "some-non-mapped-class". 89 …\FlowAnnotationDriver_Original::getClassSchema("some-non-mapped-class") 88 …\FlowAnnotationDriver_Original::loadMetadataForClass("some-non-mapped-class", Neos\Flow\Persistence\Doctrine\Mapping\ClassMetadata) ``` Fixes neos#1453
When no class schema can be found in `loadMetaDataForClass`, a Doctrine `MappingException` is now thrown. This makes our code work nicely with the change in doctrine/orm#7471 that otherwise leads to errors like this as of ORM 2.6.3: ``` FlowAnnotationDriver.php: No class schema found for "some-non-mapped-class". 89 …\FlowAnnotationDriver_Original::getClassSchema("some-non-mapped-class") 88 …\FlowAnnotationDriver_Original::loadMetadataForClass("some-non-mapped-class", Neos\Flow\Persistence\Doctrine\Mapping\ClassMetadata) ``` Fixes #1453
@@ -410,16 +412,24 @@ public function processParameterValue($value) | |||
return $value; | |||
} | |||
|
|||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) { | |||
if ($value instanceof Mapping\ClassMetadata) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just found out via kcachegrind that this caused massive performance regressions when binding any non-scalar value as parameter.
For example:
$thing = new DateTime();
$query->setParameter('foo', $thing);
$query->getResult();
Regardless of $query
, this will lead to an internal class metadata lookup (and internal failure), plus exceptions being allocated and GC'd.
The following won't help either:
$thing = new DateTime();
$query->setParameter('foo', $thing, DateTimeType::NAME);
$query->getResult();
That's because processParameterValue($value)
is called even when the type is known.
@alcaeus @Ocramius would it be a good idea to skip the entire processParameterValue()
when the type is explicitly passed in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to #7527
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patch at #7528
…()` should not be called for a well specified parameter type As previously reported by @flaushi in doctrine#7471 (comment), we discovered that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance regression when using any `object` type as parameter. Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an exception being thrown and garbage collected, plus multiple associated performance implications: ```php $query->setParameter('foo', new DateTime()); $query->getResult(); ``` ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` This is due to following portion of code: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409 Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value. That call leads to this segment being reached, which leads to the regression: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433 Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object: ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters. In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter out all parameters for which the type is given upfront, and later on merge them back in instead. The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance regression when using any `object` type as parameter. Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an exception being thrown and garbage collected, plus multiple associated performance implications: ```php $query->setParameter('foo', new DateTime()); $query->getResult(); ``` ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` This is due to following portion of code: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409 Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value. That call leads to this segment being reached, which leads to the regression: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433 Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object: ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters. In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter out all parameters for which the type is given upfront, and later on merge them back in instead. The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance regression when using any `object` type as parameter. Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an exception being thrown and garbage collected, plus multiple associated performance implications: ```php $query->setParameter('foo', new DateTime()); $query->getResult(); ``` ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` This is due to following portion of code: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409 Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value. That call leads to this segment being reached, which leads to the regression: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433 Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object: ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters. In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter out all parameters for which the type is given upfront, and later on merge them back in instead. The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
that binding a parameter causes a `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to large performance regression when using any `object` type as parameter. Following two snippets lead to an internal `ClassMetadataFactory#getClassMetadata()` call, which in turn leads to an exception being thrown and garbage collected, plus multiple associated performance implications: ```php $query->setParameter('foo', new DateTime()); $query->getResult(); ``` ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` This is due to following portion of code: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/Query.php#L406-L409 Notice how `$value = $this->processParameterValue($value);` happens before attempting to infer the type for the parameter value. That call leads to this segment being reached, which leads to the regression: https://github.com/doctrine/doctrine2/blob/434820973cadf2da2d66e7184be370084cc32ca8/lib/Doctrine/ORM/AbstractQuery.php#L423-L433 Assuming the bound parameter type is provided, we can completely skip attempting to introspect the given object: ```php $query->setParameter('foo', new DateTime(), DateTimeType::NAME); $query->getResult(); ``` Processing the parameter value is not needed in this case, so we can safely skip that logic for all known parameters. In order to not introduce a BC break or change the `AbstractQuery#processParameterValue()` implementation, we could filter out all parameters for which the type is given upfront, and later on merge them back in instead. The test expectation to be set is for `UnitOfWork#getSingleIdentifierValue()` to never be called.
v2.6.3 [](https://travis-ci.org/doctrine/doctrine2) This release provides fixes for many things, specially: - Regression in commit order calculation - BC-break in `EntityManager#find()` using optimistic lock outside of transaction - PHP 7.3 compatibility issues -------------------------------------------- - Total issues resolved: **8** - Total pull requests resolved: **26** - Total contributors: **26** Documentation ------------- - [7472: fix incorrect phpdoc typehint](doctrine#7472) thanks to @seferov - [7465: Fixes tiny typo in the 'Working with DateTime instances' documentation](doctrine#7465) thanks to @unguul - [7444: Fixed URLs of doctrine-mapping.xsd in docs](doctrine#7444) thanks to @Naitsirch - [7441: $hydrationMode throughout can be a string as well as int (for custom modes)](doctrine#7441) thanks to @asgrim - [7435: Fix a typo on Documentation](doctrine#7435) thanks to @oguzdumanoglu - [7434: Removed FAQ paragraph stating public variables are disallowed](doctrine#7434) thanks to @Naitsirch and @flaushi - [7423: Update association-mapping.rst](doctrine#7423) thanks to @ThomasLandauer - [7421: JIRA to Github issues on Limitations and Known Issues](doctrine#7421) thanks to @seferov - [7412: Some formatting improvements](doctrine#7412) thanks to @ThomasLandauer - [7411: Autoload error when following the Getting Started Guide](doctrine#7411) thanks to @ThomasLandauer - [7401: &doctrine#91;docs&doctrine#93; Fix docblock in `inheritance-mapping.rst`](doctrine#7401) thanks to @bobdenotter - [7397: Update getting-started.rst](doctrine#7397) thanks to @eibt - [7394: Class 'Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver' not found](doctrine#7394) thanks to @ekosynth - [7378: Typo fix](doctrine#7378) thanks to @BenMorel - [7377: Fix query andX doctype](doctrine#7377) thanks to @sserbin - [7374: Deprecation message in documentation for YAML](doctrine#7374) thanks to @SenseException and @iltar - [7360: Document getPartialReference() properly](doctrine#7360) thanks to @lcobucci Bug --- - [7471: Fix parameter value processing for objects with unloaded metadata](doctrine#7471) thanks to @alcaeus - [7367: Fix for BC break in 2.6.2 when calling EM::find() with LockMode::OPTIMISTIC outside of a TX](doctrine#7367) thanks to @timdev - [7328: Handle removed parameters by tree walker in Paginator](doctrine#7328) thanks to @plfort - [7325: Make code php 7.3 lint-compatible](doctrine#7325) thanks to @paxal - [7317: &doctrine#91;XML&doctrine#93; Fix default value of many-to-many order-by to ASC](doctrine#7317) thanks to @alexdenvir - [7260: Fix the handling of circular references in the commit order calculator](doctrine#7260) thanks to @stof - [6830: fix applying column options on foreign key columns](doctrine#6830) thanks to @Tobion Improvement ----------- - [7428: CI: Test against PHP 7.3](doctrine#7428) thanks to @Majkl578 - [7363: Fix compatibility with phan](doctrine#7363) thanks to @philippe-unitiz - [7345: Correct DOMDocument constructor in test](doctrine#7345) thanks to @guilliamxavier - [7307: Fix remaining usages of deprecated ClassLoader and Inflector from doctrine/common](doctrine#7307) thanks to @Majkl578 and @simonwelsh
When binding an object as query parameter, the query object normally tries to convert this object into its identifier. This however only happened if class metadata for the object was already loaded. If it wasn't loaded, conversion was skipped leading to wrong results. While
getMetadataFor
is more performance sensitive thanhasMetadataFor
, we may not assumed that metadata for the bound object has been loaded yet.The code has been changed to no longer check the metadata factory and call
UnitOfWork::getSingleIdentifierValue
directly, ignoring any mapping exception in the process. This preserves behaviour where binding any unmapped object to a query will send the entire object to the database.