Yii2 TimestampBehavior行为

  1 <?php
  2 /**
  3  * @link http://www.yiiframework.com/
  4  * @copyright Copyright (c) 2008 Yii Software LLC
  5  * @license http://www.yiiframework.com/license/
  6  */
  7 
  8 namespace yii\behaviors;
  9 
 10 use yii\base\InvalidCallException;
 11 use yii\db\BaseActiveRecord;
 12 
 13 /**
 14  * TimestampBehavior automatically fills the specified attributes with the current timestamp.
 15  *
 16  * To use TimestampBehavior, insert the following code to your ActiveRecord class:
 17  *
 18  * ```php
 19  * use yii\behaviors\TimestampBehavior;
 20  *
 21  * public function behaviors()
 22  * {
 23  *     return [
 24  *         TimestampBehavior::className(),
 25  *     ];
 26  * }
 27  * ```
 28  *
 29  * By default, TimestampBehavior will fill the `created_at` and `updated_at` attributes with the current timestamp
 30  * when the associated AR object is being inserted; it will fill the `updated_at` attribute
 31  * with the timestamp when the AR object is being updated. The timestamp value is obtained by `time()`.
 32  *
 33  * Because attribute values will be set automatically, it's a good idea to make sure `created_at` and `updated_at` aren't
 34  * in `rules()` method of the model.
 35  *
 36  * For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp.
 37  *
 38  * If your attribute names are different or you want to use a different way of calculating the timestamp,
 39  * you may configure the [[createdAtAttribute]], [[updatedAtAttribute]] and [[value]] properties like the following:
 40  *
 41  * ```php
 42  * use yii\db\Expression;
 43  *
 44  * public function behaviors()
 45  * {
 46  *     return [
 47  *         [
 48  *             'class' => TimestampBehavior::className(),
 49  *             'createdAtAttribute' => 'create_time',
 50  *             'updatedAtAttribute' => 'update_time',
 51  *             'value' => new Expression('NOW()'),
 52  *         ],
 53  *     ];
 54  * }
 55  * ```
 56  *
 57  * In case you use an [[\yii\db\Expression]] object as in the example above, the attribute will not hold the timestamp value, but
 58  * the Expression object itself after the record has been saved. If you need the value from DB afterwards you should call
 59  * the [[\yii\db\ActiveRecord::refresh()|refresh()]] method of the record.
 60  *
 61  * TimestampBehavior also provides a method named [[touch()]] that allows you to assign the current
 62  * timestamp to the specified attribute(s) and save them to the database. For example,
 63  *
 64  * ```php
 65  * $model->touch('creation_time');
 66  * ```
 67  *
 68  * @author Qiang Xue <qiang.xue@gmail.com>
 69  * @author Alexander Kochetov <creocoder@gmail.com>
 70  * @since 2.0
 71  */
 72 class TimestampBehavior extends AttributeBehavior
 73 {
 74     /**
 75      * @var string the attribute that will receive timestamp value
 76      * Set this property to false if you do not want to record the creation time.
 77      */
 78     public $createdAtAttribute = 'created_at';
 79     /**
 80      * @var string the attribute that will receive timestamp value.
 81      * Set this property to false if you do not want to record the update time.
 82      */
 83     public $updatedAtAttribute = 'updated_at';
 84     /**
 85      * @inheritdoc
 86      *
 87      * In case, when the value is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
 88      * will be used as value.
 89      */
 90     public $value;
 91 
 92 
 93     /**
 94      * @inheritdoc
 95      */
 96     public function init()
 97     {
 98         parent::init();
 99 
100         if (empty($this->attributes)) {
101             $this->attributes = [
102                 BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
103                 BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
104             ];
105         }
106     }
107 
108     /**
109      * @inheritdoc
110      *
111      * In case, when the [[value]] is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
112      * will be used as value.
113      */
114     protected function getValue($event)
115     {
116         if ($this->value === null) {
117             returntime(); 
118         }
119         return parent::getValue($event);
120     }
121 
122     /**
123      * Updates a timestamp attribute to the current timestamp.
124      *
125      * ```php
126      * $model->touch('lastVisit');
127      * ```
128      * @param string $attribute the name of the attribute to update.
129      * @throws InvalidCallException if owner is a new record (since version 2.0.6).
130      */
131     public function touch($attribute)
132     {
133         /* @var $owner BaseActiveRecord */
134         $owner = $this->owner;
135         if ($owner->getIsNewRecord()) {
136             throw new InvalidCallException('Updating the timestamp is not possible on a new record.');
137         }
138         $owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
139     }
140 }

TimestampBehavior 里面的public function init(){}初始化绑定事件处理的方法数据

 1 /**
 2      * @inheritdoc
 3      */
 4     public function init()
 5     {
 6         parent::init();
 7 
 8         if (empty($this->attributes)) {
 9             $this->attributes = [
10                 BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
11                 BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
12             ];
13         }
14     }

TimestampBehavior 父级AttributeBehavior 里面events()方法  为事件绑定执行handle :evaluateAttributes方法

 1 /**
 2      * @inheritdoc
 3      */
 4     public function events()
 5     {
 6         return array_fill_keys(
 7             array_keys($this->attributes),
 8             'evaluateAttributes'
 9         );
10     }

事件绑定的方法:evaluateAttributes方法,

 1  /**
 2      * Evaluates the attribute value and assigns it to the current attributes.
 3      * @param Event $event
 4      */
 5     public function evaluateAttributes($event)
 6     {
 7         if ($this->skipUpdateOnClean
 8             && $event->name == ActiveRecord::EVENT_BEFORE_UPDATE
 9             && empty($this->owner->dirtyAttributes)
10         ) {
11             return;
12         }
13 
14         if (!empty($this->attributes[$event->name])) {
15             $attributes = (array) $this->attributes[$event->name];
16             $value = $this->getValue($event);
17             foreach ($attributes as $attribute) {
18                 // ignore attribute names which are not string (e.g. when set by TimestampBehavior::updatedAtAttribute)
19                 if (is_string($attribute)) {
20                     $this->owner->$attribute = $value;
21                 }
22             }
23         }
24     }

当update 或者insert  save数据时候,BaseActiveRecord.php 里面的save():

 1 /**
 2      * Saves the current record.
 3      *
 4      * This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]]
 5      * when [[isNewRecord]] is false.
 6      *
 7      * For example, to save a customer record:
 8      *
 9      * ```php
10      * $customer = new Customer; // or $customer = Customer::findOne($id);
11      * $customer->name = $name;
12      * $customer->email = $email;
13      * $customer->save();
14      * ```
15      *
16      * @param boolean $runValidation whether to perform validation (calling [[validate()]])
17      * before saving the record. Defaults to `true`. If the validation fails, the record
18      * will not be saved to the database and this method will return `false`.
19      * @param array $attributeNames list of attribute names that need to be saved. Defaults to null,
20      * meaning all attributes that are loaded from DB will be saved.
21      * @return boolean whether the saving succeeded (i.e. no validation errors occurred).
22      */
23     public function save($runValidation = true, $attributeNames = null)
24     {
25         if ($this->getIsNewRecord()) {
26             return $this->insert($runValidation, $attributeNames);
27         } else {
28             return $this->update($runValidation, $attributeNames) !== false;
29         }
30     }

调用ActiveRecord.php 里面的insert()  和update  ():

 1  public function insert($runValidation = true, $attributes = null)
 2     {
 3         if ($runValidation && !$this->validate($attributes)) {
 4             Yii::info('Model not inserted due to validation error.', __METHOD__);
 5             return false;
 6         }
 7 
 8         if (!$this->isTransactional(self::OP_INSERT)) {
 9             return $this->insertInternal($attributes);
10         }
11 
12         $transaction = static::getDb()->beginTransaction();
13         try {
14             $result = $this->insertInternal($attributes);
15             if ($result === false) {
16                 $transaction->rollBack();
17             } else {
18                 $transaction->commit();
19             }
20             return $result;
21         } catch (\Exception $e) {
22             $transaction->rollBack();
23             throw $e;
24         }
25     }
26 public function update($runValidation = true, $attributeNames = null)
27     {
28         if ($runValidation && !$this->validate($attributeNames)) {
29             Yii::info('Model not updated due to validation error.', __METHOD__);
30             return false;
31         }
32 
33         if (!$this->isTransactional(self::OP_UPDATE)) {
34             return $this->updateInternal($attributeNames);
35         }
36 
37         $transaction = static::getDb()->beginTransaction();
38         try {
39             $result = $this->updateInternal($attributeNames);
40             if ($result === false) {
41                 $transaction->rollBack();
42             } else {
43                 $transaction->commit();
44             }
45             return $result;
46         } catch (\Exception $e) {
47             $transaction->rollBack();
48             throw $e;
49         }
50     }

调用ActiveRecord.php 里面insertInternal() 和updateInternal():

 1 /**
 2      * Inserts an ActiveRecord into DB without considering transaction.
 3      * @param array $attributes list of attributes that need to be saved. Defaults to null,
 4      * meaning all attributes that are loaded from DB will be saved.
 5      * @return boolean whether the record is inserted successfully.
 6      */
 7     protected function insertInternal($attributes = null)
 8     {
 9         if (!$this->beforeSave(true)) {
10             return false;
11         }
12         $values = $this->getDirtyAttributes($attributes);
13         if (($primaryKeys = static::getDb()->schema->insert(static::tableName(), $values)) === false) {
14             return false;
15         }
16         foreach ($primaryKeys as $name => $value) {
17             $id = static::getTableSchema()->columns[$name]->phpTypecast($value);
18             $this->setAttribute($name, $id);
19             $values[$name] = $id;
20         }
21 
22         $changedAttributes = array_fill_keys(array_keys($values), null);
23         $this->setOldAttributes($values);
24         $this->afterSave(true, $changedAttributes);
25 
26         return true;
27     }
28  /**
29      * @see update()
30      * @param array $attributes attributes to update
31      * @return integer number of rows updated
32      * @throws StaleObjectException
33      */
34     protected function updateInternal($attributes = null)
35     {
36         if (!$this->beforeSave(false)) {
37             return false;
38         }
39         $values = $this->getDirtyAttributes($attributes);
40         if (empty($values)) {
41             $this->afterSave(false, $values);
42             return 0;
43         }
44         $condition = $this->getOldPrimaryKey(true);
45         $lock = $this->optimisticLock();
46         if ($lock !== null) {
47             $values[$lock] = $this->$lock + 1;
48             $condition[$lock] = $this->$lock;
49         }
50         // We do not check the return value of updateAll() because it's possible
51         // that the UPDATE statement doesn't change anything and thus returns 0.
52         $rows = static::updateAll($values, $condition);
53 
54         if ($lock !== null && !$rows) {
55             throw new StaleObjectException('The object being updated is outdated.');
56         }
57 
58         if (isset($values[$lock])) {
59             $this->$lock = $values[$lock];
60         }
61 
62         $changedAttributes = [];
63         foreach ($values as $name => $value) {
64             $changedAttributes[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
65             $this->_oldAttributes[$name] = $value;
66         }
67         $this->afterSave(false, $changedAttributes);
68 
69         return $rows;
70     }

调用BaseActiveRecord.php 里面的beforeSave(),触发$this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event)事件执行添加之前绑定的事件方法evaluateAttributes自动相关添加属性值:

1  public function beforeSave($insert)
2     {
3         $event = new ModelEvent;
4         $this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event);
5 
6         return $event->isValid;
7     }

 

}

转载于:https://www.cnblogs.com/xp796/p/5803332.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值