-
-
Notifications
You must be signed in to change notification settings - Fork 922
feature: improve ids management for association and fix invalid iri/uuid in SearchFilter #1844
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 |
---|---|---|
|
@@ -20,37 +20,62 @@ Feature: Search filter on collections | |
When I send a "GET" request to "/dummy_cars?colors.prop=red" | ||
Then the response status code should be 200 | ||
And the JSON should be deep equal to: | ||
""" | ||
""" | ||
{ | ||
"@context": "/contexts/DummyCar", | ||
"@id": "/dummy_cars", | ||
"@type": "hydra:Collection", | ||
"hydra:member": [ | ||
"@context": "/contexts/DummyCar", | ||
"@id": "/dummy_cars", | ||
"@type": "hydra:Collection", | ||
"hydra:member": [ | ||
{ | ||
"@id": "/dummy_cars/1", | ||
"@type": "DummyCar", | ||
"colors": [ | ||
{ | ||
"@id": "/dummy_cars/1", | ||
"@type": "DummyCar", | ||
"colors": [ | ||
{ | ||
"@id": "/dummy_car_colors/1", | ||
"@type": "DummyCarColor", | ||
"prop": "red" | ||
}, | ||
{ | ||
"@id": "/dummy_car_colors/2", | ||
"@type": "DummyCarColor", | ||
"prop": "blue" | ||
} | ||
] | ||
"@id": "/dummy_car_colors/1", | ||
"@type": "DummyCarColor", | ||
"prop": "red" | ||
}, | ||
{ | ||
"@id": "/dummy_car_colors/2", | ||
"@type": "DummyCarColor", | ||
"prop": "blue" | ||
} | ||
], | ||
"hydra:totalItems": 1, | ||
"hydra:view": { | ||
"@id": "/dummy_cars?colors.prop=red", | ||
"@type": "hydra:PartialCollectionView" | ||
}, | ||
"hydra:search": { | ||
], | ||
"secondColors": [ | ||
{ | ||
"@id": "/dummy_car_colors/1", | ||
"@type": "DummyCarColor", | ||
"prop": "red" | ||
}, | ||
{ | ||
"@id": "/dummy_car_colors/2", | ||
"@type": "DummyCarColor", | ||
"prop": "blue" | ||
} | ||
], | ||
"thirdColors": [ | ||
{ | ||
"@id": "/dummy_car_colors/1", | ||
"@type": "DummyCarColor", | ||
"prop": "red" | ||
}, | ||
{ | ||
"@id": "/dummy_car_colors/2", | ||
"@type": "DummyCarColor", | ||
"prop": "blue" | ||
} | ||
], | ||
"uuid": [] | ||
} | ||
], | ||
"hydra:totalItems": 1, | ||
"hydra:view": { | ||
"@id": "/dummy_cars?colors.prop=red", | ||
"@type": "hydra:PartialCollectionView" | ||
}, | ||
"hydra:search": { | ||
"@type": "hydra:IriTemplate", | ||
"hydra:template": "\/dummy_cars{?availableAt[before],availableAt[strictly_before],availableAt[after],availableAt[strictly_after],canSell,foobar[],foobargroups[],foobargroups_override[],colors.prop,name}", | ||
"hydra:template": "/dummy_cars{?availableAt[before],availableAt[strictly_before],availableAt[after],availableAt[strictly_after],canSell,foobar[],foobargroups[],foobargroups_override[],colors.prop,colors,colors[],secondColors,secondColors[],thirdColors,thirdColors[],uuid,uuid[],name}", | ||
"hydra:variableRepresentation": "BasicRepresentation", | ||
"hydra:mapping": [ | ||
{ | ||
|
@@ -83,12 +108,24 @@ Feature: Search filter on collections | |
"property": "canSell", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "colors", | ||
"property": "colors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "colors.prop", | ||
"property": "colors.prop", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "colors[]", | ||
"property": "colors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "foobar[]", | ||
|
@@ -112,6 +149,42 @@ Feature: Search filter on collections | |
"variable": "name", | ||
"property": "name", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "secondColors", | ||
"property": "secondColors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "secondColors[]", | ||
"property": "secondColors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "thirdColors", | ||
"property": "thirdColors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "thirdColors[]", | ||
"property": "thirdColors", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "uuid", | ||
"property": "uuid", | ||
"required": false | ||
}, | ||
{ | ||
"@type": "IriTemplateMapping", | ||
"variable": "uuid[]", | ||
"property": "uuid", | ||
"required": false | ||
} | ||
] | ||
} | ||
|
@@ -389,8 +462,7 @@ Feature: Search filter on collections | |
"@id": {"pattern": "^/dummies$"}, | ||
"@type": {"pattern": "^hydra:Collection$"}, | ||
"hydra:member": { | ||
"type": "array", | ||
"maxItems": 0 | ||
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. Please do not remove this check, but replace it with the right value 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. This is because the test was wrong in the first place, an invalid filter should not be applied and therefore should return every items of the collection. We fixed that here. |
||
"type": "array" | ||
}, | ||
"hydra:view": { | ||
"type": "object", | ||
|
@@ -655,3 +727,4 @@ Feature: Search filter on collections | |
} | ||
} | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,13 +13,15 @@ | |
|
||
namespace ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter; | ||
|
||
use ApiPlatform\Core\Api\IdentifiersExtractorInterface; | ||
use ApiPlatform\Core\Api\IriConverterInterface; | ||
use ApiPlatform\Core\Bridge\Doctrine\Common\Filter\SearchFilterInterface; | ||
use ApiPlatform\Core\Bridge\Doctrine\Common\Filter\SearchFilterTrait; | ||
use ApiPlatform\Core\Exception\InvalidArgumentException; | ||
use Doctrine\Common\Persistence\ManagerRegistry; | ||
use Doctrine\Common\Persistence\Mapping\ClassMetadata; | ||
use Doctrine\ODM\MongoDB\Aggregation\Builder; | ||
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as MongoDBClassMetadata; | ||
use Doctrine\ODM\MongoDB\Types\Type as MongoDbType; | ||
use MongoDB\BSON\Regex; | ||
use Psr\Log\LoggerInterface; | ||
|
@@ -40,12 +42,17 @@ final class SearchFilter extends AbstractFilter implements SearchFilterInterface | |
|
||
public const DOCTRINE_INTEGER_TYPE = MongoDbType::INTEGER; | ||
|
||
public function __construct(ManagerRegistry $managerRegistry, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null, array $properties = null) | ||
public function __construct(ManagerRegistry $managerRegistry, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null, array $properties = null, IdentifiersExtractorInterface $identifiersExtractor = null) | ||
{ | ||
parent::__construct($managerRegistry, $logger, $properties); | ||
|
||
if (null === $identifiersExtractor) { | ||
@trigger_error('Not injecting ItemIdentifiersExtractor is deprecated since API Platform 2.5 and can lead to unexpected behaviors, it will not be possible anymore in API Platform 3.0.', E_USER_DEPRECATED); | ||
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. Mongo is marked as |
||
} | ||
|
||
$this->iriConverter = $iriConverter; | ||
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); | ||
$this->identifiersExtractor = $identifiersExtractor; | ||
} | ||
|
||
protected function getIriConverter(): IriConverterInterface | ||
|
@@ -77,6 +84,10 @@ protected function filterProperty(string $property, $value, Builder $aggregation | |
if ($this->isPropertyNested($property, $resourceClass)) { | ||
[$matchField, $field, $associations] = $this->addLookupsForNestedProperty($property, $aggregationBuilder, $resourceClass); | ||
} | ||
|
||
/** | ||
* @var MongoDBClassMetadata | ||
*/ | ||
$metadata = $this->getNestedMetadata($resourceClass, $associations); | ||
|
||
$values = $this->normalizeValues((array) $value, $property); | ||
|
@@ -124,8 +135,16 @@ protected function filterProperty(string $property, $value, Builder $aggregation | |
} | ||
|
||
$values = array_map([$this, 'getIdFromValue'], $values); | ||
$associationFieldIdentifier = 'id'; | ||
$doctrineTypeField = $this->getDoctrineFieldType($property, $resourceClass); | ||
|
||
if (null !== $this->identifiersExtractor) { | ||
$associationResourceClass = $metadata->getAssociationTargetClass($field); | ||
$associationFieldIdentifier = $this->identifiersExtractor->getIdentifiersFromResourceClass($associationResourceClass)[0]; | ||
$doctrineTypeField = $this->getDoctrineFieldType($associationFieldIdentifier, $associationResourceClass); | ||
} | ||
|
||
if (!$this->hasValidValues($values, $this->getDoctrineFieldType($property, $resourceClass))) { | ||
if (!$this->hasValidValues($values, $doctrineTypeField)) { | ||
$this->logger->notice('Invalid filter ignored', [ | ||
'exception' => new InvalidArgumentException(sprintf('Values for field "%s" are not valid according to the doctrine type.', $property)), | ||
]); | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -66,7 +66,9 @@ | |||||
<argument type="service" id="api_platform.iri_converter" /> | ||||||
<argument type="service" id="api_platform.property_accessor" /> | ||||||
<argument type="service" id="logger" on-invalid="ignore" /> | ||||||
<argument key="$identifiersExtractor" type="service" id="api_platform.identifiers_extractor.cached" /> | ||||||
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.
Suggested change
|
||||||
</service> | ||||||
|
||||||
<service id="ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\SearchFilter" alias="api_platform.doctrine_mongodb.odm.search_filter" /> | ||||||
|
||||||
<service id="api_platform.doctrine_mongodb.odm.boolean_filter" class="ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\BooleanFilter" public="false" abstract="true"> | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -55,6 +55,7 @@ | |||||
<argument type="service" id="api_platform.iri_converter" /> | ||||||
<argument type="service" id="api_platform.property_accessor" /> | ||||||
<argument type="service" id="logger" on-invalid="ignore" /> | ||||||
<argument key="$identifiersExtractor" type="service" id="api_platform.identifiers_extractor.cached" /> | ||||||
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.
Suggested change
|
||||||
</service> | ||||||
<service id="ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter" alias="api_platform.doctrine.orm.search_filter" /> | ||||||
|
||||||
|
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.
Tab indent instead of spaces