我使用yii2并发现它的活动记录非常方便。
但有时我发现我们总是把逻辑函数放在活动记录中,我认为它应该属于域。
我查了一些书,其中大部分建议使用数据映射器将数据库记录映射到域。
虽然这是分割域和数据的好方法,但我不想浪费yii2的活动记录功能。
我认为我们可以从活动记录扩展域,以便数据库操作将在域的父类活动记录中,业务逻辑操作将在域中:
class UserModel extends ActiveRecord{
// do database operations
}
class UserDomain extends UserModel{
// do domain's logic
}
我不知道这个设计很棒吗?请告诉我你的建议。
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;
}
}
}
答案 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
的基本功能,而不是使用AR作为数据映射器。
这就是ActiveRecord
的设计目标。因此,只要您的Domain层保持简洁明了,它就会非常方便和优化。