Symfony 4, как реализовать общий контроллер как сервис? - PullRequest
2 голосов
/ 11 июня 2019

У меня есть этот контроллер

Controller1.php

<?php


namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class file1Controller extends AbstractController
{
    /**
     * @Route("/Some/URI", methods={"GET"})
     * @param Request $request
     * @return JsonResponse
     */
    public function list(Request $request)
    {
        if (empty($request->headers->get('api-key'))) {
            return new JsonResponse(['error' => 'Please provide an API_key'], 401);
        }

        if ($request->headers->get('api-key') !== $_ENV['API_KEY']) {
            return new JsonResponse(['error' => 'Invalid API key'], 401);
        }

        return new JsonResponse($this->getDoctrine()->getRepository('App:Something')->findAll());
    }
}

Который работает точно так, как задумано (протестировано с Почтальоном и с моим браузером). Я хотел бы обобщить, чтобы сделать общий контроллер в качестве службы и использовать эту службу для каждого контроллера, Controller1.php, Controller2.php и Controller3.php, где все одинаково, за исключением @route и Something внутри метода getRepository.

Это мой путь:

GeneralService.php

<?php


namespace Service;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;


class GeneralService
{
    /**
     * @param Request $request
     * @param String $entity
     * @return JsonResponse
     */
    public function list(Request $request, String $entity)
    {
        if (empty($request->headers->get('api-key'))) {
            return new JsonResponse(['error' => 'Please provide an API_key'], 401);
        }

        if ($request->headers->get('api-key') !== $_ENV['API_KEY']) {
            return new JsonResponse(['error' => 'Invalid API key'], 401);
        }

        return new JsonResponse($this->getDoctrine()->getRepository('App:{$entity}')->findAll());
    }

}

И Controller1.php затем изменяется на SubscriptionController.php:

<?php


namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Service\GeneralService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class SubscriptionController extends AbstractController
{
    /**
     * @Route("/Some/Uri", methods={"GET"})
     * @param GeneralService $generalService
     * @param Request $request
     * @return JsonResponse
     */
    public function AuthenticateAPI(GeneralService $generalService, Request $request)
    {
        $AuthenticatorObject = $generalService->list($request ,'Something');
        return $AuthenticatorObject;
    }

}

Это, к сожалению, не работает и выдает следующую ошибку:

InvalidArgumentException

Невозможно определить аргумент контроллера для «App \ Controller \ Controller1 :: AuthenticateAPI ()»: аргумент $ generalService намекается на тип с помощью несуществующего класса или интерфейса: «Service \ GeneralService».

Я не вижу, откуда эта ошибка и почему. Может ли кто-нибудь помочь мне понять, почему это так и как это исправить?

Ответы [ 2 ]

4 голосов
/ 11 июня 2019

Хорошо.Вернуться к истокам.Начните с того, что получите себе IDE, такую ​​как PHPStorm.Он будет выделять различные синтаксические ошибки, а что нет.В частности, IDE поможет с проблемой пространства имен службы, а также с рядом других проблем.

Фундаментальная концепция внедрения зависимостей заключается в том, что зависимости, необходимые для данного класса, должны быть, впрочем, внедрены.Вашему классу GeneralService нужен менеджер сущностей.В вашем предыдущем идентичном вопросе у вас был GeneralService, расширяющий AbstractController, потому что AbstractController имеет метод getDoctrine.Это все равно не сработало бы, потому что getDoctrine, в свою очередь, нуждается в контейнере службы.И, конечно же, в вашем текущем коде GeneralService вообще не имеет метода getDoctrine.

В любом случае, поскольку GeneralService нужен менеджер сущностей, введите его:

# src/Service/GeneralService.php
namespace App\Service; # NOTE App\Service not just Service

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class GeneralService
{
    private $entityManager;

    // Let Symfony inject whatever dependencies are needed
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }
    public function list(Request $request, String $entityClass) : JsonResponse
    {
        if (!$request->headers->has('api-key')) {
            return new JsonResponse(['error' => 'Please provide an API_key'], 401);
        }

        if (!$request->headers->get('api-key') !== $_ENV['API_KEY']) {
            return new JsonResponse(['error' => 'Invalid API key'], 401);
        }

        return new JsonResponse($this->entityManager->getRepository($entityClass)->findAll());
    }
}

И не исключайтеGeneralService больше.

С вашим классом контроллера все в порядке, когда вы используете IDE, чтобы избавиться от всех небольших синтаксических ошибок:

namespace App\Controller;

use App\Service\GeneralService;
use App\Entity\SomeEntity;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;

class SubscriptionClass extends AbstractController
{
    public function AuthenticateAPI(Request $request, GeneralService $generalService)
    {
        $AuthenticatorObject = $generalService->list($request,SomeEntity::class);
        return $AuthenticatorObject;
    }

}

Я на самом деле не тестировал приведенный выше код, хотядолжен сделать вас хотя бы на шаг впереди.

Последнее замечание: не обращайтесь напрямую ни к одному из суперглобальных элементов, т. е. $ _ENV ['API_KEY'] - это нет, нет.Ключ api_key должен быть введен вместе с менеджером сущности.Я оставлю точные детали в качестве упражнения для студента, поскольку введение строк немного отличается от ввода объектов.

3 голосов
/ 11 июня 2019

Похоже, что вы импортировали сервис неправильно и некоторые другие вещи, о которых мы говорили в tchat.

Важно:

  • Сервис должен находиться в папке src/Service.
  • Услуга не должна быть исключена в services.yml

Окончательное решение для людей:

Услуга:

namespace App\Service;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface; 

class GeneralService
{

    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    } 

    /**
     * @param Request $request
     * @param String $entity
     * @return JsonResponse
     */
    public function list(Request $request, String $entity)
    {
        if (empty($request->headers->get('api-key'))) {
            return new JsonResponse(['error' => 'Please provide an API_key'], 401);
        }

        if ($request->headers->get('api-key') !== $_ENV['API_KEY']) {
            return new JsonResponse(['error' => 'Invalid API key'], 401);
        }

        return new JsonResponse($this->entityManager->getRepository($entity)->findAll()); 
    }

}

Иконтроллер:

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Service\GeneralService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class SubscriptionController extends AbstractController
{

    /**
    * @Route("/Some/Uri", methods={"GET"})
    * @param GeneralService $generalService
    * @param Request $request
    * @return JsonResponse
    */
    public function AuthenticateAPI(GeneralService $generalService, Request $request)
    {
        $AuthenticatorObject = $generalService->list($request , 'App\Entity\Something');
        return $AuthenticatorObject;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...