跳转到内容

模型行为


概览

行为是多个模型可以采用的共享构造,以复用代码。虽然你可以使用特性来复用代码,但行为有更多优点使它们更吸引人。特性要求你必须使用完全相同的字段名以便通用代码生效。而行为更加灵活。

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,
                ]
            )
        );
    }
}

此行为接受两个选项:fieldvalue, 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)

如果我们删除其中任意一条记录,状态会被更新而不是真正删除记录:

<?php

Invoices::findFirst(2)->delete();

该操作将在表中生成以下数据:

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要求你的自定义行为中存在两个方法:

public function missingMethod(
    ModelInterface $model, 
    string $method, 
    array $arguments = []
)

当调用模型上不存在的方法时,此方法充当回退。

public function notify(
    string $type, 
    ModelInterface $model
)

此方法接收来自事件管理器.

的通知。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 友好的标题:

<?php

$title = $invoice->getSlug();

特性

你可以使用特性在类中复用代码,这是实现自定义行为的另一种方式。下面的特性实现了一个简单版本的Timestampable行为:

<?php

trait Timestampable
{
    public function beforeCreate()
    {
        $this->inv_created_at = date('r');
    }

    public function beforeUpdate()
    {
        $this->inv_updated_at = date('r');
    }
}

然后你可以在模型中按以下方式使用它:

<?php

use Phalcon\Mvc\Model;

class Invoices extends Model
{
    use Timestampable;
}

注意

你可以使用特性代替行为,但它们要求所有可能受影响的字段必须具有相同名称。此外,如果你在一个特性中实现了事件方法(例如beforeCreate),则不能再在模型中实现它,因为两者会产生冲突错误。

无噪 Logo
无噪文档
25 年 6 月翻译
文档源↗