zoukankan      html  css  js  c++  java
  • 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 yiiehaviors;
      9 
     10 use yiiaseInvalidCallException;
     11 use yiidbBaseActiveRecord;
     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 yiiehaviorsTimestampBehavior;
     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 yiidbExpression;
     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 [[yiidbExpression]] 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 [[yiidbActiveRecord::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     }
    }
  • 相关阅读:
    智慧北京04_自定义下拉刷新
    智慧北京03_菜单详情页_ViewPagerIndicator框架_页签详情页_事件处理
    (转发)RJcente,安卓常用工具
    (转发 )将Eclipse代码导入到Android Studio的两种方式
    智慧北京02_初步ui框架_ 主界面_viewPager事件_xUtils_slidingMenu_网络缓存_数据传递
    智慧北京01_splash界面_新手引导界面_slidingMenu框架_.主界面结构
    自定义控件进阶02_侧滑删除,粘性控件
    一个抽奖H5页面的记录
    分享一个情侣头像小程序,欢迎体验、拍砖
    iPhone X H5页面适配
  • 原文地址:https://www.cnblogs.com/xp796/p/5803332.html
Copyright © 2011-2022 走看看