Yii2 TimestampBehavior行为
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/ namespace yii\behaviors; use yii\base\InvalidCallException;
use yii\db\BaseActiveRecord; /**
* TimestampBehavior automatically fills the specified attributes with the current timestamp.
*
* To use TimestampBehavior, insert the following code to your ActiveRecord class:
*
* ```php
* use yii\behaviors\TimestampBehavior;
*
* public function behaviors()
* {
* return [
* TimestampBehavior::className(),
* ];
* }
* ```
*
* By default, TimestampBehavior will fill the `created_at` and `updated_at` attributes with the current timestamp
* when the associated AR object is being inserted; it will fill the `updated_at` attribute
* with the timestamp when the AR object is being updated. The timestamp value is obtained by `time()`.
*
* Because attribute values will be set automatically, it's a good idea to make sure `created_at` and `updated_at` aren't
* in `rules()` method of the model.
*
* For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp.
*
* If your attribute names are different or you want to use a different way of calculating the timestamp,
* you may configure the [[createdAtAttribute]], [[updatedAtAttribute]] and [[value]] properties like the following:
*
* ```php
* use yii\db\Expression;
*
* public function behaviors()
* {
* return [
* [
* 'class' => TimestampBehavior::className(),
* 'createdAtAttribute' => 'create_time',
* 'updatedAtAttribute' => 'update_time',
* 'value' => new Expression('NOW()'),
* ],
* ];
* }
* ```
*
* In case you use an [[\yii\db\Expression]] object as in the example above, the attribute will not hold the timestamp value, but
* the Expression object itself after the record has been saved. If you need the value from DB afterwards you should call
* the [[\yii\db\ActiveRecord::refresh()|refresh()]] method of the record.
*
* TimestampBehavior also provides a method named [[touch()]] that allows you to assign the current
* timestamp to the specified attribute(s) and save them to the database. For example,
*
* ```php
* $model->touch('creation_time');
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0
*/
class TimestampBehavior extends AttributeBehavior
{
/**
* @var string the attribute that will receive timestamp value
* Set this property to false if you do not want to record the creation time.
*/
public $createdAtAttribute = 'created_at';
/**
* @var string the attribute that will receive timestamp value.
* Set this property to false if you do not want to record the update time.
*/
public $updatedAtAttribute = 'updated_at';
/**
* @inheritdoc
*
* In case, when the value is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
* will be used as value.
*/
public $value; /**
* @inheritdoc
*/
public function init()
{
parent::init(); if (empty($this->attributes)) {
$this->attributes = [
BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
];
}
} /**
* @inheritdoc
*
* In case, when the [[value]] is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
* will be used as value.
*/
protected function getValue($event)
{
if ($this->value === null) {
returntime();
}
return parent::getValue($event);
} /**
* Updates a timestamp attribute to the current timestamp.
*
* ```php
* $model->touch('lastVisit');
* ```
* @param string $attribute the name of the attribute to update.
* @throws InvalidCallException if owner is a new record (since version 2.0.6).
*/
public function touch($attribute)
{
/* @var $owner BaseActiveRecord */
$owner = $this->owner;
if ($owner->getIsNewRecord()) {
throw new InvalidCallException('Updating the timestamp is not possible on a new record.');
}
$owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
}
}
TimestampBehavior 里面的public function init(){}初始化绑定事件处理的方法数据
/**
* @inheritdoc
*/
public function init()
{
parent::init(); if (empty($this->attributes)) {
$this->attributes = [
BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
];
}
}
TimestampBehavior 父级AttributeBehavior 里面events()方法 为事件绑定执行handle :evaluateAttributes方法
/**
* @inheritdoc
*/
public function events()
{
return array_fill_keys(
array_keys($this->attributes),
'evaluateAttributes'
);
}
事件绑定的方法:evaluateAttributes方法,
/**
* Evaluates the attribute value and assigns it to the current attributes.
* @param Event $event
*/
public function evaluateAttributes($event)
{
if ($this->skipUpdateOnClean
&& $event->name == ActiveRecord::EVENT_BEFORE_UPDATE
&& empty($this->owner->dirtyAttributes)
) {
return;
} if (!empty($this->attributes[$event->name])) {
$attributes = (array) $this->attributes[$event->name];
$value = $this->getValue($event);
foreach ($attributes as $attribute) {
// ignore attribute names which are not string (e.g. when set by TimestampBehavior::updatedAtAttribute)
if (is_string($attribute)) {
$this->owner->$attribute = $value;
}
}
}
}
当update 或者insert save数据时候,BaseActiveRecord.php 里面的save():
/**
* Saves the current record.
*
* This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]]
* when [[isNewRecord]] is false.
*
* For example, to save a customer record:
*
* ```php
* $customer = new Customer; // or $customer = Customer::findOne($id);
* $customer->name = $name;
* $customer->email = $email;
* $customer->save();
* ```
*
* @param boolean $runValidation whether to perform validation (calling [[validate()]])
* before saving the record. Defaults to `true`. If the validation fails, the record
* will not be saved to the database and this method will return `false`.
* @param array $attributeNames list of attribute names that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the saving succeeded (i.e. no validation errors occurred).
*/
public function save($runValidation = true, $attributeNames = null)
{
if ($this->getIsNewRecord()) {
return $this->insert($runValidation, $attributeNames);
} else {
return $this->update($runValidation, $attributeNames) !== false;
}
}
调用ActiveRecord.php 里面的insert() 和update ():
public function insert($runValidation = true, $attributes = null)
{
if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not inserted due to validation error.', __METHOD__);
return false;
} if (!$this->isTransactional(self::OP_INSERT)) {
return $this->insertInternal($attributes);
} $transaction = static::getDb()->beginTransaction();
try {
$result = $this->insertInternal($attributes);
if ($result === false) {
$transaction->rollBack();
} else {
$transaction->commit();
}
return $result;
} catch (\Exception $e) {
$transaction->rollBack();
throw $e;
}
}
public function update($runValidation = true, $attributeNames = null)
{
if ($runValidation && !$this->validate($attributeNames)) {
Yii::info('Model not updated due to validation error.', __METHOD__);
return false;
} if (!$this->isTransactional(self::OP_UPDATE)) {
return $this->updateInternal($attributeNames);
} $transaction = static::getDb()->beginTransaction();
try {
$result = $this->updateInternal($attributeNames);
if ($result === false) {
$transaction->rollBack();
} else {
$transaction->commit();
}
return $result;
} catch (\Exception $e) {
$transaction->rollBack();
throw $e;
}
}
调用ActiveRecord.php 里面insertInternal() 和updateInternal():
/**
* Inserts an ActiveRecord into DB without considering transaction.
* @param array $attributes list of attributes that need to be saved. Defaults to null,
* meaning all attributes that are loaded from DB will be saved.
* @return boolean whether the record is inserted successfully.
*/
protected function insertInternal($attributes = null)
{
if (!$this->beforeSave(true)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
if (($primaryKeys = static::getDb()->schema->insert(static::tableName(), $values)) === false) {
return false;
}
foreach ($primaryKeys as $name => $value) {
$id = static::getTableSchema()->columns[$name]->phpTypecast($value);
$this->setAttribute($name, $id);
$values[$name] = $id;
} $changedAttributes = array_fill_keys(array_keys($values), null);
$this->setOldAttributes($values);
$this->afterSave(true, $changedAttributes); return true;
}
/**
* @see update()
* @param array $attributes attributes to update
* @return integer number of rows updated
* @throws StaleObjectException
*/
protected function updateInternal($attributes = null)
{
if (!$this->beforeSave(false)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
$this->afterSave(false, $values);
return 0;
}
$condition = $this->getOldPrimaryKey(true);
$lock = $this->optimisticLock();
if ($lock !== null) {
$values[$lock] = $this->$lock + 1;
$condition[$lock] = $this->$lock;
}
// We do not check the return value of updateAll() because it's possible
// that the UPDATE statement doesn't change anything and thus returns 0.
$rows = static::updateAll($values, $condition); if ($lock !== null && !$rows) {
throw new StaleObjectException('The object being updated is outdated.');
} if (isset($values[$lock])) {
$this->$lock = $values[$lock];
} $changedAttributes = [];
foreach ($values as $name => $value) {
$changedAttributes[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
$this->_oldAttributes[$name] = $value;
}
$this->afterSave(false, $changedAttributes); return $rows;
}
调用BaseActiveRecord.php 里面的beforeSave(),触发$this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event)事件执行添加之前绑定的事件方法evaluateAttributes自动相关添加属性值:
public function beforeSave($insert)
{
$event = new ModelEvent;
$this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event); return $event->isValid;
}
}
Yii2 TimestampBehavior行为的更多相关文章
- Yii2 TimestampBehavior 用来自动给指定的属性填充当前时间戳
要使用 TimestampBehavior,把下面的代码加到你的 ActiveRecord 类中: use yii\behaviors\TimestampBehavior; public functi ...
- Yii2的深入学习--行为Behavior
我们先来看下行为在 Yii2 中的使用,如下内容摘自 Yii2中文文档 行为是 [[yii\base\Behavior]] 或其子类的实例.行为,也称为 mixins,可以无须改变类继承关系即可增强一 ...
- Yii2框架RESTful API教程(二) - 格式化响应,授权认证和速率限制
之前写过一篇Yii2框架RESTful API教程(一) - 快速入门,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分 一.目录结构 先列出需要改动的文件.目录如下 ...
- yii2 小技巧
参考地址:http://www.cnblogs.com/sandea/p/5714830.html 1.不通过日志获取AR执行的原生SQL语句和打印变量数据 $query = User::find() ...
- YII2项目常用技能知识总结
1.不通过日志获取AR执行的原生SQL语句和打印变量数据 $query = User::find() ->select(['username'])->where(['id'=>[1, ...
- 忘记时间戳的存在——Yii2超实用的自动更新时间戳的Behavior(改进版)
本文改进了Yii2中内置行为类TimestampBehavior,使得时间戳字段(如created_at,updated_at) 完全自己更新,方便得让你忘记它们的存在. Yii2的内置行为类Time ...
- Yii2基本概念之——行为(Behavior)
使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充.通过将行为绑定到一个类,可以使得类具有行为本身所具有的属性和方法,就好像是类本来就具有的这些属性和功能一样. 好的代码设计, ...
- Yii2 Restful api设计--App接口编程
Yii2框架写一套RESTful风格的API,对照魏曦教你学 一,入门 一.目录结构 实现一个简单地RESTful API只需用到三个文件.目录如下: frontend ├─ config │ └ m ...
- Yii2框架RESTful API教程
前不久做一个项目,是用Yii2框架写一套RESTful风格的API,就去查了下<Yii 2.0 权威指南 >,发现上面写得比较简略.所以就在这里写一篇教程贴,希望帮助刚接触Yii2框架RE ...
随机推荐
- Oracle的登录操作
在完美的启动Oracle数据库之后就可以登录数据库了: 1. 首先登录时使用的用户名默认是“SYSTEM”密码是你安装的时候自行设置的. 登录使用的命令是“sqlplus / as sysdba”之后 ...
- unity 嵌入 百度分享 与 游戏内购物 iap
原地址:http://blog.csdn.net/u012085988/article/details/18268869 最近老板让在unity项目里实现分享与内购功能,还要ios和android两个 ...
- HDU 2985 Another lottery(坑题)
点我看题目 题意 : 有n个人,每个人可以玩m轮,每一轮中每个参与者都有cj张票,第 i 轮的奖金是2的i次方,问你每个人所能赢得最多的奖金的概率是多少. 思路 : 这个题比较坑啊,其实不用去算前几轮 ...
- 利用ZABBIX的RPC-JSON作API扩展应用示例
计划将ZABBIX的一些状态可以在另一个应用的显示GRAPH及链接. 故而在网上找了几个文档,作了一个测试. https://www.zabbix.com/documentation/2.4/manu ...
- 告别山寨数据线:USB Type-C加密认证出炉
从去年苹果发布的MacBook首次采用USB Type-C接口开始,这一标准逐渐成为主流,许多旗舰手机慢慢地采用了这种接口.今日,非盈利机构USB开发者论坛(USB-IF)宣布了USB Type-C认 ...
- USB Type-C,接口上的大统一?
这款 24-pin 连接器的机械设计反应了设计人员从 Micro-B 连接器上获得的历史教训,它无需确定插入的正反方向并可实现 10000 次的插拔.使用者再也不需要担心“哪头上,哪头下”,因为 US ...
- OpenSSH for Windows,CopSSH
https://www.oschina.net/p/openssh+for+windows https://www.oschina.net/p/copssh
- 存储过程系列之存储过程sql查询存储过程的使用
1.查询某个表被哪些存储过程(以下简称 SP)使用到 : select distinct object_name(id) from syscomments where id in (select ob ...
- 开源的文件比较工具:WinMerge,KDiff3,diffuse
为了寻找免费的BeyondCompare的替代品,最后经过实用,找到如下一些: 1.diffuse 感受:如果仅仅是比较两个文本类的文件,这个软件也就够用了. 安装好后,对着文件点击右键,会出现&qu ...
- Android开发之启动Activity的最佳写法
从MainActivity跳转到SecondActivity 在SecondActivity中,写一个静态方法actionStart() public static void actionStart( ...