无法为类型的项生成IRI

时间:2018-01-16 14:50:50

标签: symfony api-platform.com symfony-flex

我实际上正在构建一个基于以下内容的API:

  • symfony / flex:v1.0.61
  • symfony:v4.0.3
  • api-platform / api-pack:v1.0.1
  • api-platform / core:v2.1.4

CRUD操作很容易实现。不过, custom operation似乎不是直截了当的。

我尝试实施的自定义操作只会根据给定的App\Entity\Product返回$slug

  • 路线为:/api/products/by-slugs/{slug}
  • 方法是:GET
  • 操作类型为:itemOperations

这是事情的完成方式:

产品资源声明

<?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 &#34;类型的项目生成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"
            ]
        ]
    },

这个错误似乎是反复出现的。不过,我再问一遍,因为问题似乎与我的flex-enable symfony 4应用程序中的路径顺序有关(请参阅https://github.com/api-platform/core/issues/830)。

那么,如果我在symfony 4中使用注释,如何设置路由的正确顺序。路由在这些文件中定义:

第一个文件:annotations.yaml

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

第二个文件:api_platform.yaml

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

这是否意味着我必须使用YAML文件配置我的所有工作而不是注释,以便我可以指定路由的顺序?

由于

这是什么

1 个答案:

答案 0 :(得分:0)

自定义操作路由的声明只能通过 yaml文件。事实上,使用注释不会让我们正确的路线顺序。自定义操作的路径必须在声明路由mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # # * Basic Settings # user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. bind-address = 127.0.0.1 # # * Fine Tuning # key_buffer_size = 16M max_allowed_packet = 150M thread_stack = 192K thread_cache_size = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover-options = BACKUP #max_connections = 100 #table_cache = 64 #thread_concurrency = 10 # # * Query Cache Configuration # query_cache_limit = 1M query_cache_size = 16M 之后。

api_platform