0

私は実際に以下に基づいてAPIを構築しています:

  • symfony/フレックス: v1.0.61
  • symfony: v4.0.3
  • API プラットフォーム/API パック: v1.0.1
  • API プラットフォーム/コア: v2.1.4

CRUD 操作は簡単に実装できました。それにもかかわらず、 カスタム操作は単純ではないようです。

App\Entity\Product実装しようとしているカスタム操作は、指定された に基づいて を返すだけ$slugです。

  • ルートは次のとおりです。/api/products/by-slugs/{slug}
  • メソッドは次のとおりです。GET
  • 操作タイプは次のとおりです。itemOperations

これは物事が行われている方法です:

Product リソースの宣言

<?php
// src/Entity/Product
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;


/**
 * @ORM\Entity
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 * @ApiResource(attributes={"pagination_client_items_per_page"=true,
 *                          "filters"={"product.search"}
 *                         },
 *              collectionOperations={
 *                      "get"={
 *                      "method"="GET",
 *                      "normalization_context"={"groups"={"product_gets"}} },
 *                      "post"={
 *                      "method"="POST",
 *                      "denormalization_context"={"groups"={"product_post"}} }
 *              },
 *              itemOperations={
 *                      "get"={
 *                      "method"="GET",
 *                      "normalization_context"={"groups"={"product_get"}} },
 *                      "put"={
 *                      "method"="PUT",
 *                      "denormalization_context"={"groups"={"product_put"}} },
 *                      "delete"={
 *                      "method"="DELETE"},
 *                      "product_slug"={"route_name"="route_product_slug"}
 *              })
 * @ORM\HasLifecycleCallbacks()
 */

class Product{
}

ProductLoader の宣言

<?php

namespace App\Loader;

use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Psr\Cache\CacheItemPoolInterface;

class ProductLoader {
    private $em;
    private $logger;
    private $cache;

    public function __construct(
        EntityManagerInterface $em,
        LoggerInterface $logger,
        CacheItemPoolInterface $cache){
        $this->em = $em;
        $this->logger = $logger;
        $this->cache = $cache;
    }

    public function findBySlug($slug){
        return $this->em->getRepository(Product::class)->findProductBySlug($slug);
    }
}

ProductRepository の宣言

<?php

namespace App\Repository;

use Doctrine\ORM\EntityRepository;

/**
 * ProductRepository
 */
class ProductRepository extends EntityRepository {

    public function findProductBySlug($slug) {
        $qb = $this->createQueryBuilder("b")
                ->where("b.slug = :slug")
                ->setParameter('slug', $slug);
        return $qb->getQuery()->getOneOrNullResult();
    }

}

Symfony コントローラーでのカスタム操作の宣言

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;

use App\Loader\ProductLoader;
use App\Entity\Product;

class ProductController extends Controller
{

    /**
     * @Route(
     *     name="route_product_slug",
     *     path="/api/products/by-slug/{slug}",
     *     defaults={"_api_resource_class"=Product::class,
     *               "_api_item_operation_name"="product_slug"
     *     }
     * )
     * @Method("GET")
     */
     public function productsGetBySlugAction(ProductLoader $productLoader, $slug){
        return $productLoader->findBySlug($slug);
     }
}

以下のコマンドをすばやく実行すると、次のものが返されました。

bin/console debug:router
 --------------------------------------- -------- -------- ------ --------------------------------------- 
  Name                                    Method   Scheme   Host   Path                                   
 --------------------------------------- -------- -------- ------ --------------------------------------- 
  app_product_products                    ANY      ANY      ANY    /                                      
  route_product_slug                      GET      ANY      ANY    /api/products/by-slug/{slug}           
  api_entrypoint                          ANY      ANY      ANY    /api/{index}.{_format}                 
  api_doc                                 ANY      ANY      ANY    /api/docs.{_format}                    
  api_jsonld_context                      ANY      ANY      ANY    /api/contexts/{shortName}.{_format}    
  api_products_get_collection             GET      ANY      ANY    /api/products.{_format}                
  api_products_post_collection            POST     ANY      ANY    /api/products.{_format}                
  api_products_get_item                   GET      ANY      ANY    /api/products/{id}.{_format}           
  api_products_put_item                   PUT      ANY      ANY    /api/products/{id}.{_format}           
  api_products_delete_item                DELETE   ANY      ANY    /api/products/{id}.{_format}           
  api_regions_get_collection              GET      ANY      ANY    /api/regions.{_format}                 
  api_regions_post_collection             POST     ANY      ANY    /api/regions.{_format}                 
  api_regions_get_item                    GET      ANY      ANY    /api/regions/{id}.{_format}            
  api_regions_put_item                    PUT      ANY      ANY    /api/regions/{id}.{_format}            
  api_regions_delete_item                 DELETE   ANY      ANY    /api/regions/{id}.{_format}            
  api_countries_get_collection            GET      ANY      ANY    /api/countries.{_format}               
  api_countries_post_collection           POST     ANY      ANY    /api/countries.{_format}               
  api_countries_get_item                  GET      ANY      ANY    /api/countries/{id}.{_format}          
  api_countries_put_item                  PUT      ANY      ANY    /api/countries/{id}.{_format}          
  api_countries_delete_item               DELETE   ANY      ANY    /api/countries/{id}.{_format}          
  api_countries_regions_get_subresource   GET      ANY      ANY    /api/countries/{id}/regions.{_format}  
  _twig_error_test                        ANY      ANY      ANY    /_error/{code}.{_format}               
  _wdt                                    ANY      ANY      ANY    /_wdt/{token}                          
  _profiler_home                          ANY      ANY      ANY    /_profiler/                            
  _profiler_search                        ANY      ANY      ANY    /_profiler/search                      
  _profiler_search_bar                    ANY      ANY      ANY    /_profiler/search_bar                  
  _profiler_phpinfo                       ANY      ANY      ANY    /_profiler/phpinfo                     
  _profiler_search_results                ANY      ANY      ANY    /_profiler/{token}/search/results      
  _profiler_open_file                     ANY      ANY      ANY    /_profiler/open                        
  _profiler                               ANY      ANY      ANY    /_profiler/{token}                     
  _profiler_router                        ANY      ANY      ANY    /_profiler/{token}/router              
  _profiler_exception                     ANY      ANY      ANY    /_profiler/{token}/exception           
  _profiler_exception_css                 ANY      ANY      ANY    /_profiler/{token}/exception.css       
 --------------------------------------- -------- -------- ------ --------------------------------------- 

ルートroute_product_slugは十分に存在しますが、常に次のエラーが発生します。

タイプ App\Entity\Product の項目の IRI を生成できません"

{
"@context": "/sf-flex-40/public/index.php/api/contexts/Error",
"@type": "hydra:Error",
"hydra:title": "An error occurred",
"hydra:description": "Unable to generate an IRI for the item of type \"App\\Entity\\Product\"",
"trace": [
    {
        "namespace": "",
        "short_class": "",
        "class": "",
        "type": "",
        "function": "",
        "file": "/home/amine/docker-projects/sf-flex-40/vendor/api-platform/core/src/Bridge/Symfony/Routing/IriConverter.php",
        "line": 107,
        "args": []
    },
    {
        "namespace": "ApiPlatform\\Core\\Bridge\\Symfony\\Routing",
        "short_class": "IriConverter",
        "class": "ApiPlatform\\Core\\Bridge\\Symfony\\Routing\\IriConverter",
        "type": "->",
        "function": "getIriFromItem",
        "file": "/home/amine/docker-projects/sf-flex-40/vendor/api-platform/core/src/JsonLd/Serializer/ItemNormalizer.php",
        "line": 71,
        "args": [
            [
                "object",
                "App\\Entity\\Product"
            ]
        ]
    },

このエラーは繰り返されるようです。それにもかかわらず、この問題は symfony 4 アプリケーションの flex-enable でのルートの順序の誤りに関連しているように思われるため、再度質問します ( https://github.com/api-platform/core/issues/830を参照してください)。

では、symfony 4 でアノテーションを使用している場合、ルートの適切な順序を設定するにはどうすればよいでしょうか。ルートはこれらのファイルで定義されています。

最初のファイル: annotations.yaml

# config/routes/annotations.yaml
controllers:
    resource: ../../src/Controller/
    type: annotation

2 番目のファイル: api_platform.yaml

# config/routes/api_platform.yaml
api_platform:
    resource: .
    type: api_platform
    prefix: /api

これは、ルートの順序を指定できるように、注釈の代わりに YAML ファイルを使用してすべての作業を構成する必要があるということですか?

ありがとう

ここで何

4

1 に答える 1

0

カスタム操作のルートの宣言は、yaml ファイルを介してのみ行うことができます。実際、注釈を使用しても、ルートの正しい順序を取得することはできません。カスタム操作のルートは、ルートの宣言の後に来る必要がありますapi_platform

api_platform:
    resource: .
    type: api_platform
    prefix: /api

api_product_slug:
    path: '/api/products/by-slug/{slug}'
    methods:  ['GET']
    defaults:
        _controller: App\Controller\ProductController:productsGetBySlugAction
        _api_resource_class: 'App\Entity\Product'
        _api_collection_operation_name: 'product_slug'
于 2018-01-19T06:21:14.033 に答える