1

目的

您好,我是 Symfony 的新手,正在尝试为我们的 Web API 创建异常/错误处理功能。

要求

当用户向我们的 API 发出无效请求时,我们希望返回一个简单的 JSON 对象,如下所示:

{"errorCode": 1234567, "errorMessage": "Parameter 1 is invalid. String expected"}

除了特定于 API 的错误之外,我们还希望挂钩到 Symfony 中的内置异常处理并重新使用它,但是我们不想返回 HTML 错误页面(这是默认情况下发生的),我们希望返回一个 JSON 对象,例如:

{"errorCode": 404, "errorMessage": "Not found"}

当前方法

显然,我们希望以最有效的方式实现这一点,所以在做了一些研究之后,我发现我认为这是一个很好的方法,然后我可以适应我们的特定需求。这是我遵循的教程:

https://knpuniversity.com/screencast/symfony-rest2

我最终购买了这门课程以获取完整代码。问题是它是为 Symfony 2 编写的,但我们运行的是 Symfony 3.3,所以有些东西已经过时了,我还不能让这个例子运行起来。

代码

因此,我在下面发布了一些相关代码。(我显然不能发布整个代码,但已经发布了希望公开的代码的相关部分)。

services.yml(他们的版本,Symfony 2 风格)

api_exception_subscriber:
        class: AppBundle\EventListener\ApiExceptionSubscriber
        arguments: []
        tags:
            - { name: kernel.event_subscriber }

services.yml(我删除了所有评论的完整文件) 这包括他们上面的修改版本(希望这是正确的Symfony 3.3做事方式)。 注意:任何属于我无法显示的私人代码的一部分,我已用“某物”一词替换。

parameters:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    AppBundle\:
        resource: '../../src/AppBundle/*'
        exclude: '../../src/AppBundle/{Entity,Repository,Tests}'

    AppBundle\Controller\:
        resource: '../../src/AppBundle/Controller'
        public: true
        tags: ['controller.service_arguments']

    AppBundle\EventListener\ApiExceptionSubscriber:
        arguments:
        - ['%something.something%']
        tags:
        - {name: 'kernel.event_subscriber'}

routing.yml(他们文件的相关部分)

app_api:
    resource: "@AppBundle/Controller/Api"
    type:     annotation
    defaults:
        _format: json

routing.yml(我的完整文件) -注意:我必须将“_format:json”直接添加到“app”部分而不是“app_api”,因为在我们的 REST API 中,我们所有的 URL 都在根级别,并且不必像教程代码中那样以http://localhost/api/someMethod/someMethodParameter为前缀

app:
    resource: '@AppBundle/Controller/'
    type: annotation
    defaults: {_format:json}
yml_route:
  path: /yml-route
  defaults:
    _controller: AppBundle:Default:yml
awesome_route:
  path: /awesome-route/{ic}
  defaults:
    _controller: AppBundle:Rest:awesomeRoute

src/AppBundle/RestController.php(编辑以仅显示基本结构)

    <?php 
    namespace AppBundle\Controller;
    use FOS\RestBundle\Controller\Annotations as Rest;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\HttpFoundation\JsonResponse;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Serializer\Serializer;
    use Symfony\Component\Serializer\Encoder\XmlEncoder;
    use Symfony\Component\Serializer\Encoder\JsonEncoder;
    use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
    use Symfony\Component\HttpFoundation\Request;

    class RestController extends Controller {

       public function doSomething($id)
       {
          // Code to populate $result with data from database is here
          return new JsonResponse($result);
       }

    // This file contains many different functions similar to doSomething() which retrieve the request for the API caller.
   // For example, doSomething() can be accessed via http://localhost/app_dev.php/doSomething/123
    }

src/AppBundle/Api/ApiProblem.php(编辑以仅显示基本结构)

namespace AppBundle\Api;
use Symfony\Component\HttpFoundation\Response;

class ApiProblem
{
   // Code relevant to this class is in here
}

src/AppBundle/Api/ApiProblemException.php(已编辑以仅显示基本结构)

    <?php

    namespace AppBundle\Api;
    use Symfony\Component\HttpKernel\Exception\HttpException;

    class ApiProblemException extends HttpException
    {
       private $apiProblem;

       public function __construct($severalParametersWhichICannotListHereBecauseCodeIsPrivate) {
       // Does some stuff and then calls the parent:__construct
       // Includes a getter for $apiProblem
    }
}

src/AppBundle/EventListener/ApiExceptionSubscriber.php(已编辑以仅显示基本结构)

<?php 
namespace AppBundle\EventListener;
use AppBundle\Api\ApiProblem;
use AppBundle\Api\ApiProblemException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\KernelEvents;

class ApiExceptionSubscriber implements EventSubscriberInterface
{
   // Code relevant to this subscriber is here
}

问题

当我尝试从命令行 bin/console 运行任何类型的命令时,出现以下错误:

    C:\htdocs\projects\myproject>php bin/console debug:container
    PHP Fatal error:  Uncaught Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: T
    here is no extension able to load the configuration for "AppBundle\EventListener\ApiExceptionSubscribe
    r" (in C:\htdocs\projects\myproject\app/config\services.yml). Looked for namespace "AppBundle\EventListe
    ner\ApiExceptionSubscriber", found "framework", "security", "twig", "monolog", "swiftmailer", "doctrin
    e", "sensio_framework_extra", "demontpx_parsedown", "doctrine_cache", "doctrine_migrations", "debug",
    "web_profiler", "sensio_distribution", "web_server" in C:\htdocs\projects\myproject\vendor\symfony\symfo
    ny\src\Symfony\Component\DependencyInjection\Loader\YamlFileLoader.php:644
    Stack trace:
    #0 C:\htdocs\projects\myproject\vendor\symfony\symfony\src\Symfony\Component\DependencyInjection\Loader\
    YamlFileLoader.php(614): Symfony\Component\DependencyInjection\Loader\YamlFileLoader->validate(Array,
    'C:\\htdocs\\proje...')
    #1 C:\htdocs\projects\myproject\vendor\symfony\symfony\src\Symfony\Component\DependencyInjection\Loader\
    YamlFileLoad in C:\htdocs\projects\myproject\vendor\symfony\symfony\src\Symfony\Component\Config\Loader\
    FileLoader.php on line 179

    Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: There
    is no extension able to load the configuration for "AppBundle\EventListener\ApiExceptionSubscriber" (i
    n C:\htdocs\projects\myproject\app/config\services.yml). Looked for namespace "AppBundle\EventListener\A
    piExceptionSubscriber", found "framework", "security", "twig", "monolog", "swiftmailer", "doctrine", "
    sensio_framework_extra", "demontpx_parsedown", "doctrine_cache", "doctrine_migrations", "debug", "web_
    profiler", "sensio_distribution", "web_server" in C:\htdocs\projects\myproject\vendor\symfony\symfony\sr
    c\Symfony\Component\Config\Loader\FileLoader.php on line 179

    Symfony\Component\Config\Exception\FileLoaderLoadException: There is no extension able to load the con
    figuration for "AppBundle\EventListener\ApiExceptionSubscriber" (in C:\htdoc
    fig\services.yml). Looked for namespace "AppBundle\EventListener\ApiExceptio
    work", "security", "twig", "monolog", "swiftmailer", "doctrine", "sensio_fra
    arsedown", "doctrine_cache", "doctrine_migrations", "debug", "web_profiler",
    eb_server" in C:\htdocs\projects\myproject\app/config\services.yml (which is b
    ocs\projects\myproject\app/config\config.yml"). in C:\htdocs\projects\myproject\
    \Symfony\Component\Config\Loader\FileLoader.php on line 179

    Call Stack:
        1.4353    6149416   1. Symfony\Component\Debug\ErrorHandler->handleExcep
    myproject\vendor\symfony\symfony\src\Symfony\Component\Debug\ErrorHandler.php:

我试过的

过去几天我一直在调试它,并阅读了许多关于 Stack Overflow 的相关讨论。我对服务、订阅者和依赖注入相当陌生,我已经尝试过多次编辑 routes.yml 和 services.yml。我之前也遇到过一些循环引用异常,但我认为我现在已经修复了这些异常。我希望有人能给我一些指导,并希望能帮助我把它变成一个我可以从中学习的 Symfony 3.3 上的工作示例。如果您需要任何其他详细信息,请告诉我。

据我所知,Symfony 3.3 中服务的自动装配/自动配置似乎是新事物,我认为这可能会影响一些事情,但我不确定。我确实尝试在 services.yml 中关闭这两个设置,但没有运气。

4

0 回答 0