Skip to content
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

Check if the discriminator value is null before converting it and setting into rowData during hydration #6304

Closed
wants to merge 11 commits into from

Conversation

fullbl
Copy link
Contributor

@fullbl fullbl commented Feb 24, 2017

fixes #6303

@Ocramius
Copy link
Member

Ocramius commented Feb 24, 2017 via email

@fullbl
Copy link
Contributor Author

fullbl commented Feb 25, 2017

Tests added, but seems that my edit broke a lot of other tests...

Checking for non empty values instead of isset seems to fix things, but this solution is dipendent on the default value of SimpleArray.
I really believe that value assignation should be made in 2 steps, one for checking null values and another one for assigning the default in case of null!

@@ -10,6 +10,7 @@
* @DiscriminatorMap({
* "person" = "Issue5989Person",
* "manager" = "Issue5989Manager",
* "secretary" = "Issue5989Secretary",
Copy link
Member

Choose a reason for hiding this comment

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

Please use a different entity and a new inheritance tree to test your specific scenario

@@ -290,10 +290,10 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
// in an inheritance hierarchy the same field could be defined several times.
// We overwrite this value so long we don't have a non-null value, that value we keep.
// Per definition it cannot be that a field is defined several times and has several values.
if (isset($rowData['data'][$dqlAlias][$fieldName])) {
if (!empty($rowData['data'][$dqlAlias][$fieldName])) {
Copy link
Member

Choose a reason for hiding this comment

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

Comment above explicitly references "non-null" values

$secretary = new Issue5989Secretary();

$secretaryTags = 'single_tag';
$secretary->tags = $secretaryTags;
Copy link
Member

Choose a reason for hiding this comment

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

The fact that you use a different type for a property in the inheritance tree is quite confusing: is this intentional?


static::assertEquals($tags[$people[0]->id], $people[0]->tags);
static::assertEquals($tags[$people[1]->id], $people[1]->tags);
static::assertEquals($tags[$people[2]->id], $people[2]->tags);
Copy link
Member

Choose a reason for hiding this comment

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

Which of these assertions would fail without your patch in place?

@@ -290,10 +290,10 @@ protected function gatherRowData(array $data, array &$id, array &$nonemptyCompon
// in an inheritance hierarchy the same field could be defined several times.
// We overwrite this value so long we don't have a non-null value, that value we keep.
// Per definition it cannot be that a field is defined several times and has several values.
Copy link
Member

Choose a reason for hiding this comment

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

This particular definition is what is being challenged by your inheritance design. The field definition should be fetched per entity name, and $fieldName should be specific to the currently hydrated entity type instead of just the name of a field. Did you try step-debugging here? What is $type?

@fullbl
Copy link
Contributor Author

fullbl commented Feb 28, 2017

Hi, I will create new entities as soon as possible, I thought it would be good to reuse the old ones!

$type is StringType for string and SimpleArrayType for simple array, so is different based on the field.

The problem is exactly as you stated in

The fact that you use a different type for a property in the inheritance tree is quite confusing: is this intentional?

This is what is breaking stuff.

The failing assertion is the one for the string field. It's hydrated by the simple_array as an empty array and missing the real value.

To be honest, I'm not satisfied with my solution, I will think about it in next days!

@fullbl fullbl closed this Mar 4, 2017
@fullbl fullbl reopened this Mar 4, 2017
@fullbl
Copy link
Contributor Author

fullbl commented Mar 4, 2017

Hi again, I fixed the tests to use their own inheritance, but I removed my fix, because I would like to add more tests for checking that setting some property to false, 0 or empty array should return correct values!

@fullbl
Copy link
Contributor Author

fullbl commented Mar 4, 2017

Here we are, I added those tests and decided to redo the fix in another way, keeping only values from the correct table!

Copy link
Member

@lcobucci lcobucci left a comment

Choose a reason for hiding this comment

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

Can you also fix the coding style to match with rest of the project, please?

* "contract_a" = "DDC6303ContractA"
* })
*/
class DDC6303Contract
Copy link
Member

Choose a reason for hiding this comment

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

Please move this class together with the test class (same file)

* @Entity
* @Table(name="ddc6303_contracts_a")
*/
class DDC6303ContractA extends DDC6303Contract
Copy link
Member

Choose a reason for hiding this comment

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

Please move this class together with the test class (same file)

* @Entity
* @Table(name="ddc6303_contracts_b")
*/
class DDC6303ContractB extends DDC6303Contract
Copy link
Member

Choose a reason for hiding this comment

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

Please move this class together with the test class (same file)

{
public function setUp()
{
$this->useModelSet('ddc6303');
Copy link
Member

Choose a reason for hiding this comment

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

Initialise the schema here instead of using a model set

@@ -302,6 +302,12 @@
Models\Issue5989\Issue5989Employee::class,
Models\Issue5989\Issue5989Manager::class,
],
'ddc6303' => [
Copy link
Member

Choose a reason for hiding this comment

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

Not needed when models are in the test file

// in an inheritance hierarchy the same field could be defined several times.
// We overwrite this value so long we don't have a non-null value, that value we keep.
// Per definition it cannot be that a field is defined several times and has several values.
if (isset($rowData['data'][$dqlAlias][$fieldName])) {
break;
}

Copy link
Member

Choose a reason for hiding this comment

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

Please remove the trailing spaces

];
if( !empty($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap]))){
Copy link
Member

Choose a reason for hiding this comment

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

Is this really the expression we're looking for? It looks like it should be:

 if ( ! empty($classMetadata->parentClasses) && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
 }

@fullbl
Copy link
Contributor Author

fullbl commented Mar 11, 2017

Done, I made it first into different files because I copypasted from another issue, maybe it was old!

Copy link
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.

Patch looks good to me! The rest are nitpicks and improvements that can be done on merge.

if(
isset($cacheKeyInfo['discriminatorColumn']) &&
isset($data[$cacheKeyInfo['discriminatorColumn']]) &&
$data[$cacheKeyInfo['discriminatorColumn']] != $cacheKeyInfo['discriminatorValue']
Copy link
Member

Choose a reason for hiding this comment

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

This should be !== to avoid type juggling hell. Yes, that means that object discriminators will fail, that's an edge case that the ORM doesn't handle anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it seems to me that this change is breaking another test (/code/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php:179). Is it ok?

Copy link
Member

Choose a reason for hiding this comment

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

@fullbl it shouldn't break it... let's keep the strict comparison and try to find the root cause.

];
if( !empty($classMetadata->parentClasses) && isset($this->_rsm->discriminatorColumns[$ownerMap])){
$returnArray += [
Copy link
Member

Choose a reason for hiding this comment

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

Consider making two return operations instead of using +=

$contractA->originalData = $contractAData;

$contractB = new DDC6303ContractB();
$contractBData = ['accepted', 'authorized'];
Copy link
Member

Choose a reason for hiding this comment

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

Could you add comments for the reader, specifying that these two entities map originalData differently?

@Ocramius Ocramius self-assigned this Jun 21, 2017
@Ocramius Ocramius changed the title check if value is null before converting it and setting into rowData Check if the discriminator value is null before converting it and setting into rowData during hydration Jun 21, 2017
@Ocramius
Copy link
Member

@fullbl I rebased this branch on top of master to start merging it, but there's a failure in the test suite:

1) Doctrine\Tests\ORM\Functional\SecondLevelCacheJoinTableInheritanceTest::testOneToManyRelationJoinTable
Failed asserting that null matches expected '0000-0000'.

/home/ocramius/Documents/doctrine/doctrine2/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php:179

FAILURES!
Tests: 3185, Assertions: 11878, Failures: 1, Skipped: 46, Incomplete: 2.

@Ocramius
Copy link
Member

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.

@Ocramius Ocramius assigned Ocramius and unassigned fullbl Aug 18, 2017
@lcobucci lcobucci dismissed their stale review August 18, 2017 11:38

Things changed

Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
… (which is bullshit), so we use `array` here
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
Ocramius added a commit that referenced this pull request Aug 19, 2017
…/JTI require additional information and checks in the hydration process
@Ocramius Ocramius closed this in a30d8d8 Aug 19, 2017
@Ocramius
Copy link
Member

Manually merged via a30d8d8

Thanks @fullbl! It took me a while to figure out, but basically, the bug depends on the discriminator map sorting.

A lot of weird factors involved, and indeed an extremely tricky bug to fix. Good work!

@JanTvrdik
Copy link
Contributor

JanTvrdik commented Aug 29, 2017

Maybe I'm doing sth wrong but this change seems to broke the following multi-level STI schema when selecting with QueryBuilder FROM C because $cacheKeyInfo['discriminatorValue'] is NULL and therefore $data[$cacheKeyInfo['discriminatorColumn']] != $cacheKeyInfo['discriminatorValue'] returns in TRUE.

image

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
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants