Skip to content
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
9 changes: 9 additions & 0 deletions src/Doctrine/Common/Filter/PropertyAwareFilterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
namespace ApiPlatform\Doctrine\Common\Filter;

/**
* TODO: 5.x uncomment method.
*
* @author Antoine Bluchet <soyuka@gmail.com>
*
* @method ?array getProperties()
*
* @experimental
*/
interface PropertyAwareFilterInterface
Expand All @@ -24,4 +28,9 @@ interface PropertyAwareFilterInterface
* @param string[] $properties
*/
public function setProperties(array $properties): void;

// /**
// * @return string[]
// */
// public function getProperties(): ?array;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,6 @@ trait PropertyPlaceholderOpenApiParameterTrait
*/
public function getOpenApiParameters(Parameter $parameter): ?array
{
if (str_contains($parameter->getKey(), ':property')) {
$parameters = [];
$key = str_replace('[:property]', '', $parameter->getKey());
foreach (array_keys($parameter->getExtraProperties()['_properties'] ?? []) as $property) {
$parameters[] = new OpenApiParameter(name: \sprintf('%s[%s]', $key, $property), in: 'query');
}

return $parameters;
}

return null;
return [new OpenApiParameter(name: $parameter->getKey(), in: 'query')];
}
}
63 changes: 63 additions & 0 deletions src/Doctrine/Common/ParameterExtensionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Doctrine\Common;

use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface;
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
use ApiPlatform\Metadata\Parameter;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

trait ParameterExtensionTrait
{
use ParameterValueExtractorTrait;

protected ContainerInterface $filterLocator;
protected ?ManagerRegistry $managerRegistry = null;
protected ?LoggerInterface $logger = null;

/**
* @param object $filter the filter instance to configure
* @param Parameter $parameter the operation parameter associated with the filter
*/
private function configureFilter(object $filter, Parameter $parameter): void
{
if ($this->managerRegistry && $filter instanceof ManagerRegistryAwareInterface && !$filter->hasManagerRegistry()) {
$filter->setManagerRegistry($this->managerRegistry);
}

if ($this->logger && $filter instanceof LoggerAwareInterface && !$filter->hasLogger()) {
$filter->setLogger($this->logger);
}

if ($filter instanceof PropertyAwareFilterInterface) {
$properties = [];
// Check if the filter has getProperties method (e.g., if it's an AbstractFilter)
if (method_exists($filter, 'getProperties')) { // @phpstan-ignore-line todo 5.x remove this check @see interface
$properties = $filter->getProperties() ?? [];
}

$propertyKey = $parameter->getProperty() ?? $parameter->getKey();
foreach ($parameter->getProperties() ?? [$propertyKey] as $property) {
if (!isset($properties[$property])) {
$properties[$property] = $parameter->getFilterContext();
}
}

$filter->setProperties($properties);
}
}
}
5 changes: 1 addition & 4 deletions src/Doctrine/Common/ParameterValueExtractorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ trait ParameterValueExtractorTrait
private function extractParameterValue(Parameter $parameter, mixed $value): array
{
$key = $parameter->getProperty() ?? $parameter->getKey();
if (!str_contains($key, ':property')) {
return [$key => $value];
}

return [str_replace('[:property]', '', $key) => $value];
return [$key => $value];
}
}
42 changes: 11 additions & 31 deletions src/Doctrine/Odm/Extension/ParameterExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@

namespace ApiPlatform\Doctrine\Odm\Extension;

use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface;
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
use ApiPlatform\Doctrine\Common\ParameterValueExtractorTrait;
use ApiPlatform\Doctrine\Odm\Filter\AbstractFilter;
use ApiPlatform\Doctrine\Odm\Filter\FilterInterface;
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
use ApiPlatform\Doctrine\Common\ParameterExtensionTrait;
use ApiPlatform\Doctrine\Odm\Filter\FilterInterface; // Explicitly import PropertyAwareFilterInterface
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ParameterNotFound;
use Doctrine\Bundle\MongoDBBundle\ManagerRegistry;
Expand All @@ -32,13 +30,16 @@
*/
final class ParameterExtension implements AggregationCollectionExtensionInterface, AggregationItemExtensionInterface
{
use ParameterValueExtractorTrait;
use ParameterExtensionTrait;

public function __construct(
private readonly ContainerInterface $filterLocator,
private readonly ?ManagerRegistry $managerRegistry = null,
private readonly ?LoggerInterface $logger = null,
ContainerInterface $filterLocator,
?ManagerRegistry $managerRegistry = null,
?LoggerInterface $logger = null,
) {
$this->filterLocator = $filterLocator;
$this->managerRegistry = $managerRegistry;
$this->logger = $logger;
}

/**
Expand Down Expand Up @@ -66,28 +67,7 @@ private function applyFilter(Builder $aggregationBuilder, ?string $resourceClass
continue;
}

if ($this->managerRegistry && $filter instanceof ManagerRegistryAwareInterface && !$filter->hasManagerRegistry()) {
$filter->setManagerRegistry($this->managerRegistry);
}

if ($this->logger && $filter instanceof LoggerAwareInterface && !$filter->hasLogger()) {
$filter->setLogger($this->logger);
}

if ($filter instanceof AbstractFilter && !$filter->getProperties()) {
$propertyKey = $parameter->getProperty() ?? $parameter->getKey();

if (str_contains($propertyKey, ':property')) {
$extraProperties = $parameter->getExtraProperties()['_properties'] ?? [];
foreach (array_keys($extraProperties) as $property) {
$properties[$property] = $parameter->getFilterContext();
}
} else {
$properties = [$propertyKey => $parameter->getFilterContext()];
}

$filter->setProperties($properties ?? []);
}
$this->configureFilter($filter, $parameter);

$context['filters'] = $values;
$context['parameter'] = $parameter;
Expand Down
2 changes: 1 addition & 1 deletion src/Doctrine/Odm/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
],
"require": {
"php": ">=8.2",
"api-platform/doctrine-common": "^4.2",
"api-platform/doctrine-common": "^4.2.9",
"api-platform/metadata": "^4.2",
"api-platform/state": "^4.2.4",
"doctrine/mongodb-odm": "^2.10",
Expand Down
42 changes: 9 additions & 33 deletions src/Doctrine/Orm/Extension/ParameterExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@

namespace ApiPlatform\Doctrine\Orm\Extension;

use ApiPlatform\Doctrine\Common\Filter\LoggerAwareInterface;
use ApiPlatform\Doctrine\Common\Filter\ManagerRegistryAwareInterface;
use ApiPlatform\Doctrine\Common\Filter\PropertyAwareFilterInterface;
use ApiPlatform\Doctrine\Common\ParameterValueExtractorTrait;
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Doctrine\Common\ParameterExtensionTrait;
use ApiPlatform\Doctrine\Orm\Filter\FilterInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
Expand All @@ -34,13 +30,16 @@
*/
final class ParameterExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
use ParameterValueExtractorTrait;
use ParameterExtensionTrait;

public function __construct(
private readonly ContainerInterface $filterLocator,
private readonly ?ManagerRegistry $managerRegistry = null,
private readonly ?LoggerInterface $logger = null,
ContainerInterface $filterLocator,
?ManagerRegistry $managerRegistry = null,
?LoggerInterface $logger = null,
) {
$this->filterLocator = $filterLocator;
$this->managerRegistry = $managerRegistry;
$this->logger = $logger;
}

/**
Expand Down Expand Up @@ -68,30 +67,7 @@ private function applyFilter(QueryBuilder $queryBuilder, QueryNameGeneratorInter
continue;
}

if ($this->managerRegistry && $filter instanceof ManagerRegistryAwareInterface && !$filter->hasManagerRegistry()) {
$filter->setManagerRegistry($this->managerRegistry);
}

if ($this->logger && $filter instanceof LoggerAwareInterface && !$filter->hasLogger()) {
$filter->setLogger($this->logger);
}

if ($filter instanceof PropertyAwareFilterInterface) {
$properties = [];
$propertyKey = $parameter->getProperty() ?? $parameter->getKey();
if ($filter instanceof AbstractFilter) {
$properties = $filter->getProperties() ?? [];

if (str_contains($propertyKey, ':property')) {
$extraProperties = $parameter->getExtraProperties()['_properties'] ?? [];
foreach (array_keys($extraProperties) as $property) {
$properties[$property] = $parameter->getFilterContext();
}
}
}

$filter->setProperties($properties + [$propertyKey => $parameter->getFilterContext()]);
}
$this->configureFilter($filter, $parameter);

$filter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operation,
['filters' => $values, 'parameter' => $parameter] + $context
Expand Down
2 changes: 1 addition & 1 deletion src/Doctrine/Orm/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
],
"require": {
"php": ">=8.2",
"api-platform/doctrine-common": "^4.2.0-alpha.3@alpha",
"api-platform/doctrine-common": "^4.2.9",
"api-platform/metadata": "^4.2",
"api-platform/state": "^4.2.4",
"doctrine/orm": "^2.17 || ^3.0"
Expand Down
87 changes: 48 additions & 39 deletions src/GraphQl/Type/FieldsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\GraphQl\Subscription;
use ApiPlatform\Metadata\InflectorInterface;
use ApiPlatform\Metadata\OpenApiParameterFilterInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
Expand Down Expand Up @@ -356,6 +355,8 @@ private function parameterToObjectType(array $flattenFields, string $name): Inpu
if (isset($fields[$key])) {
if ($type instanceof ListOfType) {
$key .= '_list';
} elseif ($fields[$key]['type'] instanceof InputObjectType && !$type instanceof InputObjectType) {
continue;
}
}

Expand Down Expand Up @@ -497,56 +498,64 @@ private function getResourceFieldConfiguration(?string $property, ?string $field
*/
private function getParameterArgs(Operation $operation, array $args = []): array
{
$groups = [];

foreach ($operation->getParameters() ?? [] as $parameter) {
$key = $parameter->getKey();

if (!str_contains($key, ':property')) {
$args[$key] = ['type' => GraphQLType::string()];

if ($parameter->getRequired()) {
$args[$key]['type'] = GraphQLType::nonNull($args[$key]['type']);
if (str_contains($key, '[')) {
$key = str_replace('.', $this->nestingSeparator, $key);
parse_str($key, $values);
$rootKey = key($values);

$leafs = $values[$rootKey];
$name = key($leafs);

$filterLeafs = [];
if (($filterId = $parameter->getFilter()) && $this->filterLocator->has($filterId)) {
$filter = $this->filterLocator->get($filterId);

if ($filter instanceof FilterInterface) {
$property = $parameter->getProperty() ?? $name;
$property = str_replace('.', $this->nestingSeparator, $property);
$description = $filter->getDescription($operation->getClass());

foreach ($description as $descKey => $descValue) {
$descKey = str_replace('.', $this->nestingSeparator, $descKey);
parse_str($descKey, $descValues);
if (isset($descValues[$property]) && \is_array($descValues[$property])) {
$filterLeafs = array_merge($filterLeafs, $descValues[$property]);
}
}
}
}

continue;
}
if ($filterLeafs) {
$leafs[$name] = $filterLeafs;
}

if (!($filterId = $parameter->getFilter()) || !$this->filterLocator->has($filterId)) {
$groups[$rootKey][] = [
'name' => $name,
'leafs' => $leafs[$name],
'required' => $parameter->getRequired(),
'description' => $parameter->getDescription(),
'type' => 'string',
];
continue;
}

$filter = $this->filterLocator->get($filterId);
$parsedKey = explode('[:property]', $key);
$flattenFields = [];
$args[$key] = ['type' => GraphQLType::string()];

if ($filter instanceof FilterInterface) {
foreach ($filter->getDescription($operation->getClass()) as $name => $value) {
$values = [];
parse_str($name, $values);
if (isset($values[$parsedKey[0]])) {
$values = $values[$parsedKey[0]];
}

$name = key($values);
$flattenFields[] = ['name' => $name, 'required' => $value['required'] ?? null, 'description' => $value['description'] ?? null, 'leafs' => $values[$name], 'type' => $value['type'] ?? 'string'];
}

$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0]);
if ($parameter->getRequired()) {
$args[$key]['type'] = GraphQLType::nonNull($args[$key]['type']);
}
}

if ($filter instanceof OpenApiParameterFilterInterface) {
foreach ($filter->getOpenApiParameters($parameter) as $value) {
$values = [];
parse_str($value->getName(), $values);
if (isset($values[$parsedKey[0]])) {
$values = $values[$parsedKey[0]];
}

$name = key($values);
$flattenFields[] = ['name' => $name, 'required' => $value->getRequired(), 'description' => $value->getDescription(), 'leafs' => $values[$name], 'type' => $value->getSchema()['type'] ?? 'string'];
}

$args[$parsedKey[0]] = $this->parameterToObjectType($flattenFields, $parsedKey[0].$operation->getShortName().$operation->getName());
}
foreach ($groups as $key => $flattenFields) {
$name = $key.$operation->getShortName().$operation->getName();
$inputObject = $this->parameterToObjectType($flattenFields, $name);
$this->typesContainer->set($name, $inputObject);
$args[$key] = $inputObject;
}

return $args;
Expand Down
Loading
Loading