目的
您好,我是 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 中关闭这两个设置,但没有运气。