Search code examples
phpsymfonyapi-platform.com

How can i get only get the resourcer for the logged user in API platform without using custom operations?


i have the entity below in Api Platform and i want to know if there is an idiomatic way to get all of the critical question of the logged user (an normal user logged with the jwt token) without using processor or custom operation.

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Table(name: 'critical_question')]
#[ORM\Index(name: 'fk_criticals_question_user1_idx', columns: ['user_id'])]
#[ORM\Index(name: 'fk_criticals_question_question1_idx', columns: ['question_id'])]
#[ORM\Entity]
class CriticalQuestion
{
    #[ORM\Column(name: 'id', type: 'integer', nullable: false)]
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
    private int $id;

    #[ORM\Column(name: 'correct_times', type: 'integer', nullable: false)]
    private int $correctTimes;

    #[ORM\ManyToOne(targetEntity: Question::class)]
    #[ORM\JoinColumn(name: 'question_id', referencedColumnName: 'id')]
    #[ORM\JoinColumn(name: 'question_id', referencedColumnName: 'id')]
    private Question $question;

    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
    private User $user;

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

    /**
     * @param int $id
     */
    public function setId(int $id): void
    {
        $this->id = $id;
    }

    /**
     * @return Question
     */
    public function getQuestion(): Question
    {
        return $this->question;
    }

    /**
     * @param Question $question
     */
    public function setQuestion(Question $question): void
    {
        $this->question = $question;
    }

    /**
     * @return int
     */
    public function getCorrectTimes(): int
    {
        return $this->correctTimes;
    }

}

I just want to know if there is a simple way to do it, because i used it for speed up the process of building API but for most of the use case that i have in my application i use custom operation with custom repositories, or in some cases i used processor.

Unfortunately the documentation is not that well explaining topics, or maybe it's just my problem.


Solution

  • In one of my projects, we use QueryCollectionExtensionInterface and QueryItemExtensionInterface for this to do the filtering on Doctrine level. Example code (untested, without any guarantee):

    use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
    use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
    use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
    use ApiPlatform\Metadata\Operation;
    use Doctrine\ORM\QueryBuilder;
    use Symfony\Bundle\SecurityBundle\Security;
    
    class FilterForCurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
    {
        public function __construct(protected Security $security)
        {
        }
    
        public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
        {
            $this->addWhere($queryBuilder, $resourceClass);
        }
    
        /**
         * @param mixed[] $identifiers
         * @param mixed[] $context
         */
        public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, ?Operation $operation = null, array $context = []): void
        {
            $this->addWhere($queryBuilder, $resourceClass);
        }
    
        protected function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
        {
            $user = $this->security->getUser();
    
            $rootAlias = $queryBuilder->getRootAliases()[0];
            $queryBuilder->andWhere(sprintf('%s.user = :current_user', $rootAlias));
            $queryBuilder->setParameter('current_user', $user->getId());
        }
    }