Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ApiFilter overloads filters #6770

Open
Tarac21 opened this issue Nov 2, 2024 · 1 comment
Open

ApiFilter overloads filters #6770

Tarac21 opened this issue Nov 2, 2024 · 1 comment

Comments

@Tarac21
Copy link

Tarac21 commented Nov 2, 2024

API Platform version(s) affected: 4.0.6

Description
The ApiFilter attribute takes over my empty "filters" for my post counter.

How to reproduce

<?php

namespace App\Entity;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post as ApiPlatformPost;
use ApiPlatform\Metadata\Put;
use ApiPlatform\OpenApi\Model\MediaType;
use ApiPlatform\OpenApi\Model;
use ApiPlatform\OpenApi\Model\RequestBody;
use ApiPlatform\OpenApi\Model\Schema;
use App\Controller\PostCountController;
use App\Repository\PostRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\Valid;
use App\Controller\PostPublishController;

#[ORM\Entity(repositoryClass: PostRepository::class)]
#[ApiResource(
    operations: [
        new GetCollection(
            uriTemplate: '/posts/count',
            controller: PostCountController::class,
            openapi: new Model\Operation(
                responses: [
                    '200' => [
                        'description' => 'OK',
                        'content' => [
                            'application/json' => [
                                'schema' => [
                                    'type' => 'integer',
                                    'example' => 3,
                                ]
                            ]
                        ]
                    ]
                ],
                summary: 'Retrieves the total number of posts',
                parameters: [
                    new Model\Parameter(
                        name: 'online',
                        in: 'query',
                        description: 'Filter online posts',
                        required: false,
                        schema: [
                            'type' => 'integer',
                            'maximum' => 1,
                            'minimum' => 0
                        ]
                    )
                ]
            ),
            paginationEnabled: false,
            filters: [],
            read: false
        ),
        new Put(),
        new Patch(),
        new Delete(),
        new GetCollection(),
        new ApiPlatformPost(),
        new Get(
            uriTemplate: '/posts/{id}',
            normalizationContext: [
                'groups' => ['read:collection', 'read:item', 'read:Post'],
                'openapi_definition_name' => 'Detail'
            ]),
        new ApiPlatformPost(
            uriTemplate: '/posts/{id}/publish',
            controller: PostPublishController::class,
            openapi: new Model\Operation(
                summary: 'Allows to publish an post',
                requestBody: new Model\RequestBody(
                    content: new \ArrayObject([
                        'application/json' => [
                            'schema' => [
                                'type' => 'object',
                                'properties' => []
                            ]
                        ]
                    ])
                )
            ),
            name: 'publish'
        )
    ],
    normalizationContext: [
        'groups' => ['read:collection'],
        'openapi_definition_name' => 'Collection'
    ],
    denormalizationContext: ['groups' => ['write:Post']],
    paginationClientItemsPerPage: true,
    paginationItemsPerPage: 2,
    paginationMaximumItemsPerPage: 2,
)]
#[ApiFilter(SearchFilter::class, properties: ['id' => 'exact', 'title' => 'partial'])]
class Post
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    #[Groups(['read:collection'])]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[
        Groups(['read:collection', 'write:Post']),
        Length(min:5, groups: ['create:Post'])
    ]
    private ?string $title = null;

    #[ORM\Column(length: 255)]
    #[Groups(['read:collection', 'write:Post'])]
    private ?string $slug = null;

    #[ORM\Column(type: Types::TEXT)]
    #[Groups(['read:item', 'write:Post'])]
    private ?string $content = null;

    #[ORM\Column]
    #[Groups(['read:item'])]
    private ?\DateTimeImmutable $createdAt = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $updatedAt = null;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'posts')]
    #[
        Groups(['read:item', 'write:Post']),
        Valid()
    ]
    private ?Category $category = null;

    #[ORM\Column(type:"boolean", options: ["default" => "0"])]
    #[
        Groups(['read:collection']),
        ApiProperty(openapiContext: ['type' => 'boolean', 'description' => 'Online or not?'])
    ]
    private ?bool $online = false;

    public function __construct()
    {
        $this->createdAt = new \DateTimeImmutable();
        $this->updatedAt = new \DateTimeImmutable();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): static
    {
        $this->title = $title;

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): static
    {
        $this->slug = $slug;

        return $this;
    }

    public function getContent(): ?string
    {
        return $this->content;
    }

    public function setContent(string $content): static
    {
        $this->content = $content;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\DateTimeImmutable $createdAt): static
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeImmutable
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(\DateTimeImmutable $updatedAt): static
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): static
    {
        $this->category = $category;

        return $this;
    }

    public function isOnline(): ?bool
    {
        return $this->online;
    }

    public function setOnline(bool $online): static
    {
        $this->online = $online;

        return $this;
    }
}
<?php

namespace App\Controller;

use App\Repository\PostRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Serializer\SerializerInterface;

#[AsController]
class PostCountController extends AbstractController
{
    public function __construct(private PostRepository $postRepository) {

    }

    public function __invoke(Request $request, SerializerInterface $serializer): JsonResponse
    {
        $onlineQuery = $request->get('online');
        $conditions = [];

        if($onlineQuery !== null) {
            $conditions['online'] = $onlineQuery === '1' ? true : false;
        }

        $count = $this->postRepository->count($conditions);

        $jsonContent = $serializer->serialize($count, 'json', ['groups' => ['read:collection', 'read:item']]);

        return new JsonResponse($jsonContent, JsonResponse::HTTP_OK, [], true);
    }
}

Possible Solution
/

Additional Context
/

@mrossard
Copy link
Contributor

mrossard commented Nov 5, 2024

AFAIK the filters option on the operation can only add filters, not remove the filters defined with #ApiFilter().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants