I am trying to implement a custom or-filter in API Platform. But for some reason it is not loading. Find below my configuration.
This is my filter:
<?php
namespace AppBundle\Filter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Common\Annotations\AnnotationReader;
final class SearchFilter extends AbstractFilter
{
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
{
if ($property === 'search') {
$this->logger->info('Search for: ' . $value);
} else {
return;
}
$reader = new AnnotationReader();
$annotation = $reader->getClassAnnotation(new \ReflectionClass(new $resourceClass), \AppBundle\Filter\SearchAnnotation::class);
if (!$annotation) {
throw new \HttpInvalidParamException('No Search implemented.');
}
$parameterName = $queryNameGenerator->generateParameterName($property);
$search = [];
$mappedJoins = [];
foreach ($annotation->fields as $field)
{
$joins = explode(".", $field);
for ($lastAlias = 'o', $i = 0, $num = count($joins); $i < $num; $i++) {
$currentAlias = $joins[$i];
if ($i === $num - 1) {
$search[] = "LOWER({$lastAlias}.{$currentAlias}) LIKE LOWER(:{$parameterName})";
} else {
$join = "{$lastAlias}.{$currentAlias}";
if (false === array_search($join, $mappedJoins)) {
$queryBuilder->leftJoin($join, $currentAlias);
$mappedJoins[] = $join;
}
}
$lastAlias = $currentAlias;
}
}
$queryBuilder->andWhere(implode(' OR ', $search));
$queryBuilder->setParameter($parameterName, '%' . $value . '%');
}
/**
* @param string $resourceClass
* @return array
*/
public function getDescription(string $resourceClass): array
{
$reader = new AnnotationReader();
$annotation = $reader->getClassAnnotation(new \ReflectionClass(new $resourceClass), \AppBundle\Filter\SearchAnnotation::class);
$description['search'] = [
'property' => 'search',
'type' => 'string',
'required' => false,
'swagger' => ['description' => 'Filter on ' . implode(', ', $annotation->fields)],
];
return $description;
}
}
In api_filters.yml:
driver.custom_search_filter:
class: 'AppBundle\Filter\SearchFilter'
autowire: true
tags: [ { name: 'api_platform.filter' } ]
In my annotation file:
<?php
namespace AppBundle\Filter;
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Target;
use Doctrine\Common\Annotations\AnnotationException;
/**
* @Annotation
* @Target("CLASS")
*/
final class SearchAnnotation
{
public $fields = [];
/**
* Constructor.
*
* @param array $data Key-value for properties to be defined in this class.
* @throws AnnotationException
*/
public function __construct(array $data)
{
if (!isset($data['value']) || !is_array($data['value'])) {
throw new AnnotationException('Options must be a array of strings.');
}
foreach ($data['value'] as $key => $value) {
if (is_string($value)) {
$this->fields[] = $value;
} else {
throw new AnnotationException('Options must be a array of strings.');
}
}
}
}
And finally in my entity:
/**
* A driver that bring meals from hub to customer.
*
*
* @ApiResource(
* attributes={
* "filters"={"driver.search_filter","driver.custom_search_filter"},
* "denormalization_context"={"groups"={"post_driver"}}
* }
* )
* @Searchable({"firstName"})
*
* @ORM\Entity
* @ORM\Table(name="vendor_driver")
*/
class Driver
{
It is exactly as according to the issue that was reported here: https://github.com/api-platform/core/issues/398
I am not getting any errors, but the filter is simply not working. I am seeing it in Swagger. But when I enter a value in Swagger, the db returns all entities. Its never reaching the filterProperty method.
Does anyone have an idea?
I've just managed to get this working by removing the autowiring, e.g.
my.custom_search_filter:
class: AppBundle\Filter\CustomSearchFilter
arguments:
- '@doctrine'
- '@request_stack'
- '@logger'
tags: [ { name: 'api_platform.filter', id: 'search' } ]
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With