core icon indicating copy to clipboard operation
core copied to clipboard

[Laravel] Support for ExistsFilter

Open cay89 opened this issue 5 months ago • 1 comments

Description
I would like to use the ExistsFilter in Laravel a Laravel project using the JSON:API format. Currently, the ExistsFilter is only implemented under Doctrine ORM, but there is no equivalent under src/Laravel/Eloquent/Filter.

Use Case Filtering a resource collection based on whether a nullable field is present or not, via a JSON:API-compliant request.

Example

Query:

GET /books?filter[optional_field]=true

Model:

#[
    ApiResource(
        operations: [
            new GetCollection(
                name: 'books',
                parameters: [
                    new QueryParameter(
                        key: 'filter[optional_field]',
                        filter: ExistsFilter::class,
                        property: 'optional_field',
                    ),
                    // ...
                    new QueryParameter(key: 'sort', filter: SortFilter::class),
                ],
            ),
            // ...
        ],
    ),
]
class Book extends Model
{
}

Expected Outcome This should allow filtering records where optional_field is not null (when true is passed) or is null (when false is passed), similar to how it's done in the Doctrine ORM implementation.

cay89 avatar Jun 11 '25 08:06 cay89

Can't you use the boolean filter for this ? Or create a custom one its quite accessible looking at our code:

<?php

declare(strict_types=1);

namespace ApiPlatform\Laravel\Eloquent\Filter;

use ApiPlatform\Metadata\JsonSchemaFilterInterface;
use ApiPlatform\Metadata\Parameter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

final class ExistsFilter implements FilterInterface, JsonSchemaFilterInterface
{
    use QueryPropertyTrait;

    private const BOOLEAN_VALUES = [
        'true' => true,
        'false' => false,
        '1' => true,
        '0' => false,
    ];

    /**
     * @param Builder<Model>       $builder
     * @param array<string, mixed> $context
     */
    public function apply(Builder $builder, mixed $values, Parameter $parameter, array $context = []): Builder
    {
        if (!\is_string($values) || !\array_key_exists($values, self::BOOLEAN_VALUES)) {
            return $builder;
        }

        $property = $this->getQueryProperty($parameter);
        $value = self::BOOLEAN_VALUES[$values];

        $whereClause = $value ? 'whereNotNull' : 'whereNull';

        return $builder->{$whereClause}($property);
    }

    public function getSchema(Parameter $parameter): array
    {
        return [
            'type' => 'boolean',
            'description' => sprintf('Filter on the existence of the "%s" property.', $this->getQueryProperty($parameter)),
        ];
    }
}

These are autoconfigured they should be declared in our Provider automatically.

soyuka avatar Jun 13 '25 08:06 soyuka