如何在使用活动记录的框架中实现模型工厂?

时间:2019-02-12 10:34:21

标签: php activerecord factory phalcon

因此,在我的框架X中,让它成为 Phalcon ,我经常创建模型对象。

  

让我们假设所有字段均已验证。问题仅与创建逻辑有关。

创建 Users 对象并将其保存到DB的简单示例:

<?php

$user = new Users();
$user->setName($name);
$user->setLastName($lastname);
$user->setAge($age);
$user->create();

为简单起见,我在这里仅显示3个要设置的字段,在现实世界中,它们总是更多。

我有3个问题:

1)在 Factory 类中封装此逻辑的最佳方法是什么?如果我创建 Factory 类,该类将创建诸如 Users 对象之类的对象,则每次我都需要传递大量参数。

示例:

<?php

$factory = new UsersFactory();
$factory->make($name, $lastname, $address, $phone, $status, $active);

2)即使我以上述方式实现 Factory - Factory 是否应在数据库中插入数据?在我的示例调用方法 create()中?还是只执行所有的二传手操作?

3)还有,如果我需要创建具有关联性的 Users 对象以及其他相关对象怎么办?

谢谢您的任何建议。

2 个答案:

答案 0 :(得分:0)

您的问题从简单开始,然后复杂起来。阅读您的帖子听起来就像您担心必须传递给方法以构建对象的参数数量。这是一种合理的担心,因为您应该尝试避免使用超过2或3个arg的函数,并且因为有时您需要传递第1个第3和第5个arg而不是第2和第4个arg,而这只会使您感到不舒服。

相反,我鼓励您看一下构建器模式。

最后,与直接使用User对象并没有什么不同,但是它将帮助您防止User对象处于无效状态(未设置必填字段)

  

1)在Factory类中封装此逻辑的最佳方法是什么?如果我创建Factory类来创建类似于Users对象的对象,那么每次我都需要传递大量参数。

这就是为什么我推荐构建器模式的原因。为了避免将大量参数传递给单个函数。它还可以让您验证build方法中的状态并处理或引发异常。

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)即使我以上述方式实现Factory-Factory是否应在DB中插入数据?在我的示例中,调用方法create()?还是只执行所有的二传手操作?

否,不应插入。它应该只是帮助您构建对象,而不是假设您将如何处理它。您可能会释放它,一旦构建它,您将需要在插入之前对其进行其他操作。

  

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模型的工作原理。

答案 1 :(得分:0)

我认为不必完全使用构建器或“模式”来动态填充模型属性。虽然这取决于您所追求的。

您可以像这样通过构造函数填充模型

$user = new Users([
    'name' => $name,
    'lastName' => $lastname,
    'age' => $age,
]);
$user->create();

这样,您可以通过构建数组而不是大量方法调用来动态填充模型。


还值得注意的是,如果要使用“ setters”和“ 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方法,则无法将值分配给受保护的模型属性。