为应用程序配置中的所有模型全局附加行为(无继承)
Attach behavior globally for all models in application config (without inheritance)
我正在处理 Yii2 从主配置向 运行 添加 TimestampBehavior 的问题。原因是我必须在我的大多数模型的前端和后端使用它。
在模型中使用它很简单:
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => function(){ return date('Y-m-d H:i:s'); } ,
],
];
}
但是,如果我尝试在 main.php 中添加行为,则什么也不会发生。
我在想:
'as timestamp'=>[
'class'=> \yii\behaviors\TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => function(){ return date('Y-m-d H:i:s'); } ,
],
但是没用。有什么想法吗?
如果您不想使用继承,我可以建议您使用以下方法。
其背后的基本思想是使用 ActiveRecord
:
的事件
use yii\base\Event;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
...
$events = [ActiveRecord::EVENT_BEFORE_INSERT, ActiveRecord::EVENT_BEFORE_UPDATE];
foreach ($events as $eventName) {
Event::on(ActiveRecord::className(), $eventName, function ($event) {
$model = $event->sender;
if ($model->hasAttribute('created_at') && $model->hasAttribute('updated_at')) {
$model->attachBehavior('timestamp', [
'class' => TimestampBehavior::className(),
'value' => function () {
return date('Y-m-d H:i:s');
},
]);
}
});
}
此代码将动态附加 TimestampBehavior
到从 yii\db\ActiveRecord
继承的所有模型,然后再保存到数据库。
您也可以省略 createdAtAttribute
和 updatedAtAttribute
,因为默认情况下它们已经有了这些名称(因为它最常见)。
如您所见,仅当 created_at
和 updated_at
属性都存在时才会附加行为,无需为此创建扩展行为。
为避免继承,应将此代码复制/粘贴到每个应用程序 运行 bootstrap。
您可以立即将其添加到入口脚本(在应用程序 运行 之前),它会起作用,但将其放置在这里不是一个好习惯,而且这些文件是自动生成的并且在 git 忽略的文件列表。
因此您只需要创建一个包含该逻辑的单独组件并将其包含在配置中。无需扩展 类 等
假设它叫做 common\components\EventBootstrap
。它必须实现 BootstrapInterface
才能正常工作。
namespace common\components;
// Other namespaces from previous code
use yii\base\BootstrapInterface;
class EventBootstrap implements BootstrapInterface
{
public function bootstrap($app)
{
// Put the code above here
}
}
然后你需要将它包含在 bootstrap 部分的配置中:
return [
'bootstrap' => [
'common\components\EventBootstrap',
],
];
官方文档:
附加说明:我也尝试仅通过应用程序配置指定它,但没有成功。
我没有找到指定 ActiveRecord
的方法。
您可以看到 this question,但是那里的行为附加到整个应用程序,这可以通过配置实现。
我知道这是一个有点老的问题,但如果有人遇到同样的问题,我将分享我发现的简洁方法。我只是在特征中定义了一种行为。然后我只是在模型中使用该特征,仅此而已。它只在模型中添加一行,但它更干净,代码维护也更轻松。
这是样本特征
<?php
namespace common\traits;
use Yii;
use yii\behaviors\BlameableBehavior;
use yii\behaviors\TimestampBehavior;
trait Signature
{
public function behaviors()
{
return [
[
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'created_by',
'updatedByAttribute' => 'updated_by',
],
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' =>function(){
return time();
},
],
];
}
}
及型号代码
class Category extends \yii\db\ActiveRecord
{
use \common\traits\Signature;
// Model code here
}
我正在处理 Yii2 从主配置向 运行 添加 TimestampBehavior 的问题。原因是我必须在我的大多数模型的前端和后端使用它。
在模型中使用它很简单:
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => function(){ return date('Y-m-d H:i:s'); } ,
],
];
}
但是,如果我尝试在 main.php 中添加行为,则什么也不会发生。 我在想:
'as timestamp'=>[
'class'=> \yii\behaviors\TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => function(){ return date('Y-m-d H:i:s'); } ,
],
但是没用。有什么想法吗?
如果您不想使用继承,我可以建议您使用以下方法。
其背后的基本思想是使用 ActiveRecord
:
use yii\base\Event;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
...
$events = [ActiveRecord::EVENT_BEFORE_INSERT, ActiveRecord::EVENT_BEFORE_UPDATE];
foreach ($events as $eventName) {
Event::on(ActiveRecord::className(), $eventName, function ($event) {
$model = $event->sender;
if ($model->hasAttribute('created_at') && $model->hasAttribute('updated_at')) {
$model->attachBehavior('timestamp', [
'class' => TimestampBehavior::className(),
'value' => function () {
return date('Y-m-d H:i:s');
},
]);
}
});
}
此代码将动态附加 TimestampBehavior
到从 yii\db\ActiveRecord
继承的所有模型,然后再保存到数据库。
您也可以省略 createdAtAttribute
和 updatedAtAttribute
,因为默认情况下它们已经有了这些名称(因为它最常见)。
如您所见,仅当 created_at
和 updated_at
属性都存在时才会附加行为,无需为此创建扩展行为。
为避免继承,应将此代码复制/粘贴到每个应用程序 运行 bootstrap。
您可以立即将其添加到入口脚本(在应用程序 运行 之前),它会起作用,但将其放置在这里不是一个好习惯,而且这些文件是自动生成的并且在 git 忽略的文件列表。
因此您只需要创建一个包含该逻辑的单独组件并将其包含在配置中。无需扩展 类 等
假设它叫做 common\components\EventBootstrap
。它必须实现 BootstrapInterface
才能正常工作。
namespace common\components;
// Other namespaces from previous code
use yii\base\BootstrapInterface;
class EventBootstrap implements BootstrapInterface
{
public function bootstrap($app)
{
// Put the code above here
}
}
然后你需要将它包含在 bootstrap 部分的配置中:
return [
'bootstrap' => [
'common\components\EventBootstrap',
],
];
官方文档:
附加说明:我也尝试仅通过应用程序配置指定它,但没有成功。
我没有找到指定 ActiveRecord
的方法。
您可以看到 this question,但是那里的行为附加到整个应用程序,这可以通过配置实现。
我知道这是一个有点老的问题,但如果有人遇到同样的问题,我将分享我发现的简洁方法。我只是在特征中定义了一种行为。然后我只是在模型中使用该特征,仅此而已。它只在模型中添加一行,但它更干净,代码维护也更轻松。
这是样本特征
<?php
namespace common\traits;
use Yii;
use yii\behaviors\BlameableBehavior;
use yii\behaviors\TimestampBehavior;
trait Signature
{
public function behaviors()
{
return [
[
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'created_by',
'updatedByAttribute' => 'updated_by',
],
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' =>function(){
return time();
},
],
];
}
}
及型号代码
class Category extends \yii\db\ActiveRecord
{
use \common\traits\Signature;
// Model code here
}