Skip to content

Instantly share code, notes, and snippets.

@tezvi
Last active September 4, 2024 11:51
Show Gist options
  • Save tezvi/d0974664a423a3052518bfb47bac672c to your computer and use it in GitHub Desktop.
Save tezvi/d0974664a423a3052518bfb47bac672c to your computer and use it in GitHub Desktop.
Prevent duplicate SQL order when combining ApiPlatform default resource order and order filters
<?php
/**
* @author Andrej Vitez <[email protected]>
* @licence MIT
*/
declare(strict_types=1);
namespace Acme\ApiPlatform\Extension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\OrderExtension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
/**
* Class DefaultOrderExtension
*
* This extension is used to prevent applying of default SQL order if order filters are already being applied.
* This class is potential solution to https://github.com/api-platform/core/issues/2690.
*/
final class DefaultOrderExtensionDecorator implements ContextAwareQueryCollectionExtensionInterface
{
/**
* @var OrderExtension
*/
private $decorated;
/**
* @var string
*/
private $orderParameterName;
/**
* DefaultOrderExtension constructor.
*
* @param OrderExtension $decorated
* @param string $orderParameterName
*/
public function __construct(OrderExtension $decorated, string $orderParameterName)
{
$this->decorated = $decorated;
$this->orderParameterName = $orderParameterName;
}
/**
* @inheritDoc
*/
public function applyToCollection(
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
string $operationName = null,
array $context = []
) {
// Ignore default resource order if query filters are defined.
if (isset($context['filters'][$this->orderParameterName])) {
return;
}
$this->decorated->applyToCollection(
$queryBuilder,
$queryNameGenerator,
$resourceClass,
$operationName,
$context
);
}
}
# Defines the decorator service
Acme\ApiPlatform\Extension\DefaultOrderExtensionDecorator:
decorates: api_platform.doctrine.orm.query_extension.order
arguments:
$decorated: '@Acme\ApiPlatform\Extension\DefaultOrderExtensionDecorator.inner'
$orderParameterName: '%api_platform.collection.order_parameter_name%'
@cetver
Copy link

cetver commented Dec 3, 2020

// replace
if (isset($context['filters'][$this->orderParameterName])) {
   return;
}
// with
$filters = $context['filters'] ?? [];
$orderFilters = (array) ($filters[$this->orderParameterName] ?? []);
$sanitizedOrderFilters = array_filter($orderFilters);
if (!empty($sanitizedOrderFilters)) {
    return;
}

For the invalid order values like

  • ?order=
  • ?order[]=
  • ?order[1]=&order[2]=

To applying the default order

@tezvi
Copy link
Author

tezvi commented Sep 22, 2021

// replace
if (isset($context['filters'][$this->orderParameterName])) {
   return;
}
// with
$filters = $context['filters'] ?? [];
$orderFilters = (array) ($filters[$this->orderParameterName] ?? []);
$sanitizedOrderFilters = array_filter($orderFilters);
if (!empty($sanitizedOrderFilters)) {
    return;
}

For the invalid order values like

  • ?order=
  • ?order[]=
  • ?order[1]=&order[2]=

To applying the default order

Thanks for contribution! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment