Skip to content

Merge 2.6 #4111

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

Merged
merged 10 commits into from
Mar 4, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring
extensions: intl, bcmath, curl, openssl, mbstring, pdo_sqlite
coverage: pcov
ini-values: memory_limit=-1
- name: Get composer cache directory
Expand Down Expand Up @@ -507,7 +507,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
tools: pecl, composer
extensions: intl, bcmath, curl, openssl, mbstring
extensions: intl, bcmath, curl, openssl, mbstring, mongodb
coverage: none
ini-values: memory_limit=-1
- name: Get composer cache directory
Expand Down Expand Up @@ -669,7 +669,7 @@ jobs:
- name: Update project dependencies
run: composer update --no-interaction --no-progress --ansi
- name: Require Symfony Uid
run: composer require symfony/uid --dev --no-interaction --no-progress --ansi
run: composer require symfony/uid symfony/intl --dev --no-interaction --no-progress --ansi
- name: Flag held back Symfony packages
env:
symfony_version: ${{ matrix.symfony }}
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
* Mercure: Do not use data in options when deleting (#4056)
* Doctrine: Support for foreign identifiers (#4042)
* Doctrine: Support for binary UUID in search filter (#3774)
* Doctrine: Do not add join or lookup for search filter with empty value (#3703)
* Doctrine: Reduce code duplication in search filter (#3541)
* JSON Schema: Allow generating documentation when property and method start from "is" (property `isActive` and method `isActive`) (#4064)
* OpenAPI: Fix missing 422 responses in the documentation (#4086)
* OpenAPI: Fix error when schema is empty (#4051)
* OpenAPI: Do not set scheme to oauth2 when generating securitySchemes (#4073)
* OpenAPI: Fix missing `$ref` when no `type` is used in context (#4076)
* GraphQL: Fix "Resource class cannot be determined." error when a null iterable field is returned (#4092)
* Metadata: Check the output class when calculating serializer groups (#3696)

## 2.6.2

Expand Down
62 changes: 34 additions & 28 deletions src/Bridge/Doctrine/MongoDbOdm/Filter/SearchFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,27 @@ protected function filterProperty(string $property, $value, Builder $aggregation

$matchField = $field = $property;

$values = $this->normalizeValues((array) $value, $property);
if (null === $values) {
return;
}

$associations = [];
if ($this->isPropertyNested($property, $resourceClass)) {
[$matchField, $field, $associations] = $this->addLookupsForNestedProperty($property, $aggregationBuilder, $resourceClass);
}

/**
* @var MongoDBClassMetadata
*/
$metadata = $this->getNestedMetadata($resourceClass, $associations);
$caseSensitive = true;
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;

$values = $this->normalizeValues((array) $value, $property);
if (null === $values) {
return;
// prefixing the strategy with i makes it case insensitive
if (0 === strpos($strategy, 'i')) {
$strategy = substr($strategy, 1);
$caseSensitive = false;
}

$caseSensitive = true;
/** @var MongoDBClassMetadata */
$metadata = $this->getNestedMetadata($resourceClass, $associations);

if ($metadata->hasField($field) && !$metadata->hasAssociation($field)) {
if ('id' === $field) {
Expand All @@ -107,23 +112,9 @@ protected function filterProperty(string $property, $value, Builder $aggregation
return;
}

$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;

// prefixing the strategy with i makes it case insensitive
if (0 === strpos($strategy, 'i')) {
$strategy = substr($strategy, 1);
$caseSensitive = false;
}
$this->addEqualityMatchStrategy($strategy, $aggregationBuilder, $field, $matchField, $values, $caseSensitive, $metadata);

$inValues = [];
foreach ($values as $inValue) {
$inValues[] = $this->addEqualityMatchStrategy($strategy, $field, $inValue, $caseSensitive, $metadata);
}

$aggregationBuilder
->match()
->field($matchField)
->in($inValues);
return;
}

// metadata doesn't have the field, nor an association on the field
Expand All @@ -132,7 +123,6 @@ 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) {
Expand All @@ -149,23 +139,39 @@ protected function filterProperty(string $property, $value, Builder $aggregation
return;
}

$this->addEqualityMatchStrategy($strategy, $aggregationBuilder, $field, $matchField, $values, $caseSensitive, $metadata);
}

/**
* Add equality match stage according to the strategy.
*/
private function addEqualityMatchStrategy(string $strategy, Builder $aggregationBuilder, string $field, string $matchField, $values, bool $caseSensitive, ClassMetadata $metadata): void
{
$inValues = [];
foreach ($values as $inValue) {
$inValues[] = $this->getEqualityMatchStrategyValue($strategy, $field, $inValue, $caseSensitive, $metadata);
}

$aggregationBuilder
->match()
->field($matchField)
->in($values);
->in($inValues);
}

/**
* Add equality match stage according to the strategy.
* Get equality match value according to the strategy.
*
* @throws InvalidArgumentException If strategy does not exist
*
* @return Regex|string
*/
private function addEqualityMatchStrategy(string $strategy, string $field, $value, bool $caseSensitive, ClassMetadata $metadata)
private function getEqualityMatchStrategyValue(string $strategy, string $field, $value, bool $caseSensitive, ClassMetadata $metadata)
{
$type = $metadata->getTypeOfField($field);

if (!MongoDbType::hasType($type)) {
return $value;
}
if (MongoDbType::STRING !== $type) {
return MongoDbType::getType($type)->convertToDatabaseValue($value);
}
Expand Down
48 changes: 13 additions & 35 deletions src/Bridge/Doctrine/Orm/Filter/SearchFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,23 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB
$alias = $queryBuilder->getRootAliases()[0];
$field = $property;

$values = $this->normalizeValues((array) $value, $property);
if (null === $values) {
return;
}

$associations = [];
if ($this->isPropertyNested($property, $resourceClass)) {
[$alias, $field, $associations] = $this->addJoinsForNestedProperty($property, $alias, $queryBuilder, $queryNameGenerator, $resourceClass);
}

$values = $this->normalizeValues((array) $value, $property);
if (null === $values) {
return;
$caseSensitive = true;
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;

// prefixing the strategy with i makes it case insensitive
if (0 === strpos($strategy, 'i')) {
$strategy = substr($strategy, 1);
$caseSensitive = false;
}

$metadata = $this->getNestedMetadata($resourceClass, $associations);
Expand All @@ -106,15 +115,6 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB
return;
}

$caseSensitive = true;
$strategy = $this->properties[$property] ?? self::STRATEGY_EXACT;

// prefixing the strategy with i makes it case insensitive
if (0 === strpos($strategy, 'i')) {
$strategy = substr($strategy, 1);
$caseSensitive = false;
}

$this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $alias, $field, $values, $caseSensitive, $metadata);

return;
Expand Down Expand Up @@ -145,34 +145,12 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB

$associationAlias = $alias;
$associationField = $field;
$valueParameter = $queryNameGenerator->generateParameterName($associationField);
if ($metadata->isCollectionValuedAssociation($associationField)) {
$associationAlias = QueryBuilderHelper::addJoinOnce($queryBuilder, $queryNameGenerator, $alias, $associationField);
$associationField = $associationFieldIdentifier;
}

$type = $metadata->getTypeOfField($associationField);

if (1 === \count($values)) {
$queryBuilder
->andWhere($queryBuilder->expr()->eq($associationAlias.'.'.$associationField, ':'.$valueParameter))
->setParameter($valueParameter, $values[0], $type);

return;
}

$parameters = $queryBuilder->getParameters();
$inQuery = [];

foreach ($values as $val) {
$inQuery[] = ':'.$valueParameter;
$parameters->add(new Parameter($valueParameter, $val, $type));
$valueParameter = $queryNameGenerator->generateParameterName($associationField);
}

$queryBuilder
->andWhere($associationAlias.'.'.$associationField.' IN ('.implode(', ', $inQuery).')')
->setParameters($parameters);
$this->addWhereByStrategy($strategy, $queryBuilder, $queryNameGenerator, $associationAlias, $associationField, $values, $caseSensitive, $metadata);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ private function getSerializerAttributeMetadata(string $class, string $attribute
*/
private function getClassSerializerGroups(string $class): array
{
$resourceMetadata = $this->resourceMetadataFactory->create($class);
if ($outputClass = $resourceMetadata->getAttribute('output')['class'] ?? null) {
$class = $outputClass;
}

$serializerClassMetadata = $this->serializerClassMetadataFactory->getMetadataFor($class);

$groups = [];
Expand Down
10 changes: 5 additions & 5 deletions src/OpenApi/Model/PathItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,31 +138,31 @@ public function withDescription(string $description): self
return $clone;
}

public function withGet(Operation $get): self
public function withGet(?Operation $get): self
{
$clone = clone $this;
$clone->get = $get;

return $clone;
}

public function withPut(Operation $put): self
public function withPut(?Operation $put): self
{
$clone = clone $this;
$clone->put = $put;

return $clone;
}

public function withPost(Operation $post): self
public function withPost(?Operation $post): self
{
$clone = clone $this;
$clone->post = $post;

return $clone;
}

public function withDelete(Operation $delete): self
public function withDelete(?Operation $delete): self
{
$clone = clone $this;
$clone->delete = $delete;
Expand All @@ -186,7 +186,7 @@ public function withHead(Operation $head): self
return $clone;
}

public function withPatch(Operation $patch): self
public function withPatch(?Operation $patch): self
{
$clone = clone $this;
$clone->patch = $patch;
Expand Down
2 changes: 1 addition & 1 deletion src/OpenApi/OpenApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function getServers(): array
return $this->servers;
}

public function getPaths()
public function getPaths(): Paths
{
return $this->paths;
}
Expand Down
8 changes: 8 additions & 0 deletions tests/Bridge/Doctrine/Common/Filter/SearchFilterTestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,14 @@ private function provideApplyTestArguments(): array
'relatedDummy.symfony' => 'exact',
],
],
'empty nested property' => [
[
'relatedDummy.symfony' => null,
],
[
'relatedDummy.symfony' => [],
],
],
];
}
}
4 changes: 4 additions & 0 deletions tests/Bridge/Doctrine/MongoDbOdm/Filter/SearchFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,10 @@ public function provideApplyTestData(): array
],
$filterFactory,
],
'empty nested property' => [
[],
$filterFactory,
],
]
);
}
Expand Down
9 changes: 7 additions & 2 deletions tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -543,11 +543,11 @@ public function provideApplyTestData(): array
$filterFactory,
],
'mixed IRI and entity ID values for relations' => [
sprintf('SELECT %s FROM %s %1$s INNER JOIN %1$s.relatedDummies relatedDummies_a1 WHERE %1$s.relatedDummy IN (:relatedDummy_p1, :relatedDummy_p2) AND relatedDummies_a1.id = :relatedDummies_p4', $this->alias, Dummy::class),
sprintf('SELECT %s FROM %s %1$s INNER JOIN %1$s.relatedDummies relatedDummies_a1 WHERE %1$s.relatedDummy IN (:relatedDummy_p1, :relatedDummy_p2) AND relatedDummies_a1.id = :id_p4', $this->alias, Dummy::class),
[
'relatedDummy_p1' => 1,
'relatedDummy_p2' => 2,
'relatedDummies_p4' => 1,
'id_p4' => 1,
],
$filterFactory,
],
Expand All @@ -559,6 +559,11 @@ public function provideApplyTestData(): array
],
$filterFactory,
],
'empty nested property' => [
sprintf('SELECT %s FROM %s %1$s', $this->alias, Dummy::class),
[],
$filterFactory,
],
]
);
}
Expand Down
Loading