将 Eloquent 模型与业务逻辑分离

Posted

技术标签:

【中文标题】将 Eloquent 模型与业务逻辑分离【英文标题】:separating an Eloquent Model from business logic 【发布时间】:2014-12-16 00:50:56 【问题描述】:

我想编写与框架无关的离散模型。

我为所有这些模型编写了接口。

问题是在实现这些接口时,例如使用 Eloquent,我将所有业务逻辑链接到 ORM。

例如,我想在 Product 模型上使用方法 addVariation

界面

interface ProductInterface
   
    /**
     * Adds a variation
     *
     * @param VariationInterface $variation
     */
    public function addVariation(VariationInterface $variation);

    // ...

凝结

class Product extends Model 

    /**
     *  @param Collection | VariationInterface
     */
    protected $variations;

    public function addVariation(VarientInterface $varient)
    
        if( ! $this->hasVariation($varient) ) 
        
            $this->variations->add($variations);
        

        return $this;
    

我遇到的问题是我的所有业务逻辑都存在于我的模型的特定 Eloquent ORM 实现中。

我怎么可能把它分开?我能看到的唯一真正的依赖是我需要某种类型的集合类?或者我可以只使用普通的旧数组?

我只是不想将我的所有逻辑链接到特定的 ORM 我想保持与框架无关。

【问题讨论】:

您可以创建一个与 eloquent 接口的存储库,这将允许您切换模型但保持相同的接口。我经历了类似的事情,但对于我的项目规模(不是很大),我决定让事情变得更简单。 culttt.com/2014/03/17/eloquent-tricks-better-repositories 了解更多信息。实际上,他所有的博客文章都非常适合从 laravel 开始。 说实话,即使您使用存储库模式,我也很难编写与框架无关的模型。据我了解,那一堆存储库本质上是通常注入 Laravel 控制器的接口。是的,您似乎将控制器与业务逻辑分开,但不要忘记那些 Laravel 控制器大量使用其他 Laravel 组件,例如 Redirect 或 View。 说到模型,你不能真正完全摆脱 Laravel。例如,如果你想在数据显示在视图中之前以某种方式自动重新格式化数据,你很可能会定义一些 Laravel 的 setter 和 getter:setXXXAttribute() 和 getXXXAttribute()。这个特性确实很棒,但是这样的编码会导致对 Laravel 的依赖,更不用说它们通常会扩展 Eloquent。 总之,对我来说,采用存储库/接口模式的好处更多是关于 Laravel 支持的应用程序的关注点分离,以及在 Laravel 上下文中更多可测试的代码,而不是你可以构建不可知论的框架楷模。 @uberweb 【参考方案1】:

只需从 Eloquent ORM 中删除所有逻辑即可。

您只需要一个 ORM 就可以更轻松地从数据库中保存和检索数据。您应该使用普通的旧 php 对象编写所有业务逻辑。然后,您可以创建一些通用的PersistenceGateway 接口,供您的所有业务逻辑模型使用,例如

interface PersistenceGatway 

   public function saveGatewayData($id, array $data);

   public function retrieveGatewayData($id)

您的解耦业务逻辑将此接口用于saveretrieve 数据。然后您需要做的就是使用您选择的 ORM 实现接口(或者您可能还需要创建一些适配器类来帮助您)。你现在可以插入任何你喜欢的 ORM,只要它实现了PersistenceGateway 接口。

看看Uncle Bobs Clean Architecture。像 Laravel 这样的 Web 框架应该是您的应用程序/业务逻辑的插件,而不是相反。

编辑:非常基本的示例。

class SomeBusinessLogic 

   // Note: Class depends on the PersistenceGateway. Any class
   // that implements this interface can be passed in. This is
   // essentially how you decouple logic from ORMS. You can now 
   // implement this interface with any ORM you like and pass it in
   public __construct(PersistenceGateway $gateway)
      $this->gateway = $gateway;
    

   public function someLogicMethod($id)
      // do something and save state to the gateway
      $this->gateway->saveGatewayData($id, ['some_state'=>'value']);
   

   public function someDataReturnMethod($id)
      return $this->gateway->retrieveGatewayData($id);
   



// Im extending from Eloquent here, but you can do a similar thing
// with any ORM.
class SomeEloquentModel extends Eloquent implements PersistenceGateway 

   public function saveGatewayData($id, array $data)
       $model = $this->find($id);
       // call eloquent save method
       $model->save($data);
   

   public function retrieveGatewayData($id)
       // retrieve the data. Important to return
       // an array NOT an eloquent model, otherwise
       // we are still coupled. I think toArray() is
       // the correct method to call on eloquent model
       return $this->find($id)->toArray();
   


class SomeController 

    class someControllerMethod 
       // Your controller decides on the implementation of PersistenGateway
       // to use. You could also use an IoC container which would be a slightly
       // cleaner solution
       $logic = new SomeBusinessLogic(new SomeEloquentModel());
       $logic->someLogicMethod(Input::get('id'));
       return $logic->someDataReturnMethod(Input::get('id'));
    


【讨论】:

我怎么可能用活动记录模式做到这一点?如果我的业务实体的属性和对象本质上必须是 Eloquent 模型,我会不会总是在其他层中包装一个 eloquent 模型?因此仍然与活动记录 ORM 耦合? @AndrewMcLagan 您可能需要从架构的角度了解为什么要使用 ORM。您不必将实体耦合到 ORM。你可以像我上面描述的那样将它们解耦。实体 ---> PersistenceGateway 谢谢,这可以解决问题。你能充实我们的例子吗?我想我在你的例子中遗漏了一些东西。 @AndrewMcLagan Uncle Bobs Clean Architecture 解释了如何将持久层/ORM 从应用程序逻辑和实体中分离出来。阅读有关 Uncle Bobs Clean Architecture 的链接和谷歌视频以获取更多信息。我认为您需要了解这些概念。如果我给你举个例子,在你理解理论之前,我仍然认为它对你没有意义。 @AndrewMcLagan 添加了非常基本的示例。如果仍然不清楚,建议阅读干净的架构

以上是关于将 Eloquent 模型与业务逻辑分离的主要内容,如果未能解决你的问题,请参考以下文章

使用 MVVM 将 GUI 与业务逻辑分离的最后步骤?

C 语言字符串拷贝 ( 字符串拷贝业务逻辑代码 | 分离 主函数 与 字符串拷贝 业务模型 )

平台技术框架的基本思路:基本原则

将存储与业务逻辑分离的技术(RDBMS 和 NoSQL)

sqlalchemy 模型的数据和逻辑分离

SpringMVC