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 ...
随机推荐
- BZOJ 3993 [SDOI 2015] 星际战争 解题报告
首先我们可以二分答案. 假设当前二分出来的答案是 $Ans$ ,那么我们考虑用网络流检验: 设武器为 $X$,第 $i$ 个武器的攻击力为 $B_i$: 设机器人为 $Y$,第 $i$ 个机器人的装甲 ...
- 如何从软硬件层面提升 Android 动画性能?
若是有人问如何解决动画性能不佳的问题,Dan Lew Codes 总会反问:你是否使用了硬件层? 动画放映过程中每帧画面可能都要重绘.如果使用视图层,,渲染过的视图可以存入离屏缓存以待将来重用,而无需 ...
- Memcached总结三:Memcached常用命令及使用说明
一.存储命令 存储命令的格式: 1 2 <command name> <key> <flags> <exptime> <bytes> < ...
- 李洪强漫谈iOS开发[C语言-020]-scanf的本质
scanf是有返回值和参数的
- 字符串相似度算法(编辑距离算法 Levenshtein Distance)
在搞验证码识别的时候需要比较字符代码的相似度用到“编辑距离算法”,关于原理和C#实现做个记录.据百度百科介绍:编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串 ...
- SPRING IN ACTION 第4版笔记-第三章ADVANCING WIRING-008-SpEL介绍
一. 1.SpEL expressions are framed with #{ ... } 2.SpEl的作用 Sp EL has a lot of tricks up its sleeves, ...
- linux下 修改配置文件的命令
vi或vim 进入后,按i,屏幕下方会出现INSERT字样,此时可以修改内容 按ESC,退回命令模式 :x是保存退出 :q!是不保存退出
- 【HDOJ】1857 Word Puzzle
trie树.以puzzle做trie树内存不够,从puzzle中直接找串应该会TLE.其实可以将查询组成trie树,离线做.扫描puzzle时注意仅三个方向即可. /* 1857 */ #includ ...
- 安装db2 提示不是有效的win32应用程序?
问题已经解决了,就是版本的问题.我在官网上下载的最新版本(10.5),网上说是最新的版本不支持xp系统,完了我下了9.7的版本,安装没有一点点问题
- Java 异常类层次结构
在Java中,异常分为受检查的异常,与运行时异常. 两者都在异常类层次结构中. 下面的图展示了Java异常类的继承关系. 图1 粉红色的是受检查的异常(checked exceptions),其必须被 ...