Symfony - Нет расширения, способного загрузить конфигурацию (подписчик / прослушивание событий) (обработка исключений REST API с выводом JSON)
Цель
Здравствуйте, я новичок в Symfony и пытаюсь создать функциональность обработки исключений / ошибок для нашего веб-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 Style)
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 находятся на корневом уровне, и не должны иметь префикс "api", например 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:
Что я пробовал
Я отлаживал это в течение последних нескольких дней и прочитал много связанных обсуждений по переполнению стека. Я довольно новичок в службах, подписчиках и внедрении зависимостей, и я неоднократно пытался редактировать и маршруты., И сервисы. Я также получал некоторые исключения из циклических ссылок, но думаю, что исправил их сейчас. Я надеялся, что кто-нибудь может дать мне какое-то руководство и, надеюсь, помочь мне превратить это в рабочий пример Symfony 3.3, из которого я могу извлечь уроки. Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.
Из того, что я узнал, автоматическое подключение / автоконфигурирование сервисов в Symfony 3.3 кажется новым, и я думаю, что это может повлиять, но я не уверен. Я попытался отключить обе эти настройки в services.yml, но безуспешно.