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

Add support for name converter in filters #2751

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
144 changes: 123 additions & 21 deletions features/bootstrap/DoctrineContext.php
Expand Up @@ -17,6 +17,10 @@
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\CompositeLabel as CompositeLabelDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\CompositePrimitiveItem as CompositePrimitiveItemDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\CompositeRelation as CompositeRelationDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ConvertedBoolean as ConvertedBoolDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ConvertedDate as ConvertedDateDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ConvertedInteger as ConvertedIntegerDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ConvertedString as ConvertedStringDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Customer as CustomerDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Dummy as DummyDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyAggregateOffer as DummyAggregateOfferDocument;
Expand Down Expand Up @@ -62,6 +66,10 @@
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\CompositePrimitiveItem;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\CompositeRelation;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Container;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\ConvertedBoolean;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\ConvertedDate;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\ConvertedInteger;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\ConvertedString;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Customer;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyAggregateOffer;
Expand Down Expand Up @@ -164,6 +172,7 @@ public function thereAreDummyObjects(int $nb)
$dummy->setAlias('Alias #'.($nb - $i));
$dummy->setDummy('SomeDummyTest'.$i);
$dummy->setDescription($descriptions[($i - 1) % 2]);
$dummy->nameConverted = 'Converted '.$i;

$this->manager->persist($dummy);
}
Expand Down Expand Up @@ -257,6 +266,7 @@ public function thereAreDummyPropertyObjects(int $nb)
foreach (['foo', 'bar', 'baz'] as $property) {
$dummyProperty->{$property} = $dummyGroup->{$property} = ucfirst($property).' #'.$i;
}
$dummyProperty->nameConverted = "NameConverted #$i";

$dummyProperty->group = $dummyGroup;

Expand Down Expand Up @@ -657,6 +667,66 @@ public function thereAreDummyObjectsWithDummyDateAndEmbeddedDummy(int $nb)
$this->manager->flush();
}

/**
* @Given there are :nb convertedDate objects
*/
public function thereAreconvertedDateObjectsWith(int $nb)
{
for ($i = 1; $i <= $nb; ++$i) {
$convertedDate = $this->buildConvertedDate();
$convertedDate->nameConverted = new \DateTime(sprintf('2015-04-%d', $i), new \DateTimeZone('UTC'));

$this->manager->persist($convertedDate);
}

$this->manager->flush();
}

/**
* @Given there are :nb convertedString objects
*/
public function thereAreconvertedStringObjectsWith(int $nb)
{
for ($i = 1; $i <= $nb; ++$i) {
$convertedString = $this->buildConvertedString();
$convertedString->nameConverted = ($i % 2) ? "name#$i" : null;

$this->manager->persist($convertedString);
}

$this->manager->flush();
}

/**
* @Given there are :nb convertedBoolean objects
*/
public function thereAreconvertedBooleanObjectsWith(int $nb)
{
for ($i = 1; $i <= $nb; ++$i) {
$convertedBoolean = $this->buildConvertedBoolean();
$convertedBoolean->nameConverted = (bool) ($i % 2);

$this->manager->persist($convertedBoolean);
}

$this->manager->flush();
}

/**
* @Given there are :nb convertedInteger objects
*/
public function thereAreconvertedIntegerObjectsWith(int $nb)
{
for ($i = 1; $i <= $nb; ++$i) {
$convertedInteger = $this->buildConvertedInteger();
$convertedInteger->nameConverted = $i;

$this->manager->persist($convertedInteger);
}

$this->manager->flush();
}

/**
* @Given there are :nb dummy objects with dummyPrice
*/
Expand Down Expand Up @@ -1264,6 +1334,35 @@ public function thereAreNbDummyDtoCustom($nb)
$this->manager->clear();
}

/**
* @Given there is a order with same customer and receiver
*/
public function testEagerLoadingNotDuplicateRelation()
{
$customer = $this->isOrm() ? new Customer() : new CustomerDocument();
$customer->name = 'customer_name';

$address1 = $this->isOrm() ? new Address() : new AddressDocument();
$address1->name = 'foo';
$address2 = $this->isOrm() ? new Address() : new AddressDocument();
$address2->name = 'bar';

$order = $this->isOrm() ? new Order() : new OrderDocument();
$order->recipient = $customer;
$order->customer = $customer;

$customer->addresses->add($address1);
$customer->addresses->add($address2);

$this->manager->persist($address1);
$this->manager->persist($address2);
$this->manager->persist($customer);
$this->manager->persist($order);

$this->manager->flush();
$this->manager->clear();
}

private function isOrm(): bool
{
return null !== $this->schemaTool;
Expand Down Expand Up @@ -1579,31 +1678,34 @@ private function buildThirdLevel()
}

/**
* @Given there is a order with same customer and receiver
* @return ConvertedDate|ConvertedDateDocument
*/
public function testEagerLoadingNotDuplicateRelation()
private function buildConvertedDate()
{
$customer = $this->isOrm() ? new Customer() : new CustomerDocument();
$customer->name = 'customer_name';

$address1 = $this->isOrm() ? new Address() : new AddressDocument();
$address1->name = 'foo';
$address2 = $this->isOrm() ? new Address() : new AddressDocument();
$address2->name = 'bar';

$order = $this->isOrm() ? new Order() : new OrderDocument();
$order->recipient = $customer;
$order->customer = $customer;
return $this->isOrm() ? new ConvertedDate() : new ConvertedDateDocument();
}

$customer->addresses->add($address1);
$customer->addresses->add($address2);
/**
* @return ConvertedBoolean|ConvertedBoolDocument
*/
private function buildConvertedBoolean()
{
return $this->isOrm() ? new ConvertedBoolean() : new ConvertedBoolDocument();
}

$this->manager->persist($address1);
$this->manager->persist($address2);
$this->manager->persist($customer);
$this->manager->persist($order);
/**
* @return ConvertedInteger|ConvertedIntegerDocument
*/
private function buildConvertedInteger()
{
return $this->isOrm() ? new ConvertedInteger() : new ConvertedIntegerDocument();
}

$this->manager->flush();
$this->manager->clear();
/**
* @return ConvertedString|ConvertedStringDocument
*/
private function buildConvertedString()
{
return $this->isOrm() ? new ConvertedString() : new ConvertedStringDocument();
}
}
75 changes: 75 additions & 0 deletions features/doctrine/boolean_filter.feature
Expand Up @@ -448,3 +448,78 @@ Feature: Boolean filter on collections
}
"""
And the JSON node "hydra:totalItems" should be equal to 25

@createSchema
Scenario: Get collection filtered using a name converter
Given there are 5 convertedBoolean objects
When I send a "GET" request to "/converted_booleans?name_converted=false"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/ConvertedBoolean"},
"@id": {"pattern": "^/converted_booleans"},
"@type": {"pattern": "^hydra:Collection$"},
"hydra:member": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@id": {"pattern": "^/converted_booleans/(2|4)$"},
"@type": {"pattern": "^ConvertedBoolean"},
"name_converted": {"type": "boolean"},
"id": {"type": "integer", "minimum":2, "maximum": 4}
},
"required": ["@id", "@type", "name_converted", "id"],
"additionalProperties": false
},
"minItems": 2,
"maxItems": 2,
"uniqueItems": true
},
"hydra:totalItems": {"type": "integer", "minimum": 2, "maximum": 2},
"hydra:view": {
"type": "object",
"properties": {
"@id": {"pattern": "^/converted_booleans\\?name_converted=false"},
"@type": {"pattern": "^hydra:PartialCollectionView$"}
},
"required": ["@id", "@type"],
"additionalProperties": false
},
"hydra:search": {
"type": "object",
"properties": {
"@type": {"pattern": "^hydra:IriTemplate$"},
"hydra:template": {"pattern": "^/converted_booleans\\{\\?name_converted\\}$"},
"hydra:variableRepresentation": {"pattern": "^BasicRepresentation$"},
"hydra:mapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@type": {"pattern": "^IriTemplateMapping$"},
"variable": {"pattern": "^name_converted$"},
"property": {"pattern": "^name_converted$"},
"required": {"type": "boolean"}
},
"required": ["@type", "variable", "property", "required"],
"additionalProperties": false
},
"minItems": 1,
"maxItems": 1,
"uniqueItems": true
}
},
"additionalProperties": false,
"required": ["@type", "hydra:template", "hydra:variableRepresentation", "hydra:mapping"]
},
"additionalProperties": false,
"required": ["@context", "@id", "@type", "hydra:member", "hydra:totalItems", "hydra:view", "hydra:search"]
}
}
"""
83 changes: 82 additions & 1 deletion features/doctrine/date_filter.feature
Expand Up @@ -413,7 +413,7 @@ Feature: Date filter on collections
},
"hydra:search": {
"@type": "hydra:IriTemplate",
"hydra:template": "/dummies{?dummyBoolean,relatedDummy.embeddedDummy.dummyBoolean,dummyDate[before],dummyDate[strictly_before],dummyDate[after],dummyDate[strictly_after],relatedDummy.dummyDate[before],relatedDummy.dummyDate[strictly_before],relatedDummy.dummyDate[after],relatedDummy.dummyDate[strictly_after],exists[alias],exists[description],exists[relatedDummy.name],exists[dummyBoolean],exists[relatedDummy],dummyFloat,dummyFloat[],dummyPrice,dummyPrice[],order[id],order[name],order[description],order[relatedDummy.name],order[relatedDummy.symfony],order[dummyDate],dummyFloat[between],dummyFloat[gt],dummyFloat[gte],dummyFloat[lt],dummyFloat[lte],dummyPrice[between],dummyPrice[gt],dummyPrice[gte],dummyPrice[lt],dummyPrice[lte],id,id[],name,alias,description,relatedDummy.name,relatedDummy.name[],relatedDummies,relatedDummies[],dummy,relatedDummies.name,relatedDummy.thirdLevel.level,relatedDummy.thirdLevel.level[],relatedDummy.thirdLevel.fourthLevel.level,relatedDummy.thirdLevel.fourthLevel.level[],relatedDummy.thirdLevel.badFourthLevel.level,relatedDummy.thirdLevel.badFourthLevel.level[],relatedDummy.thirdLevel.fourthLevel.badThirdLevel.level,relatedDummy.thirdLevel.fourthLevel.badThirdLevel.level[],properties[]}",
"hydra:template": "/dummies{?dummyBoolean,relatedDummy.embeddedDummy.dummyBoolean,dummyDate[before],dummyDate[strictly_before],dummyDate[after],dummyDate[strictly_after],relatedDummy.dummyDate[before],relatedDummy.dummyDate[strictly_before],relatedDummy.dummyDate[after],relatedDummy.dummyDate[strictly_after],exists[alias],exists[description],exists[relatedDummy.name],exists[dummyBoolean],exists[relatedDummy],dummyFloat,dummyFloat[],dummyPrice,dummyPrice[],order[id],order[name],order[description],order[relatedDummy.name],order[relatedDummy.symfony],order[dummyDate],dummyFloat[between],dummyFloat[gt],dummyFloat[gte],dummyFloat[lt],dummyFloat[lte],dummyPrice[between],dummyPrice[gt],dummyPrice[gte],dummyPrice[lt],dummyPrice[lte],id,id[],name,alias,description,relatedDummy.name,relatedDummy.name[],relatedDummies,relatedDummies[],dummy,relatedDummies.name,relatedDummy.thirdLevel.level,relatedDummy.thirdLevel.level[],relatedDummy.thirdLevel.fourthLevel.level,relatedDummy.thirdLevel.fourthLevel.level[],relatedDummy.thirdLevel.badFourthLevel.level,relatedDummy.thirdLevel.badFourthLevel.level[],relatedDummy.thirdLevel.fourthLevel.badThirdLevel.level,relatedDummy.thirdLevel.fourthLevel.badThirdLevel.level[],name_converted,properties[]}",
"hydra:variableRepresentation": "BasicRepresentation",
"hydra:mapping": [
{
Expand Down Expand Up @@ -740,6 +740,12 @@ Feature: Date filter on collections
"property": "relatedDummy.thirdLevel.fourthLevel.badThirdLevel.level",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "name_converted",
"property": "name_converted",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "properties[]",
Expand Down Expand Up @@ -1102,3 +1108,78 @@ Feature: Date filter on collections
}
}
"""

@createSchema
Scenario: Get collection filtered using a name converter
Given there are 30 convertedDate objects
When I send a "GET" request to "/converted_dates?name_converted[strictly_after]=2015-04-28"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be valid according to this schema:
"""
{
"type": "object",
"properties": {
"@context": {"pattern": "^/contexts/ConvertedDate"},
"@id": {"pattern": "^/converted_dates"},
"@type": {"pattern": "^hydra:Collection$"},
"hydra:member": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@id": {"pattern": "^/converted_dates/(29|30)$"},
"@type": {"pattern": "^ConvertedDate"},
"name_converted": {"type": "string"},
"id": {"type": "integer", "minimum":29, "maximum": 30}
},
"required": ["@id", "@type", "name_converted", "id"],
"additionalProperties": false
},
"minItems": 2,
"maxItems": 2,
"uniqueItems": true
},
"hydra:totalItems": {"type": "integer", "minimum": 2, "maximum": 2},
"hydra:view": {
"type": "object",
"properties": {
"@id": {"pattern": "^/converted_dates\\?name_converted%5Bstrictly_after%5D=2015\\-04\\-28$"},
"@type": {"pattern": "^hydra:PartialCollectionView$"}
},
"required": ["@id", "@type"],
"additionalProperties": false
},
"hydra:search": {
"type": "object",
"properties": {
"@type": {"pattern": "^hydra:IriTemplate$"},
"hydra:template": {"pattern": "^/converted_dates\\{\\?.*name_converted\\[before\\],name_converted\\[strictly_before\\],name_converted\\[after\\],name_converted\\[strictly_after\\].*\\}$"},
"hydra:variableRepresentation": {"pattern": "^BasicRepresentation$"},
"hydra:mapping": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@type": {"pattern": "^IriTemplateMapping$"},
"variable": {"pattern": "^name_converted(\\[(strictly_)?(before|after)\\])$"},
"property": {"pattern": "^name_converted$"},
"required": {"type": "boolean"}
},
"required": ["@type", "variable", "property", "required"],
"additionalProperties": false
},
"minItems": 4,
"maxItems": 4,
"uniqueItems": true
}
},
"additionalProperties": false,
"required": ["@type", "hydra:template", "hydra:variableRepresentation", "hydra:mapping"]
},
"additionalProperties": false,
"required": ["@context", "@id", "@type", "hydra:member", "hydra:totalItems", "hydra:view", "hydra:search"]
}
}
"""