模型行为¶
概览¶
行为是多个模型可以采用的共享构造,以复用代码。虽然你可以使用特性来复用代码,但行为有更多优点使它们更吸引人。特性要求你必须使用完全相同的字段名以便通用代码生效。而行为更加灵活。
ORM 提供了一个 API 用于在模型中实现行为。此外,你可以使用前面提到的事件和回调作为另一种实现行为的方式。
行为必须在模型初始化器中添加,一个模型可以有零个或多个行为:
<?php
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Behavior\Timestampable;
class Invoices extends Model
{
/**
* @var int
*/
public $inv_id;
/**
* @var string
*/
public $inv_created_at;
/**
* @var int
*/
public $inv_status_flag;
/**
* @var string
*/
public $inv_title;
public function initialize()
{
$this->addBehavior(
new Timestampable(
[
'beforeCreate' => [
'field' => 'inv_created_at',
'format' => 'Y-m-d',
],
]
)
);
}
}
内置¶
框架提供了以下内置行为:
名称 | 描述 |
---|---|
软删除 | 不会永久删除记录,而是通过更改标志列的值来标记记录为已删除 |
时间戳功能 | 允许自动更新模型的属性,保存记录创建或更新时的时间 |
时间戳功能¶
此行为接收一个选项数组,第一级键必须是事件名称,指示何时分配列:
<?php
use Phalcon\Mvc\Model\Behavior\Timestampable;
public function initialize()
{
$this->addBehavior(
new Timestampable(
[
'beforeCreate' => [
'field' => 'inv_created_at',
'format' => 'Y-m-d',
],
]
)
);
}
每个事件可以有自己的选项,field
是需要更新的列的名称,如果format
是字符串,则它将用作日期函数的格式。format
还可以是一个匿名函数,提供生成任何类型时间戳字符串的额外功能:
<?php
use DateTime;
use DateTimeZone;
use Phalcon\Mvc\Model\Behavior\Timestampable;
public function initialize()
{
$this->addBehavior(
new Timestampable(
[
'beforeCreate' => [
'field' => 'inv_created_at',
'format' => function () {
$datetime = new Datetime(
new DateTimeZone('Europe/Stockholm')
);
return $datetime->format('Y-m-d H:i:sP');
},
],
]
)
);
}
如果省略了format
选项,则会使用 PHP 的time函数生成时间戳。
软删除¶
此行为可以按以下方式使用:
<?php
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class Invoices extends Model
{
const ACTIVE = 1;
const INACTIVE = 0;
/**
* @var int
*/
public $inv_id;
/**
* @var string
*/
public $inv_created_at;
/**
* @var int
*/
public $inv_deleted_flag;
/**
* @var string
*/
public $inv_title;
public function initialize()
{
$this->addBehavior(
new SoftDelete(
[
'field' => 'inv_deleted_flag',
'value' => Invoices::INACTIVE,
]
)
);
}
}
此行为接受两个选项:field
和value
, field
确定哪个字段需要更新,并且value
是要删除的值。假设我们的表有以下行:
mysql> select * from co_invoices;
+--------+------------------+-----------------------------+
| inv_id | inv_deleted_flag | inv_title |
+--------+------------------+-----------------------------+
| 1 | 0 | Invoice for ACME Inc. |
| 2 | 0 | Invoice for Spaceballs Inc. |
+--------+------------------+-----------------------------+
2 rows in set (0.00 sec)
如果我们删除其中任意一条记录,状态会被更新而不是真正删除记录:
该操作将在表中生成以下数据:
mysql> select * from co_invoices;
+--------+------------------+-----------------------------+
| inv_id | inv_deleted_flag | inv_title |
+--------+------------------+-----------------------------+
| 1 | 0 | Invoice for ACME Inc. |
| 2 | 1 | Invoice for Spaceballs Inc. |
+--------+------------------+-----------------------------+
2 rows in set (0.00 sec)
注意
你需要确保指定已删除条件来过滤你的记录,以便获取已删除或未删除的结果。此行为不支持自动过滤。
注意
在模型中添加此行为会阻止其afterDelete事件被触发,因为记录实际上并未被删除。
自定义¶
ORM 提供了一个 API 用于创建你自己的行为。行为必须是一个类,实现Phalcon\Mvc\Model\BehaviorInterface或扩展Phalcon\Mvc\Model\Behavior,后者暴露了实现自定义行为所需的大多数方法。
The Phalcon\Mvc\Model\BehaviorInterface要求你的自定义行为中存在两个方法:
当调用模型上不存在的方法时,此方法充当回退。
此方法接收来自事件管理器.
的通知。Phalcon\Mvc\Model\Behavior此外,如果你扩展
方法 | 描述 |
---|---|
getOptions(string $eventName = null) | Returns the behavior options related to an event |
mustTakeAction(string $eventName) | 检查行为是否应在某些事件上采取行动。 |
返回与事件相关的行为选项。Blameable
行为,有助于识别对模型执行操作的用户:
<?php
use Phalcon\Di\Di;
use Phalcon\Mvc\ModelInterface;
use Phalcon\Mvc\Model\Behavior;
class Blameable extends Behavior
{
public function notify(string $eventType, ModelInterface $model)
{
$container = Di::getDefault();
$userName = $container->get('auth')->getFullName();
switch ($eventType) {
case 'afterCreate':
case 'afterDelete':
case 'afterUpdate':
file_put_contents(
'logs/blamable-log.txt',
$userName . ' ' . $eventType . ' ' . $model->inv_id
);
break;
default:
// ...
}
}
}
上述是一个非常简单的行为,但它说明了如何创建行为。下面展示了如何将行为添加到模型中:
<?php
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public function initialize()
{
$this->addBehavior(
new Blameable()
);
}
}
行为还可以拦截模型上缺少的方法,并为其提供功能:
<?php
use Phalcon\Tag;
use Phalcon\Mvc\ModelInterface;
use Phalcon\Mvc\Model\Behavior;
use Phalcon\Mvc\Model\BehaviorInterface;
class Sluggable extends Behavior
{
public function missingMethod(
ModelInterface $model,
string $method,
$arguments = []
) {
if ($method === 'getSlug') {
return Tag::friendlyTitle($model->title);
}
}
}
在实现了Sluggable
的模型上调用该方法返回一个 SEO 友好的标题:
特性¶
你可以使用特性在类中复用代码,这是实现自定义行为的另一种方式。下面的特性实现了一个简单版本的Timestampable
行为:
<?php
trait Timestampable
{
public function beforeCreate()
{
$this->inv_created_at = date('r');
}
public function beforeUpdate()
{
$this->inv_updated_at = date('r');
}
}
然后你可以在模型中按以下方式使用它:
注意
你可以使用特性代替行为,但它们要求所有可能受影响的字段必须具有相同名称。此外,如果你在一个特性中实现了事件方法(例如beforeCreate
),则不能再在模型中实现它,因为两者会产生冲突错误。