phprestsymfonyapi-platform.comsymfony5

custom path to get all the subressource of an entity


I'm new with Api-platform 2.6 and i kind of succeeded to do what i attempted but i don't know if it's the "right" or easiest way to do it.

Here's what i'm trying to do:

i got an esirius_site entity that that have a collection of visitors.

The visitors are not stored in the database but they are fetched from an api endpoint.

I want to have a route like : /esirius_sites/{idsys}/visitors that return a collection of visitors (see result bellow). I don't want the route to return a esirius_site


Solution

  • i succeeded to do it by setting the visitors as a sub-resource:

    <?php
    
    /**
     * @ORM\Entity(repositoryClass=EsiriusSiteRepository::class)
     * @ApiResource(
     *     collectionOperations={
     *     },
     *     itemOperations={
     *              "get",
     *
     *          }
     *     )
     */
    class EsiriusSite
    {
    
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         */
        private $idsys;
    
       /** Other properties... **/
    
        /**
         * @ApiSubresource()
         */
        private $visitors;
    
        public function __construct()
        {
            $this->visitors = [];
        }
    
    
        public function getIdsys(): ?int
        {
            return $this->idsys;
        }
      
        /**
         * @return array
         */
        public function getVisitors():array
        {
            return $this->visitors;
        }
    
        public function addVisitor(Visitor $visitor): self
        {
            $this->visitors[]=$visitor;
            $visitor->setEsiriusSite($this);
            return $this;
        }
    }
    

    and then i created a Data provider to fetch the visitor collection :

    <?php
    
    namespace App\DataProvider;
    
    class VisitorItemDataProvider implements SubresourceDataProviderInterface,RestrictedDataProviderInterface
    {
        private EsiriusVisitorWebService $visitorWebService;
        private EsiriusSiteRepository $siteRepository;
    
        public function __construct(EsiriusVisitorWebService $visitorWebService, EsiriusSiteRepository $siteRepository)
        {
            $this->visitorWebService = $visitorWebService;
            $this->siteRepository = $siteRepository;
        }
    
        public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
        {
            return $resourceClass === Visitor::class;
        }
    
    
        public function getSubresource(string $resourceClass, array $identifiers, array $context, string $operationName = null)
        {
            $site = $this->siteRepository->find($identifiers["idsys"]["idsys"]);
            $esiriusVisitors = ($this->visitorWebService->getVisitors([$site->getCode()]))->visitorArray;
            if($esiriusVisitors== new \stdClass())
                return [];
    
            foreach ($esiriusVisitors as $visitor) {
                $newVisitor = (new Visitor())->setFirstName($visitor->firstName)->setLastname($visitor->name)->setId($visitor->businessIdentity);
                $site->addVisitor($newVisitor);
            }
            return $site->getVisitors();
        }
    }
    

    In this data provider i use the SubresourceDataProviderInterface (i found it randomly) that's not mentioned in the api platform documentation.

    I finally got the result that i espect:

    {
        "@context": "/q0met-api/contexts/Visitor",
        "@id": "/q0met-api/esirius_sites/18/visitors",
        "@type": "hydra:Collection",
        "hydra:member": [
            {
                "@id": "/q0met-api/visitors/1234",
                "@type": "Visitor",
                "id": "1234",
                "firstName": "Jean",
                "lastname": "Michel",
                "esiriusSite": "/q0met-api/esirius_sites/18"
            }
        ],
        "hydra:totalItems": 1
    }