所以,在我的框架X中,让它成为Phalcon,我经常创建模型对象。
我们假设所有字段都已经过验证。问题仅与创建逻辑有关。
创建Users对象并将其保存到DB的简单示例:
<?php
$user = new Users();
$user->setName($name);
$user->setLastName($lastname);
$user->setAge($age);
$user->create();
为简单起见,我在这里只显示了3个要设置的字段,在现实世界中它们总是更多。
我有3个问题:
1)在Factory类中封装此逻辑的最佳方法是什么?如果我创建将创建像Users对象的Factory类,每次我需要传递大量参数。
例:
<?php
$factory = new UsersFactory();
$factory->make($name, $lastname, $address, $phone, $status, $active);
2)即使我以上面显示的方式实现工厂 - 工厂是否应该在DB中插入数据?在我的示例中调用方法create()?或者只是执行所有的setter操作?
3)甚至更多,如果我需要创建具有关系的Users对象,以及其他相关对象,该怎么办?
谢谢你的任何建议。
您的问题开始很简单,然后构建复杂。阅读你的帖子听起来就像你担心你必须传递给构建对象的方法的参数数量。这是一个合理的恐惧,因为你应该尽量避免使用超过2或3个args的函数,并且因为有时候你需要通过第1和第3个arg而不是第2和第4个让它感到不舒服。
我会鼓励你看看构建器模式。
最后它与直接使用你的User
对象没有那么大的不同,但它会帮助你防止User
对象处于无效状态(必需字段未设置)
1)在Factory类中封装此逻辑的最佳方法是什么?如果我创建将创建像Users对象的Factory类,每次我需要传递大量参数。
这就是我推荐构建器模式的原因。避免将大量参数传递给单个函数。它还允许您在构建方法中验证状态并处理或抛出异常。
class UserBuilder {
protected $data = [];
public static function named($fname, $lname) {
$b = new static;
return $b
->withFirstName($fname)
->withLastName($lname);
}
public function withFirstName($fname) {
$this->data['first_name'] = $fname;
return $this;
}
public function withFirstName($lname) {
$this->data['last_name'] = $lname;
return $this;
}
public function withAge($age) {
$this->data['age'] = $age;
return $this;
}
public function build() {
$this->validate();
$d = $this->data;
$u = new User;
$u->setFirstName($d['first_name']);
$u->setLastName($d['last_name']);
$u->setAge($d['age']);
return $u;
}
protected function validate() {
$d = $this->data;
if (empty($d['age'])) {
throw new Exception('age is required');
}
}
}
那你就做..
$user = UserBuilder::named('John','Doe')->withAge(32);
现在,代替每个参数增加的函数参数的数量,方法的数量增加。
2)即使我以上面显示的方式实现工厂 - 工厂是否应该在DB中插入数据?在我的示例中调用方法create()?或者只是执行所有的setter操作?
不,它不应该插入。它应该只是帮助你构建对象,而不是假设你将如何处理它。你可以释放一旦你构建它,你将需要在插入之前用它做一些其他事情。
3)甚至更多,如果我需要创建具有关系的Users对象,以及其他相关对象,该怎么办?
在Phalcon中,这些关系是实体的一部分。你可以在their docs这个例子中看到:
// Create an artist
$artist = new Artists();
$artist->name = 'Shinichi Osawa';
$artist->country = 'Japan';
// Create an album
$album = new Albums();
$album->name = 'The One';
$album->artist = $artist; // Assign the artist
$album->year = 2008;
// Save both records
$album->save();
因此,为了将此与用户示例相关联,假设您希望在用户上存储地址信息,但地址存储在不同的表中。构建器可以公开定义地址的方法,构建方法将同时创建两个实体,并返回构建的User对象,该对象在其中具有对Address对象的引用,因为Phalcon模型的工作方式。
我不认为使用构建器或“模式”动态填充模型属性是完全必要的。虽然你所追求的是主观的。
您可以像这样通过构造函数填充模型
$user = new Users([
'name' => $name,
'lastName' => $lastname,
'age' => $age,
]);
$user->create();
这样,您可以通过构建数组而不是多次方法调用来动态填充模型。
值得注意的是,如果你想使用“setter”和“getter”方法,你应该将属性定义为protected
。这样做的原因是,当您为受保护的属性赋值时,Phalcon会自动调用set
/ get
方法。
例如:
class User extends \Phalcon\Mvc\Model
{
protected $name;
public function setName(string $name): void
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
$user= new MyModel();
$user->name = 'Cameron'; // This will invoke User::setName
echo $user->name; // This will invoke User::getName
值得注意的是,如果缺少相应的方法,属性将表现为您希望受保护属性的行为与传统受保护属性相同。例如,如果没有setter方法,则无法将值分配给受保护的模型属性。