管理控制器 api 数据调用的良好模式


A good pattern to manage my controller api data calls

我已经接管了一个Symfony 2.6项目,我正忙于尽可能多地重构胖控制器。

目前,所有控制器的jist都遵循类似的结构

/**
 * @Method({"GET"})
 * @Route("/", name="homepage")
 * @Template()
 */
public function indexAction() 
{
    //Initialize the API
    $api = $this->get('core_bundle.api_wrapper')->getApi();
    //Retrieve data from various end points
    $result_set = $api->get('/rest/resource');
    $result_set2 = $api->get('/rest/resource2');
    $result_set3 = $api->get('/rest/resource3');
    //etc.. etc..
    //Once all api calls have been completed, do some manipulation of the data if required
    $result_set = DataHelper::getInstance()->setReadFlags($result_set);
    //The api resultset keys are not always standard (It's just the way it is Stackoverflow, I cannot change the API code)
    $result_set2 = Standardize::getInstance()->standardizeKeys($result_set2);
    $result_set2 = DataHelper::getInstance()->setReadFlags($result_set2);
    //Create the social links from the existing data
    $result_set3 = SocialHelper::getInstance()->createSocialLinks($result_set3);
    return [$result_set, $result_set2, $result_set3];
}

我正在努力找到一种适用于此类场景的良好模式。我需要清理控制器并将尽可能多的业务逻辑移出其中,因为某些控制器有 100+ 行代码。

我遇到的问题是:

  1. 每个控制器都可以对 API 进行多次调用以获取数据。数据并不总是相关的,有时调用依赖于用户角色和/或上一个 API 调用中的密钥。
  2. 每个结果集都需要以某种方式进行操作,然后才能返回到视图响应中。

我觉得创建多个模型然后传入 API 结果集,然后调用一个函数来操作每个结果集将导致较小的控制器操作,但令人困惑,因为我将为每个结果集多次调用多个模型。

如果我想与单一责任保持一致,最终将不得不创建大量模型类。

任何指导将不胜感激。

您应该创建一个服务,根据需要向其传递端点,将逻辑引入,然后将数据返回到控制器。

像这样,控制器将只返回包含服务获取的数据的响应。
它会很轻。

该服务可能如下所示:

<?php
namespace AppBundle'Services;
class EndpointManager
{
    public function __construct(YourApiService $apiWrapper) 
    {
        $this->apiWrapper = $apiWrapper;
    }
    public function fetch(array $endpoints)
    {
        $data = array();    
        // Do your logic here
        foreach ($endpoints as $end) {
            $data[$end] = $apiWrapper->get($end);
        }
        // ...
        // Return the data fetched
        return $data;
    }
}

用你需要的所有服务作为参数声明它:

services:
    endpoint_manager:
        class: AppBundle'Services'EndpointManager
        arguments:
            apiWrapper: "@core_bundle.api_wrapper"

(如果传递更多参数,请不要忘记在服务的构造函数中设置它(

然后,使用它:

$apiManager = $this->get('endpoint_manager');
return $apiManager->fetch(['api/endpoint1', 'api/endpoint2']);

有关详细信息,请参阅服务文档。

希望这对你有帮助。

与许多事情一样,这取决于项目的细节。 @chalasr有一些非常好的建议。

我会考虑将我的控制器定义为服务。 这将允许您用构造函数注入替换其中的许多 get 调用,并且可能会稍微清理一下。

然后,我将更进一步,将我的控制器类替换为操作类。 我怀疑您的某些控制器实现了多个操作,使文件相当大? 虽然有些动作是相似的,但它们的差异足以开始变得有点混乱?

操作类

与控制器类的不同之处在于,操作类实现一个且只有一个操作方法。 该方法仍使用请求作为输入生成响应。 你最终会得到更多的类,但每个类都变小,只关注一件事。 我还发现,一旦代码分解为自己自己的类,来自不同控制器类的操作代码通常可以共享。

另一方面,为了保持一致性,我还会将您的单例(DataHelper,SocialHelper(定义为Symfony服务。