api-platform / api-platform

🕸️ Create REST and GraphQL APIs, scaffold Jamstack webapps, stream changes in real-time.
https://api-platform.com
MIT License
8.56k stars 960 forks source link

Filter embedded entity with Extention #1659

Open dkruchok opened 4 years ago

dkruchok commented 4 years ago

Is there a way to implement an “auto filter” for nested collections?

I have Extensions that getting the collections for the current user according to this doc For example, I have extensions for Category and Product entities. It works great if I call the entity directly like /api/category or /api/products

But the nested relations that show the under categories => products are not related to the current user And I want to have the additional condition for product status.

"hydra:member": [
    {
      "@id": "/api/categories/4",
      "@type": "Category",
      "id": "4",
      "title": "Title",
      "userId": 1,
      "products": [
        {
          "@id": "/api/products/3",
          "@type": "Product",
          "id": 3,
          "userId": 1,
          "status": true
       },
        {
          "@id": "/api/products/4",
          "@type": "Product",
          "id": 4,
          "userId": 1,
          "status": false <== should be not visible 
       },
        {
          "@id": "/api/products/5",
          "@type": "Product",
          "id": 5,
          "userId": 2, <== wrong userId
          "status": false
       }
    ]
}

For some reason /api/categories?products.status=true doesn’t work. But anyhow I want to filter this without the parameters.

For example extension of the category How I can add conditions for the related Products? Thanks =)

if (
(
    Category::class !== $resourceClass) ||
    $this->security->isGranted('ROLE_ADMIN') || null === $user = $this->security->getUser()) {
    return;
}

$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere(sprintf('%s.userId = :user', $rootAlias));
$queryBuilder->setParameter('user', $user->getId());
Spomsoree commented 1 year ago

I've got the same issue. This did work in recent versions.

In recent versions the related entity, products in the example above, also needed a item get route to be returned, that seems to have changed, but I cannot find any documentation on this.

Thats my example:

SchoolClass.php

#[ORM\Entity(
    repositoryClass: SchoolClassRepository::class
)]
#[ORM\Table(
    name: 'school_class'
)]
#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
    ],
)]
class SchoolClass
{
    /**
     * @param string $name
     * @param Collection  $students
     */
    public function __construct(
        /**
         * @var string The name of this school class.
         */
        #[ORM\Column(
            type: 'string'
        )]
        #[Groups([
            'school_class_get',
        ])]
        protected string $name = '',
        /**
         * @var Collection|ArrayCollection|<Student> The students linked to this school class.
         */
        #[ORM\OneToMany(
            mappedBy: 'schoolClass',
            targetEntity: Student::class,
            cascade: ['persist'],
            orphanRemoval: true
        )]
        #[Groups([
            'school_class_get',
        ])]
        protected Collection $students = new ArrayCollection(),
...

Student.php

#[ORM\Entity(
    repositoryClass: StudentRepository::class
)]
#[ORM\Table(
    name: 'student'
)]
#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
    ],
)]
class Student
{
    /**
     * @param string $name
     * @param bool $enabled
     */
    public function __construct(
        /**
         * @var string The name of this student.
         */
        #[ORM\Column(
            type: 'string'
        )]
        #[Groups([
            'student_get',
            'school_class_get',
        ])]
        protected string $name = '',
        /**
         * @var bool Determine if this student is active.
         */
        #[ORM\Column(
            type: 'boolean',
            options: [
                'default' => false,
            ],
        )]
        #[Groups([
            'student_get',
            'school_class_get',
        ])]
        protected bool $enabled = false,
...

StudentExtension.php

...
        $applicationProperties->getQueryBuilder()
            ->andWhere(sprintf('%s.enabled = :enabled', $applicationProperties->getRootAlias()))
            ->setParameter('enabled', true);
...

The student-API will return only enabled students. The schoolClass-API will return all students.