Symfony 4,如何将通用控制器实现为服务?

时间:2019-06-11 12:05:55

标签: symfony symfony4

我有这个控制器

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());
    }
}

可以完全按预期工作(在Postman和我的浏览器中进行了测试)。我想概括地将通用控制器作为服务,并将该服务用于每个控制器Controller1.phpController2.phpController3.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 个答案:

答案 0 :(得分:4)

好的。回到基础。首先获得一个自己的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应该与实体管理器一起注入。我将把确切的细节留给学生作为练习,因为注入字符串与注入对象有些不同。

答案 1 :(得分:3)

您似乎导入了错误的服务,以及我们在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;
    }
}