【问题标题】:Symfony4 resource controllerSymfony4 资源控制器
【发布时间】:2018-12-20 16:52:42
【问题描述】:

我正在 symfony4 下开发一个 API,我希望我可以创建一个父控制器,我可以使用它来调用将在另一个控制器中重复的函数。这是我想从父控制器扩展的控制器:

我的交付控制器:

<?php

namespace App\Controller;

use App\Entity\DeliveryMan;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class AuthController
 * @package App\Controller
 * @Route("/api")
 */
class DeliveryController extends AbstractController
{
    /**
     * @Route(
     *     name="api_delivery_man_post",
     *     path="/delivery_man",
     *     methods={"POST"},
     *     defaults={
     *         "_api_resource_class"=DeliveryMan::class,
     *         "_api_collection_operation_name"="post"
     *     }
     * )
     */
    public function postAction(DeliveryMan $data, UserPasswordEncoderInterface $encoder): DeliveryMan
    {
        return $this->encodePassword($data, $encoder);
    }

    protected function encodePassword(DeliveryMan $data, UserPasswordEncoderInterface $encoder): DeliveryMan
    {
        $encoded = $encoder->encodePassword($data, $data->getPassword());
        $data->setPassword($encoded);

        return $data;
    }
}

我的 AuthController:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Entity\User;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

/**
 * Class AuthController
 * @package App\Controller
 * @Route("/api")
 */
class AuthController extends AbstractController
{
    /**
     * @Route(
     *     name="api_users_post",
     *     path="/users",
     *     methods={"POST"},
     *     defaults={
     *         "_api_resource_class"=User::class,
     *         "_api_collection_operation_name"="post"
     *     }
     * )
     */
    public function postAction(User $data, UserPasswordEncoderInterface $encoder): User
    {
        return $this->encodePassword($data, $encoder);
    }

    protected function encodePassword(User $data, UserPasswordEncoderInterface $encoder): User
    {
        $encoded = $encoder->encodePassword($data, $data->getPassword());
        $data->setPassword($encoded);

        return $data;
    }
}

可以看出,我在 2 个不同的控制器中调用 2 个相同的动作,唯一的区别是实体和道路的路径。

所以我正在考虑创建一个 ResourceController 父控制器,该控制器将从 AbstractController 扩展,并且子控制器将从 ResourceController 扩展,但我不知道如何在我的父控制器中创建我的方法并在子控制器。

如果有人已经这样做了,我就是接受者:) 谢谢你的帮助。

编辑结果资源控制器:

<?php

namespace App\Controller;

use App\Entity\DeliveryMan;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class ResourcesController extends AbstractController
{
    private $encoder;

    public function __construct(UserPasswordEncoderInterface $encoder)
    {
        $this->encoder = $encoder;
    }

    public function encodePassword(User $data): User
    {
        $encoded = $this->encoder->encodePassword($data, $data->getPassword());
        $data->setPassword($encoded);

        return $data;
    }

    public function encodePasswordDelivery(DeliveryMan $data): DeliveryMan
    {
        $encoded = $this->encoder->encodePassword($data, $data->getPassword());
        $data->setPassword($encoded);

        return $data;
    }
}

【问题讨论】:

  • 那么你的控制器负责密码管理?每次违反SRP,你就杀了一只熊猫。

标签: api symfony symfony4 api-platform.com


【解决方案1】:

只需制作一个扩展 Symfony AbstractController 的 ResourceController。

在此处编写您的 2 个共享方法,然后在任何扩展 ResourceController 的控制器中调用它们,就像您通常调用类方法一样:使用 $this

class ResourceController extends AbstractController
{   
    private $encoder;

    public function __construct(UserPasswordEncoderInterface $encoder)
    {
        $this->encoder = $encoder;    
    }

    public function encodePassword(Object $data): Object
    {
        $encoded = $this->encoder->encodePassword($data, $data->getPassword());
        $data->setPassword($encoded);

        return $data;
    }
}

class AuthController extends ResourceController
{
    public function someAction(User $data)
    {
        return $this->encodePassword($data);
    }
}

我还建议您使用 User 和 DeliveryMan 将实现的 getPassword 方法编写一个接口。您不仅可以确保该方法已实现,而且您还可以输入提示,例如 AuthenticatedEntityInterface,而不是 Object

【讨论】:

  • 它可以工作,但缺点我必须在我的控制器资源 1 中为用户重做相同的方法,为 DeliveryMan 重做 1? (见我的帖子)
  • 你没有,你可以有 1 种方法,其中 $data 参数将被键入为“对象”,而不是一个用“用户”键入,一个用 DeliveryMan 键入,但这并不理想。最好的方法是使用 OOP 功能,例如继承或接口,您的 DeliveryMan 可能是 User 的孩子(也许已经是这种情况?)然后您可以只使用 User 键入 1 个方法。或者 User 和 DeliveryMan 可以是 AbstractUser 的子级,然后在您的 encodePassword 中键入 AbstractUser。要使用界面,请参阅我的答案。考虑学习 OOP 是如何工作的,因为 Symfony 强烈依赖它。
  • 另外,如果它适合您,请考虑支持/验证答案,谢谢:)
猜你喜欢
  • 2018-10-31
  • 2011-11-16
  • 1970-01-01
  • 2014-04-28
  • 2014-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
相关资源
最近更新 更多