在 CodeIgniter 应用程序中实现服务层的正确方法

Correct way of implementing a service layer in CodeIgniter applications

以下是在 CodeIgniter 应用程序中实现服务层的两种方式。

第一种方法

1.send request to the controller 
2.calling service layer methods from controller
3.return processed result data set(D1) from service layer to controller 
4.then according to that data set controller demand data from model
5.model return data set(D2) to the controller
6.then controller send second data set(D2) to view.

第二种方法

1.send request to the controller
2.calling service layer methods from controller
3.service layer demand data from model
4.model send requested data set(d1) to the service layer
5.after some processing return generated data(d2) to controller from service layer
6.then controller send data set(d2) to view. 

在 CodeIgniter 中实现服务层的正确方法是什么?除了这两种方法,还有其他好的方法吗?

如果你能在代码中提供一个例子那就太好了

你应该使用第一个。因为在 MVC web 应用程序中,控制器用于将您的业务逻辑与视图分离,它就像一个网关。您需要开始使用控制器处理您的信息,您应该从控制器调用模型或服务层或任何您需要的东西,最后您应该 return 从这里将数据返回到任何其他来源。您的视图或服务层不应直接访问模型。

恕我直言,这里没有对错:

选项 #1 - 如果你想在多个控制器/动作中重用服务层 并根据第一个有意义的请求从不同模型提供数据。

选项 2# - 但是,如果您的数据模型更复杂,第一个选项可能会有问题。如果需要根据第一次调用的数据对模型进行第二次调用怎么办?将控制器用于此业务逻辑违背了服务层的全部目的。在这种情况下,选择第二个可能会更好。

我觉得第二种比较常见

Please note, this is not necessarily the correct way of doing it, but I'm going to explain how a framework like might typically do it and then you can learn about other methods and decide the best one for your use-case. Therefore, I do not expect this answer to be the correct one, but I hope it imparts at least a little knowledge on how things are done before someone who actually knows what they're talking about comes along and chimes in (also to those people - please feel free to edit / downvote this answer :D). Finally this also has nothing to do with CodeIgniter but frameworks in general. Your question should not only be framed as framework-agnostic, but language-agnostic also.

所以我要在这里提出一个观点,那就是所有现代框架,特别是 PHP、 都不做 MVC。为什么这很重要?因为我们都需要说同一种语言,而 PHP 中不存在 'mvc'。这是事实。接受这一点,然后我们就可以继续对框架使用的概念进行混蛋; CodeIgnitor 是 'MVC' 混蛋化的一个特别好的例子;今后称为 "mvc" 带引号。

好的一面是像 Symfony 这样的框架,例如,提供了一个初始的自以为是的架构,它至少包含某种形式的跨应用程序的一致性,它是这样的:

  1. 一个标准的 HTTP 请求进入并命中 front-controller,通常是 app.phpapp_dev.php,具体取决于您是在开发中还是在生产中;一个涉及大量缓存,每次更改都需要 运行,而另一个则不需要 - 这非常适合开发。

  2. 路由器将当前 url 匹配到控制器 class 和 class 中的 'action'(方法)。

  3. 框架的依赖注入部分找出从控制器到模型层再到模型层的一切都需要什么对象,并在需要时实例化或准备实例化它们。

  4. 控制器被实例化并具有任何所需的依赖项并执行相关方法。这通常是您开始开发和 'hook your code in' 框架的地方。

  5. 这是您决定架构的地方,但是,从开发人员的角度和业务的角度(为了降低未来维护成本)最重要的是一致性.

  6. 我个人更愿意确保我的代码与框架分离。我将从请求中获取的标量传递给 application-layer 服务,该服务使用模型层中的对象(passed-in 通过 DI)来使用领域对象。这里的重点是域对象没有直接传递到控制器中,它们是通过 application-layer 媒介代理的,所以理论上你可以替换围绕它的整个框架,而且你需要做的就是将这些标量传递到在他们到达模型层之前的这一层,它仍然可以工作(想想 CLI 调用,没有更多的控制器)。

  7. application-level 服务使用任何必需的 RepositoriesServices 等(并将这些标量传递给它们,还记得分离吗?),执行业务逻辑,(通常这些是您的设计模式在 day-to-day 基础上发挥作用的地方),然后 return 将数据发送到 application-level 服务。

  8. 服务然后return将数据发送到控制器,你猜怎么着?这就是框架容易出错的地方!因为现在的框架中没有"View"的概念。只有一个模板,您将该数据传递给模板,然后就可以了。所以在你的图表中,绝对没有视图的概念,因为事情不是那样做的。老实说,我仍在使用模板,因为它们是最快的做事方式,但在现代框架整合起来并真正开始使用视图之前,我们运气不好,在面对问题时必须保持坚定事实上,有些(如 Laravel)将自己称为 "mvc" 框架。

Note, Fabien Potencier explicitly states that Symfony was not an MVC framework - at least he knows what he's talking about there. Again, this is not purist, it's important we're all speaking the same, factually correct language in computing.

所以,因为您非常喜欢图表,下面是一些人可能会如何使用当今的框架来实现...

这是针对每个 Review 具有 ReviewCriteria 概念的应用程序。甚至不要让我开始使用 Symfony 表单,它们与所有事物紧密相关,它们不是任何体系结构的重要组成部分。

你需要多少个效果层?我们已经有 "MVC",在 DDD 中我们有 "Application"、"Domain" 和 "Infrastructure" 分离的概念,所以先让这两个一起工作,然后再 "service layer" ?你真的需要另一层,还是上面的就足够了?需要考虑的事情...

看,您不会因为这种分离而受制于框架/http 请求来启动应用程序

看到上图中的"services"了吗?它们与控制器分离,因此您可以从任何地方抛出标量,应用程序仍然可以工作。 我认为这将为您提供所需的分离。以正确的方式做事很棒,学习如何去做,然后学习如何控制自己并在涉及业务和需求时务实地对待它,但是框架需要整理它们的东西 - 你当然不会用 CodeIgniter 编写可爱的代码 ;)

依赖注入和适配器模式将是一个很好的起点。 CodeIgniter 支持既不是开箱即用的,因此您需要编写一个包装器或一个挂钩。

您的视图只能支持 xml|html,因为 json 需要预渲染到 .json 文件,然后 return ed 作为输出,但这需要通过代码完成,在这种情况下 return 对象并在前端进行更改会更容易。 PHP 是一种嵌入式语言,可用于 (xml|html)

服务模型在注入时效果最好(依赖注入) 进入 controller/model 并列为 controller/model 的 属性。

然后服务绑定到接口

例如facebook/twitter 它们都有请求和响应功能,但都遵循相似的模式,但有不同的端点。

interface SocialMediaAdapter{
  public request(url);
  public response();
}

public class FaceBookProvider implements SocialMediaAdapter
{
     public request(url){

     }
     public response(){

     }

}

public class TwitterProvider implements SocialMediaAdapter
    {
         public request(url){

         }
         public response(){

         }
    }

public class SocialMediaServiceProvider{

    protected $provider = null;

    public function constructor(SocialMediaAdapter $provider){
       $this->provider = $provider;
    }

    public function fetch($url){
       return $this->provider->request($url);
    }
}

此处需要依赖注入

new MyController( new SocialMediaServiceProvider ( new FacebookService ) )