【问题标题】:Symfony2 reusable functions in controllers控制器中的 Symfony2 可重用函数
【发布时间】:2016-04-17 12:49:44
【问题描述】:

一段时间后不知道如何正确执行此操作,并避免在多个控制器中重复代码,我搜索并再次寻找,但找不到明确的答案。

特别是一种情况,需要计算一个实体完成的几个统计数据。此计算将在 3 个不同的控制器中使用。 在其中两个中,我将展示分解为不同的布局,在第三个中,我将使用这些数据进行全局计算。 每个计算的业务逻辑,涉及到 100 多行代码,我必须在不同的控制器中增加三倍。

一个方案可以是:

  • 计算字段已完成“数据 A”
  • 计算字段已完成“数据 B”
  • 计算字段已完成“数据 C”

有了这 3 个值,我稍后再进行总计算。

我能找到的选项是:

知道如何解决这种情况吗?

非常感谢

【问题讨论】:

  • 在服务中进行计算(只需创建一个“CalculationService”,最好使用更好的名称..),然后在控制器中使用此服务。将控制器定义为服务更像是一种约定,它允许您注入所需的任何内容,而不是从容器中获取它们。
  • 我会使用服务选项。另一种方法是将数据转发到另一个控制器,但服务解决方案会更好......开销更少
  • @JimL 的建议,我经常使用这种方法,效果很好。
  • 我理解说 Controllers as Services 只是一种约定,实际上不必将其视为控制器,对吗?

标签: php symfony controller reusability


【解决方案1】:

服务似乎与所描述的用途非常相符。

最近,我研究了一个会计解决方案。我使用了很多复杂的算法,很快我就有了很长的方法,甚至尝试优化代码。

服务很容易调用,它们的使用可以使控制器更性感、更轻便,并通过使用与特定操作相对应的独立服务使大方法更易读、更可切割。

并且它们可以在其他组件中使用,只要存在 DependencyInjection,如果您可能需要在控制器的另一个上下文中应用它,它就足以移动您的逻辑。

声明很简单:

services:
    acmeapp.calculation:
        class: Acme\AppBundle\Services\CalculationService
        arguments: ["@doctrine.orm.entity_manager", "@acmeapp.anotherservice"]

还有服务

class CalculationService {

    protected $em;
    protected $another;

    public function __constructor(EntityManager $entityManager, AnotherService $anotherService)
    {
        $this->em = $entityManager;
        $this->another = $anotherService;
    }

    //...
}

Controller-Service 方法主要是一种服务,具有其所有优点。
您的服务的方法可以呈现视图并使用 _controller 属性关联路由,如下所示:

display_data_a:
    path:     /data/A
    methods: GET
    defaults: { _controller: acmeapp.calculation:dealWithData }

无需从Symfony\Bundle\FrameworkBundle\Controller\Controller 扩展您的服务,但是,当然,您可以使用它。

此外,如果您的控制器之间有许多重复的代码和几个不同的字符,那么抽象 BaseController 可能是一个非常干净的替代方案。
这是我在使用服务之前所做的,如果方法与我对控制器的定义相对应,这与@fabpot 在您的链接中所说的相对应。

DIC 主要帮助管理“全局”对象。控制器不是全局对象。此外,控制器应尽可能薄。它主要是您的模型和视图/模板之间的粘合剂。因此,如果您需要能够自定义,这可能意味着您需要重构它们并从中提取业务逻辑。

更多关于 OOP 中的 BaseController,

方法很简单,如果你有一行代码在一个方法中重复了两三次,你就使用一个变量。
对于代码块也是如此,您将使用一种方法。 对于控制器来说也是一样的,如果你有两个或多个相同类型的对象(这里是一个控制器),你应该使用 AbstractController(或 BaseController),在其中移动你重复的方法(当然只有一次),然后删除它们从子控制器。

基础控制器:

class BaseController extends Controller
{
    /**
     * Shortcut for get doctrine entity manager.
     */
    public function getEntityManager()
    {
        return $this->getDoctrine->getEntityManager();
    }

    /**
     * Shortcut for locate a resource in the application.
     */
    public function locateResource($path)
    {
        return $this->get('kernel')->locateResource($path);
    }

    // ...
}

并将其用作子控制器的一部分

class ChildController extends BaseController
{
    public function helloAction()
    {
        $em = $this->getEntityManager();
        $file = $this->locateResource('@AcmeAppBundle/Resources/config/hello.yml');
        // ...
    }

}

希望这可以帮助您避免大量重复代码。

【讨论】:

  • 非常感谢,现在我看的更清楚了
  • 我只是在你的问题中看到了关于 AbstractController 的部分,你只需要创建一个名为 BaseController 的类,无论是否抽象,从 Symfony 控制器扩展它(你的控制器目前正在从它扩展),添加你的泛型方法,然后从这个 AbstractController 扩展你的所有控制器。就是这样,一个简单的继承,但非常有用。
  • 虽然你解释得很好,能不能放个代码示例?再次感谢。
  • 没问题,Symfony2 是扩展这类东西的一个非常好的平台。我添加了一个示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多