Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Inheritance middle-layer doesn't get hydrated#6988

Merged
Ocramius merged 4 commits into
doctrine:2.6from
kbond:inheritance-issue
Feb 19, 2018
Merged

Inheritance middle-layer doesn't get hydrated#6988
Ocramius merged 4 commits into
doctrine:2.6from
kbond:inheritance-issue

Conversation

@kbond
Copy link
Copy Markdown
Contributor

@kbond kbond commented Jan 15, 2018

This is a failing test to show the issue.

Given the following inheritance structure:

Person <- Employee <- Manager

When hydrating a manager using a query builder created from the person repository, the employee's properties do not get hydrated.

I think this was caused by #6304.

;

$this->assertSame('Kevin', $persistedManager->name);
$this->assertSame('555-5555', $persistedManager->phoneNumber);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the failure.

@kbond
Copy link
Copy Markdown
Contributor Author

kbond commented Jan 17, 2018

I added another test to show it working when using the HYDRATE_SIMPLEOBJECT hydrator.

// the current discriminator value must be saved in order to disambiguate fields hydration,
// should there be field name collisions
if ($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
$discriminatorValues = array_map(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius @guilhermeblanco in theory this addition should have some impact on performance, but the overall result of phpbench in my machine is slightly better than it was before:

- ⅀T: 1,914,921.000μs μSD/r 0.000μs μRSD/r: 0.000%
+ ⅀T: 1,879,858.000μs μSD/r 0.000μs μRSD/r: 0.000%

It's possible that my laptop is a bit crazy but... whatever.

Not sure if it's relevant for v2.x but for v3.x we could create the list of all discriminator values of the subclasses during the metadata creation.

Complete phpbench diff
\Doctrine\Performance\Hydration\SimpleQueryPartialObjectHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 109,739.000 109,739.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 95,171.000 95,171.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SimpleQueryScalarHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 37,513.000 37,513.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 34,285.000 34,285.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\MixedQueryFetchJoinFullObjectHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 105,009.000 105,009.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 100,475.000 100,475.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SimpleQueryFullObjectHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 337,610.000 337,610.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 329,276.000 329,276.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SingleTableInheritanceInsertPerformanceBench

-    benchInsertFixContracts       I0 P0 	[μ Mo]/r: 8,695.000 8,695.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInsertFixContracts       I0 P0 	[μ Mo]/r: 7,281.000 7,281.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchInsertFlexContracts      I0 P0 	[μ Mo]/r: 7,156.000 7,156.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInsertFlexContracts      I0 P0 	[μ Mo]/r: 7,624.000 7,624.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchInsertUltraContracts     I0 P0 	[μ Mo]/r: 8,162.000 8,162.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInsertUltraContracts     I0 P0 	[μ Mo]/r: 7,510.000 7,510.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchInsertAllContracts       I0 P0 	[μ Mo]/r: 11,867.000 11,867.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInsertAllContracts       I0 P0 	[μ Mo]/r: 13,101.000 13,101.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SingleTableInheritanceHydrationPerformanceBench

-    benchHydrateFixContracts      I0 P0 	[μ Mo]/r: 3,520.000 3,520.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydrateFixContracts      I0 P0 	[μ Mo]/r: 3,815.000 3,815.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchHydrateFlexContracts     I0 P0 	[μ Mo]/r: 4,791.000 4,791.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydrateFlexContracts     I0 P0 	[μ Mo]/r: 4,108.000 4,108.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchHydrateUltraContracts    I0 P0 	[μ Mo]/r: 3,921.000 3,921.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydrateUltraContracts    I0 P0 	[μ Mo]/r: 3,636.000 3,636.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchHydrateAllContracts      I0 P0 	[μ Mo]/r: 4,898.000 4,898.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydrateAllContracts      I0 P0 	[μ Mo]/r: 5,067.000 5,067.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SimpleInsertPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 494,637.000 494,637.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 497,152.000 497,152.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SimpleQueryArrayHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 53,799.000 53,799.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 50,772.000 50,772.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\MixedQueryFetchJoinPartialObjectHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 56,808.000 56,808.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 55,068.000 55,068.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\MixedQueryFetchJoinArrayHydrationPerformanceBench

-    benchHydration                I0 P0 	[μ Mo]/r: 102,135.000 102,135.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 99,480.000 99,480.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\Hydration\SimpleHydrationBench

-    benchHydration                I0 P0 	[μ Mo]/r: 260,085.000 260,085.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchHydration                I0 P0 	[μ Mo]/r: 257,370.000 257,370.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\ChangeSet\UnitOfWorkComputeChangesBench

-    benchChangeSetComputation     I0 P0 	[μ Mo]/r: 1,536.000 1,536.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchChangeSetComputation     I0 P0 	[μ Mo]/r: 1,519.000 1,519.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\LazyLoading\ProxyInitializationTimeBench

-    benchCmsUserInitialization    I0 P0 	[μ Mo]/r: 69,404.000 69,404.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchCmsUserInitialization    I0 P0 	[μ Mo]/r: 65,095.000 65,095.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchCmsEmployeeInitializationI0 P0 	[μ Mo]/r: 11,635.000 11,635.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchCmsEmployeeInitializationI0 P0 	[μ Mo]/r: 11,820.000 11,820.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchInitializationOfAlreadyInitializedCmsUsersI0 P0 	[μ Mo]/r: 777.000 777.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInitializationOfAlreadyInitializedCmsUsersI0 P0 	[μ Mo]/r: 822.000 822.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchInitializationOfAlreadyInitializedCmsEmployeesI0 P0 	[μ Mo]/r: 625.000 625.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchInitializationOfAlreadyInitializedCmsEmployeesI0 P0 	[μ Mo]/r: 651.000 651.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

\Doctrine\Performance\LazyLoading\ProxyInstantiationTimeBench

-    benchCmsUserInstantiation     I0 P0 	[μ Mo]/r: 127,576.000 127,576.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchCmsUserInstantiation     I0 P0 	[μ Mo]/r: 135,914.000 135,914.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
-    benchCmsEmployeeInstantiation I0 P0 	[μ Mo]/r: 93,023.000 93,023.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%
+    benchCmsEmployeeInstantiation I0 P0 	[μ Mo]/r: 92,846.000 92,846.000 (μs) 	[μSD μRSD]/r: 0.000μs 0.00%

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's relevant for v2.x but for v3.x we could create the list of all discriminator values of the subclasses during the metadata creation.

More than that, questions to the metadata should be asked directly to the metadata, rather than done in random metadata consumers

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is an O(1) called at hydrator initialisation, if I'm not mistaken.

Please move it to a private method

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lcobucci extremely flaky bench test results, but they seem to stay around normal values, so it is OK IMO

if (isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']])
// Note: loose comparison required. See https://github.com/doctrine/doctrine2/pull/6304#issuecomment-323294442
&& ! in_array($data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'])
&& ! in_array((string) $data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'], true)
Copy link
Copy Markdown
Member

@lcobucci lcobucci Feb 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that comment @Ocramius says:

I checked the issue locally, and it's because the discriminator is not converted to a PHP value.

That said, trying to fix the issue leads to a massive can of worms that is being opened: let's keep the loose comparison there for now.

I've opened the can of worms and it wasn't that bad but it's possible that I've overlooked things, please use some ❤️ to review this commit

@lcobucci lcobucci added this to the 2.6.1 milestone Feb 18, 2018
Copy link
Copy Markdown
Member

@Ocramius Ocramius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides code to be moved to a private method, looks OK 👍

// the current discriminator value must be saved in order to disambiguate fields hydration,
// should there be field name collisions
if ($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
$discriminatorValues = array_map(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's relevant for v2.x but for v3.x we could create the list of all discriminator values of the subclasses during the metadata creation.

More than that, questions to the metadata should be asked directly to the metadata, rather than done in random metadata consumers

// the current discriminator value must be saved in order to disambiguate fields hydration,
// should there be field name collisions
if ($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
$discriminatorValues = array_map(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is an O(1) called at hydrator initialisation, if I'm not mistaken.

Please move it to a private method

// the current discriminator value must be saved in order to disambiguate fields hydration,
// should there be field name collisions
if ($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
$discriminatorValues = array_map(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lcobucci extremely flaky bench test results, but they seem to stay around normal values, so it is OK IMO

@lcobucci
Copy link
Copy Markdown
Member

@Ocramius please check if everything is good and :shipit:

@lcobucci lcobucci assigned Ocramius and unassigned lcobucci Feb 19, 2018
kbond and others added 4 commits February 19, 2018 12:07
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.
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.
@Ocramius
Copy link
Copy Markdown
Member

🐑

@Ocramius
Copy link
Copy Markdown
Member

One unrelated test failed

@Ocramius Ocramius merged commit a736a37 into doctrine:2.6 Feb 19, 2018
Ocramius added a commit that referenced this pull request Feb 19, 2018
 - `em` protected property
 - annotation namespace change
 - `QueryBuilder` instantiation
Ocramius added a commit that referenced this pull request Feb 19, 2018
@Ocramius
Copy link
Copy Markdown
Member

Forward-port in master in 0822f8a

supersmile2009 pushed a commit to supersmile2009/doctrine2 that referenced this pull request Feb 21, 2018
Inheritance middle-layer doesn't get hydrated
maglnet pushed a commit to maglnet/doctrine2 that referenced this pull request Oct 10, 2018
…es in `3.x`

 - `em` protected property
 - annotation namespace change
 - `QueryBuilder` instantiation
@kbond kbond deleted the inheritance-issue branch February 27, 2020 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants