将域与活动记录组合在一起

时间:2017-04-17 03:05:41

标签: laravel design-patterns activerecord yii2 datamapper

我使用yii2并发现它的活动记录非常方便。

但有时我发现我们总是把逻辑函数放在活动记录中,我认为它应该属于域。

我查了一些书,其中大部分建议使用数据映射器将数据库记录映射到域。

虽然这是分割域和数据的好方法,但我不想浪费yii2的活动记录功能。

我认为我们可以从活动记录扩展域,以便数据库操作将在域的父类活动记录中,业务逻辑操作将在域中:

class UserModel extends ActiveRecord{
      // do database operations
}

class UserDomain extends UserModel{
    // do domain's logic
}

我不知道这个设计很棒吗?请告诉我你的建议。

更新#1

class UserDomain {
    private $model;

    public function __construct(UserModel $model){
         $this->model=$model;
    }

    public function __set($name, $value){
         if (isset($this->model->$name)) {
             $this->model->$name=$value;
         } else {
             $this->$name=$value;
         }
    }

    public function __get($name){
         if (isset($this->model->$name)) {
             return $this->model->$name;
         } else {
             return $this->$name;
         }
    }
}

1 个答案:

答案 0 :(得分:1)

单独的域和数据层

您假设的方法肯定比在ActiveRecord类中编写所有业务逻辑更好。它将使您的代码可维护和清晰。在我看来,遗漏的一件事是灵活性。主要想法是:

  

域类应使用实现类,不继承   来自他们。

这不是公理,但在很多情况下都是如此。这是an article,以帮助您选择所需的设计。

一个简单的例子说明了如何用组合替换继承:

class UserDomain {

    private $model;

    public function __construct(UserModel $model)
    {
        $this->model = $model;
    }
}

这是获得灵活性的第一步。它允许您使用多个模型类并使UserDomain更容易测试,因为它具有干净且松散耦合依赖性。

Yii2使用Dependency Injection模式帮助您控制此类依赖项。以下是官方文档的链接,其中包含使用Dependency Injection Container的示例。简而言之,您可以创建域类的实例,如下所示:

$user = $container->get('UserDomain');

Yii将为您注入所有必需的依赖项。

访问数据层

另一个问题是从域访问数据层。我很确定,使用PHP magic methods是一个坏主意。

UserDomain课程中,您应该使用更高级别的方法,而不是UserModel。因此,通常情况下,您在域层没有setEmail()方法,而是使用updateProfile()

class UserDomain
{

    public function updateProfile(string $name, string $email)
    {
        $this->model->name = $name;
        $this->model->email = $email;
        $this->model->save();
    }

}

如果使用属性很重要,正如您在评论中所假设的那样,我宁愿使用Properties的Yii实现。对于电子邮件,代码将如下所示:

 /**
 * Class UserDomain
 *
 * @property string email
 */
class UserDomain extends \yii\base\Object
{

    public function setEmail(string $email)
    {
        $this->model->email = trim($email);
    }

}

$userDomain = new UserDomain();
$userDomain->email = '11@gmail.com';

请注意,UserDomain已从\yii\base\Object扩展到可以设置setter。

自动设置ActiveRecord属性

如果你真的需要在域名图层中设置很多ActiveRecord属性,那么在我看来,根据属于域图层。在这种情况下,继承是良好决策,因为您正在使用业务逻辑扩展ActiveRecord的基本功能,而不是使用AR作为数据映射器。

这就是ActiveRecord的设计目标。因此,只要您的Domain层保持简洁明了,它就会非常方便和优化。