-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Failing test: Criteria matching on fields with custom column types #11897
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\Tests\ORM\Functional\ValueConversionType; | ||
|
||
use Doctrine\Common\Collections\Criteria; | ||
use Doctrine\Common\Collections\Expr\Comparison; | ||
use Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity; | ||
use Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity; | ||
use Doctrine\Tests\OrmFunctionalTestCase; | ||
use Generator; | ||
|
||
class ManyToManyCriteriaMatchingTest extends OrmFunctionalTestCase | ||
{ | ||
protected function setUp(): void | ||
{ | ||
$this->useModelSet('vct_manytomany'); | ||
|
||
parent::setUp(); | ||
} | ||
|
||
/** | ||
* @dataProvider provideMatchingExpressions | ||
*/ | ||
public function testCriteriaMatchingOnFieldInManyToManyTarget(Comparison $comparison): void | ||
{ | ||
$associated = new InversedManyToManyEntity(); | ||
$associated->id1 = 'associated'; | ||
|
||
$matching = new OwningManyToManyEntity(); | ||
$matching->id2 = 'first'; | ||
$matching->field = 'match this'; | ||
$matching->associatedEntities->add($associated); | ||
|
||
$nonMatching = new OwningManyToManyEntity(); | ||
$nonMatching->id2 = 'second'; | ||
$nonMatching->field = 'this is no match'; | ||
$nonMatching->associatedEntities->add($associated); | ||
|
||
$this->_em->persist($associated); | ||
$this->_em->persist($matching); | ||
$this->_em->persist($nonMatching); | ||
$this->_em->flush(); | ||
$this->_em->clear(); | ||
|
||
$this->getQueryLog()->reset()->enable(); | ||
|
||
$associated = $this->_em->find(InversedManyToManyEntity::class, 'associated'); | ||
self::assertFalse($associated->associatedEntities->isInitialized(), 'Pre-condition: lazy collection'); | ||
|
||
$result = $associated->associatedEntities->matching(Criteria::create()->where($comparison)); | ||
|
||
$l = $this->getQueryLog(); | ||
|
||
self::assertCount(1, $result); | ||
self::assertSame('first', $result[0]->id2); | ||
} | ||
|
||
public function provideMatchingExpressions(): Generator | ||
{ | ||
yield [Criteria::expr()->eq('field', 'match this')]; | ||
yield [Criteria::expr()->in('field', ['match this'])]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,65 @@ | ||||
<?php | ||||
|
||||
declare(strict_types=1); | ||||
|
||||
namespace Doctrine\Tests\ORM\Functional\ValueConversionType; | ||||
|
||||
use Doctrine\Common\Collections\Criteria; | ||||
use Doctrine\Common\Collections\Expr\Comparison; | ||||
use Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity; | ||||
use Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity; | ||||
use Doctrine\Tests\OrmFunctionalTestCase; | ||||
use Generator; | ||||
|
||||
class OneToManyCriteriaMatchingTest extends OrmFunctionalTestCase | ||||
{ | ||||
protected function setUp(): void | ||||
{ | ||||
$this->useModelSet('vct_onetomany'); | ||||
|
||||
parent::setUp(); | ||||
} | ||||
|
||||
/** | ||||
* @dataProvider provideMatchingExpressions | ||||
*/ | ||||
public function testCriteriaMatchingOnFieldInOneToManyTarget(Comparison $comparison): void | ||||
{ | ||||
$entityWithCollection = new InversedOneToManyEntity(); | ||||
$entityWithCollection->id1 = 'associated'; | ||||
|
||||
$matching = new OwningManyToOneEntity(); | ||||
$matching->id2 = 'first'; | ||||
$matching->field = 'match this'; | ||||
$matching->associatedEntity = $entityWithCollection; | ||||
|
||||
$notMatching = new OwningManyToOneEntity(); | ||||
$notMatching->id2 = 'second'; | ||||
$notMatching->field = 'this is no match'; | ||||
$notMatching->associatedEntity = $entityWithCollection; | ||||
|
||||
$this->_em->persist($entityWithCollection); | ||||
$this->_em->persist($matching); | ||||
$this->_em->persist($notMatching); | ||||
$this->_em->flush(); | ||||
$this->_em->clear(); | ||||
|
||||
$this->getQueryLog()->reset()->enable(); | ||||
|
||||
$entityWithCollection = $this->_em->find(InversedOneToManyEntity::class, 'associated'); | ||||
self::assertFalse($entityWithCollection->associatedEntities->isInitialized(), 'Pre-condition: lazy collection'); | ||||
|
||||
$result = $entityWithCollection->associatedEntities->matching(Criteria::create()->where($comparison)); | ||||
|
||||
$l = $this->getQueryLog(); | ||||
|
||||
self::assertCount(1, $result); | ||||
self::assertSame('first', $result[0]->id2); | ||||
} | ||||
|
||||
public function provideMatchingExpressions(): Generator | ||||
{ | ||||
yield [Criteria::expr()->eq('field', 'match this')]; | ||||
yield [Criteria::expr()->in('field', ['match this'])]; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this one fails because by the time when the following line is executed
$types contains [ArrayParameterType::STRING, 'rot13'] , so at this point, the information about the custom type is lost.
Right now, the DBAL only supports a fixed set of array types (see For this to work, we can try introducing the Not sure what effort it would take and how doable this is within the current type system. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, something like this was my assumption... that we currently cannot combine the array type hint with custom types. If I get you right, your suggestion is to have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between a wrapper and a decorator? I believe I want to see "typed array" as one of the standard types. It will (I guess) wrap (or be parameterized with) its value type. This way, we can build queries with the array values of any standard or custom type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The distinction between wrapper and decorator was not sharp enough. What I meant was that A textbook decorator – to my understanding – implements at least the same interface as the objects it wraps, it's transparent from the interface point of view. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, in this case I mean the decorator. It should wrap a type and be a type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let’s discuss this over at doctrine/dbal#6883 |
||||
} | ||||
} |
Uh oh!
There was an error while loading. Please reload this page.
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.
Not sure if it's related to custom types at all, but this test fails because the following code doesn't properly handle the
IN
operator:orm/src/Persisters/Collection/ManyToManyPersister.php
Lines 257 to 263 in fd041fb
It should:
$params[]
and$paramTypes[]
for each element of the value.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.
#11031 seems to be related to this bug.