【问题标题】:A good pattern to manage my controller api data calls管理我的控制器 api 数据调用的好模式
【发布时间】:2016-02-12 13:20:05
【问题描述】:

我接手了一个 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 symfony design-patterns


    【解决方案1】:

    您应该创建一个服务,根据您的需要将其传递给端点,将您的逻辑放入并将数据返回给您的控制器。

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

    服务可能如下所示:

    <?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']);
    

    有关详细信息,请参阅Services documentation。

    希望对你有所帮助。

    【讨论】:

      【解决方案2】:

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

      我会考虑定义我的controllers as services。这将允许您用构造函数注入替换其中的许多 get 调用,并且可能会清理一些东西。

      然后我会更进一步,将我的控制器类替换为操作类。我怀疑您的某些控制器实现了多个操作来制作相当大的文件?虽然有些动作很相似,但它们的不同之处足以开始让人有点困惑?

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-04
        • 1970-01-01
        相关资源
        最近更新 更多