Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- * Created by PhpStorm.
- * @author: svd22286@gmail.com
- * @date: 13.12.16
- * @time: 11:06
- *
- */
- namespace common\components;
- use common\traits\ConsoleHelperTrait;
- use yii\base\InvalidConfigException;
- use yii\base\ModelEvent;
- use yii\db\ActiveRecord;
- use yii\base\Event;
- use yii\base\Component;
- /**
- * Component TimeStampUtc ensures that all active record fields timestamp in a project have a time in UTC.
- * Applied for DATETIME, DATE, TIMESTAMP and INT datatypes (tested for MySql)
- * Like [[yii\behaviors\TimestampBehavior]] automatically fills the specified attributes with the current UTC timestamp or convert to UTC value of a field
- * (see [[common\components\TimeStampUtc::PROPERTY_DEFAULT_CONFIG]].
- * By default applied on all [[yii\db\ActiveRecord]] instances of a project.
- * You can configure behavior of each type of [[yii\db\ActiveRecord]] in config
- *
- * Config example:
- * ```php
- * return [
- * 'bootstrap' => ['timeStampUTC'],
- * 'components' => [
- * 'timeStampUTC' => [
- * 'class' => 'common\components\TimeStampUTC',
- * 'propertiesMap' => [
- * 'common\models\User' => [
- * 'createdAtAttribute' => [
- * 'attributeName' => 'created',
- * ]
- * ],
- * 'common\models\OtherModel1' => [
- * 'updatedAtAttribute' => [
- * 'value' => function($event) {
- * return time() - 10800; //
- * }
- * ]
- * ],
- * 'common\models\OtherModel2' => [
- * 'createdAtAttribute' => [
- * 'enableUTCBehavior' => false,//disable Utc behavior for created_at attribute of a model (use predefined value instead)
- * ],
- * ],
- * 'common\models\OtherModel3' => [
- * 'updatedAtAttribute' => [
- * 'enableUTCBehavior' => true,//enable Utc behavior
- * 'attributeName' => 'updated'//custom attribute name
- * ]
- * ],
- * ]
- * ]
- * ]
- * ]
- *
- * ```
- * The configuration above means:
- * for common\models\User:
- * attribute name is `created` (for `createdAtAttribute` config section)
- * and value would be = UTC_TIMESTAMP() if its type DATETIME, DATE or TIMESTAMP and would be = UNIX_TIMESTAMP(UTC_TIMESTAMP()) if its type is INT
- * Similarly, attribute `updated_at` would be = UTC_TIMESTAMP() or UNIX_TIMESTAMP(UTC_TIMESTAMP()) according to its type
- * (Although the configuration section `updatetAtAttribute` has not been defined)
- * for common\models\OtherModel1:
- * attribute name for `createdAtAttribute` is `created_at` (by default), and behavior by default (see above example)
- * for `updatedAtAttribute` value would be calculated by \Closure given through 'value'
- * for common\models\OtherModel2:
- * disable behavior of this component for `created_at` attribute (if present in a model)
- * `updated` attribute would be = UTC_TIMESTAMP() or UNIX_TIMESTAMP(UTC_TIMESTAMP()) according to its type (default behavior)
- * for common\models\OtherModel3
- * enable default behavior of this component for `created_at` attribute (if present in a model).
- * `updated_at` attribute would be = UTC_TIMESTAMP() or UNIX_TIMESTAMP(UTC_TIMESTAMP()) according to its type (default behavior)
- *
- * If you want to disable timeStampUTC behavior for one of two attrs: createdAtAttribute or updatedAtAttribute, set the enableUTCBehavior to false
- *
- * @package common\components
- */
- class TimeStampUTC extends Component {
- use ConsoleHelperTrait;
- /**
- * @var string $nowStrUTC UTC time in format 'Y-m-d H:i:s'
- */
- protected $nowStrUTC;
- /**
- * @var int $nowIntUTC UTC timestamp in seconds since 1 january 1970
- */
- protected $nowIntUTC;
- public $propertiesMap;
- /**
- * @var string $strategy maybe one of [[TimeStampUTC::STRATAEGY_SOFT]], [[TimeStampUTC::STRATAEGY_HARD]]
- * @todo Implement logic for hard strategy (This component by default monitors all AR models and attached to them)
- */
- public $strategy;
- const STRATAEGY_SOFT = 'soft';
- const STRATEGY_HARD = 'hard';
- const PROPERTY_DEFAULT_CONFIG = [
- 'createdAtAttribute' => [
- 'enableUTCBehavior' => true,
- 'attributeName' => 'created_at',
- 'stopPropagation' => false,
- 'value' => null,
- ],
- 'updatedAtAttribute' => [
- 'enableUTCBehavior' => true,
- 'attributeName' => 'updated_at',
- 'stopPropagation' => false,
- 'value' => null,
- ]
- ];
- /**
- * Attach event handlers
- */
- public function init() {
- if (!$this->strategy) {
- $this->strategy = self::STRATAEGY_SOFT;
- }
- $modelKeys = array_keys($this->propertiesMap);
- foreach ($modelKeys as $k) {
- Event::on($k, ActiveRecord::EVENT_BEFORE_INSERT, [$this, 'beforeInsert']);
- Event::on($k, ActiveRecord::EVENT_BEFORE_UPDATE, [$this, 'beforeUpdate']);
- }
- }
- /**
- * detache all event handlers, attached previously
- */
- public function detachAll() {
- $modelKeys = array_keys($this->propertiesMap);
- foreach ($modelKeys as $k) {
- Event::off($k, ActiveRecord::EVENT_BEFORE_INSERT);
- Event::off($k, ActiveRecord::EVENT_BEFORE_UPDATE);
- }
- }
- /**
- * @param \yii\base\ModelEvent $event
- */
- public function beforeInsert(ModelEvent $event) {
- $for = 'createdAtAttribute';
- $result = $this->process($event, $for);
- if (!$result) {
- $event->handled = true;
- }
- }
- /**
- * @param \yii\base\ModelEvent $event
- */
- public function beforeUpdate(ModelEvent $event) {
- $for = 'updatedAtAttribute';
- $result = $this->process($event, $for);
- if (!$result) {
- $event->handled = true;
- }
- }
- /**
- * @param \yii\base\ModelEvent $event
- * @param string $for
- */
- protected function process(ModelEvent $event, $for) {
- $this->nowStrUTC = gmdate('Y-m-d H:i:s');//new Expression('UTC_TIMESTAMP()');
- $this->nowIntUTC = strtotime($this->nowStrUTC);//time() + $utcDiff;//new Expression('UNIX_TIMESTAMP(UTC_TIMESTAMP())');
- /**
- * @var \yii\db\ActiveRecord $sender
- */
- $sender = $event->sender;
- $config = $this->getConfig($sender, $for);
- $attributeName = $config['attributeName'];
- if($config['enableUTCBehavior']) {
- if($sender->hasAttribute($attributeName)) {
- if ($config['enableUTCBehavior'] === true) {
- $this->setAttribute($event, $config);
- }
- } else {
- $className = get_class($sender);
- throw new InvalidConfigException('Attribute `'.$attributeName.'` must be present in `'.$className.'`');
- }
- }
- if ($config['stopPropagation'] === true) {
- return false;
- }
- return true;
- }
- /**
- * @param \yii\db\ActiveRecord $sender
- * @param string $for 'createdAtAttribute' | 'updatedAtAttribute'
- * @return [
- * 'enableUTCBehavior' => bool
- * 'attributeName' => string,
- * 'stopPropagation' => bool,
- * 'convertToUTC' => bool,
- * ]
- */
- protected function getConfig($sender, $for) {
- /**
- * @var \yii\db\ActiveRecord $sender
- */
- $className = get_class($sender);
- $config = static::PROPERTY_DEFAULT_CONFIG[$for];
- if (isset($this->propertiesMap[$className])) {
- $conf = isset($this->propertiesMap[$className][$for]);
- if($conf && is_array($this->propertiesMap[$className][$for])) {
- $config = array_replace($config,$this->propertiesMap[$className][$for]);
- }
- }
- return $config;
- }
- /**
- * @param \yii\db\ActiveRecord $sender
- * @param string $attribute
- * @throws InvalidConfigException
- */
- protected function setAttribute($event, $config) {
- $sender = $event->sender;
- $attributeName = $config['attributeName'];
- $closure = $config['value'];
- $value = null;
- if($closure) {
- $value = call_user_func($closure, $event);
- } else {
- $phpType = $sender->getTableSchema()->columns[$attributeName]->phpType;
- if ($phpType == 'string') {
- $value = $this->nowStrUTC;
- } elseif ($phpType == 'integer') {
- $value = $this->nowIntUTC;
- } else {
- throw new InvalidConfigException("Unknown column type of `$attributeName` in `{$event->sender}` model object#".$this->id);
- }
- }
- $sender->$attributeName = $value;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement