-
-
Save teohhanhui/6d77c2ef4cbdde7ecbee9b314ad27281 to your computer and use it in GitHub Desktop.
<?php | |
namespace App\Filter; | |
use ApiPlatform\Core\Api\IriConverterInterface; | |
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter; | |
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface; | |
use Doctrine\Common\Persistence\ManagerRegistry; | |
use Doctrine\ORM\QueryBuilder; | |
use Psr\Log\LoggerInterface; | |
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; | |
/** | |
* Filters the collection by match, using a property alias. | |
*/ | |
class PropertyAliasSearchFilter extends SearchFilter | |
{ | |
private $aliasedProperties; | |
public function __construct(ManagerRegistry $managerRegistry, array $properties, IriConverterInterface $iriConverter, PropertyAccessorInterface $propertyAccessor = null, LoggerInterface $logger = null) | |
{ | |
$this->aliasedProperties = $properties; | |
$properties = []; | |
foreach ($this->aliasedProperties as $property => $propertyOptions) { | |
$properties[$propertyOptions['propertyName']] = $propertyOptions['strategy']; | |
} | |
parent::__construct($managerRegistry, null, $iriConverter, $propertyAccessor, $logger, $properties); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getDescription(string $resourceClass): array | |
{ | |
$description = []; | |
$properties = $this->aliasedProperties; | |
foreach ($properties as $property => $propertyOptions) { | |
$description[$property] = [ | |
'property' => $propertyOptions['propertyName'], | |
'type' => 'string', | |
'required' => false, | |
'strategy' => $propertyOptions['strategy'], | |
]; | |
} | |
return $description; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null) | |
{ | |
if (!isset($this->aliasedProperties[$property])) { | |
return; | |
} | |
$property = $this->aliasedProperties[$property]['propertyName']; | |
parent::filterProperty($property, $value, $queryBuilder, $queryNameGenerator, $resourceClass, $operationName); | |
} | |
} |
Thank you for your help teoh, I will watch closely any of you update :)
Ok I see, like @byhoratiss said the thing is you have to register 1 service per propertyName that you want to filter and thus makes a lot of configuration.
We finally took his solution even if the code is bigger to maintain because the piped possibilites did exacltly what we intented to do (aka making annoying old filters for and old UI that offers possibilities like 'starts with', 'contains' ...).
the thing is you have to register 1 service per propertyName that you want to filter and thus makes a lot of configuration
That's entirely incorrect.
The service configuration example from @byhoratiss has a mistake. You need to pass them nested as the $properties
argument.
@byhoratiss Your solution is not maintainable because you are duplicating the code from SearchFilter
.
@teohhanhui I know I'm duplicating code from parent class, because the method "filterProperty" does not have a parameter for Strategy, neither a "Configuration" object.
When the parent class filter allow me to set the strategy I will rewrite my implementation.
Hello,
much simpler !!!
?page=1&firstname[exact]=mick
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
class SearchStrategyFilter extends SearchFilter
{
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
{
if (!is_array($value)) {
return;
}
$first = array_key_first($value);
if (!in_array($first, [
self::STRATEGY_EXACT,
self::STRATEGY_PARTIAL,
self::STRATEGY_START,
self::STRATEGY_END,
self::STRATEGY_WORD_START,
])) {
return;
}
$this->properties = [$property => $first];
$value = $value[$first];
parent::filterProperty($property, $value, $queryBuilder, $queryNameGenerator, $resourceClass, $operationName);
}
}
(Don't use the
PropertyAliasSearchFilter
when you don't need to.)Perhaps I'll write another version which allows the client to choose the strategy (from a whitelist). That should feel more natural.