vistart/yii2-models

View on GitHub
traits/TimestampTrait.php

Summary

Maintainability
A
25 mins
Test Coverage
<?php

/**
 *  _   __ __ _____ _____ ___  ____  _____
 * | | / // // ___//_  _//   ||  __||_   _|
 * | |/ // /(__  )  / / / /| || |     | |
 * |___//_//____/  /_/ /_/ |_||_|     |_|
 * @link http://vistart.name/
 * @copyright Copyright (c) 2016 vistart
 * @license http://vistart.name/license/
 */

namespace vistart\Models\traits;

use Closure;
use yii\base\ModelEvent;
use yii\behaviors\TimestampBehavior;

/**
 * Entity features concerning timestamp.
 * @property-read array $timestampBehaviors
 * @property-read string|int createdAt
 * @property-read string|int updatedAt
 * @property-read array $createdAtRules
 * @property-read array $updatedAtRules
 * @property-read boolean isExpired
 * @version 2.0
 * @author vistart <i@vistart.name>
 */
trait TimestampTrait
{

    /**
     * @var string the attribute that will receive datetime value
     * Set this property to false if you do not want to record the creation time.
     */
    public $createdAtAttribute = 'create_time';

    /**
     * @var string the attribute that will receive datetime value.
     * Set this property to false if you do not want to record the update time.
     */
    public $updatedAtAttribute = 'update_time';

    /**
     * @var integer Determine the format of timestamp.
     */
    public $timeFormat = 0;
    public static $timeFormatDatetime = 0;
    public static $timeFormatTimestamp = 1;
    public static $initDatetime = '1970-01-01 00:00:00';
    public static $initTimestamp = 0;

    /**
     * @var int|false the expiration in seconds, or false if it will not be expired.
     */
    public $expiredAt = false;

    /**
     * @var Closure
     */
    public $expiredRemovingCallback;
    public static $eventExpiredRemoved = 'expiredRemoved';

    /**
     * Check this entity whether expired.
     * @return boolean
     */
    public function getIsExpired()
    {
        $createdAt = $this->getCreatedAt();
        if ($this->expiredAt === false || $createdAt === null) {
            return false;
        }
        return $this->offsetDatetime($this->currentDatetime(), -$this->expiredAt) > $createdAt;
    }

    /**
     * Remove myself if expired.
     * @return boolean
     */
    public function removeIfExpired()
    {
        if ($this->getIsExpired() && !$this->getIsNewRecord()) {
            if (($this->expiredRemovingCallback instanceof Closure || is_array($this->expiredRemovingCallback)) && is_callable($this->expiredRemovingCallback)) {
                $result = call_user_func($this->expiredRemovingCallback, $this);
            }
            $result = $this->delete();
            $this->trigger(static::$eventExpiredRemoved, new ModelEvent(['data' => ['result' => $result]]));
        }
        return false;
    }

    /**
     * We recommened you attach this event when after finding this active record.
     * @param ModelEvent $event
     * @return boolean
     */
    public function onRemoveExpired($event)
    {
        return $event->sender->removeIfExpired();
    }

    /**
     * Get the current date & time in format of "Y-m-d H:i:s" or timestamp.
     * You can override this method to customize the return value.
     * @param ModelEvent $event
     * @return string Date & Time.
     * @since 1.1
     */
    public static function getCurrentDatetime($event)
    {
        $sender = $event->sender;
        return $sender->currentDatetime();
    }

    /**
     * Get current date & time, by current time format.
     * @return string|int Date & time string if format is datetime, or timestamp.
     */
    public function currentDatetime()
    {
        if ($this->timeFormat === self::$timeFormatDatetime) {
            return date('Y-m-d H:i:s');
        }
        if ($this->timeFormat === self::$timeFormatTimestamp) {
            return time();
        }
        return null;
    }

    /**
     * Get offset date & time, by current time format.
     * @param string|int $time Date &time string or timestamp.
     * @param int $offset Offset int seconds.
     * @return string|int Date & time string if format is datetime, or timestamp.
     */
    public function offsetDatetime($time = null, $offset = 0)
    {
        if ($this->timeFormat === self::$timeFormatDatetime) {
            return date('Y-m-d H:i:s', strtotime(($offset >= 0 ? "+$offset" : $offset) . " seconds", is_string($time) ? strtotime($time) : (is_int($time) ? $time : time())));
        }
        if ($this->timeFormat === self::$timeFormatTimestamp) {
            return (is_int($time) ? $time : time()) + $offset;
        }
        return null;
    }

    /**
     * Get init date & time in format of "Y-m-d H:i:s" or timestamp.s
     * @param ModelEvent $event
     * @return string|int
     */
    public static function getInitDatetime($event)
    {
        $sender = $event->sender;
        return $sender->initDatetime();
    }

    /**
     * Get init date & time, by current time format.
     * @return string|int Date & time string if format is datetime, or timestamp.
     */
    public function initDatetime()
    {
        if ($this->timeFormat === self::$timeFormatDatetime) {
            return static::$initDatetime;
        }
        if ($this->timeFormat === self::$timeFormatTimestamp) {
            return static::$initTimestamp;
        }
        return null;
    }

    /**
     * Check whether the attribute is init datetime.
     * @param mixed $attribute
     * @return boolean
     */
    protected function isInitDatetime($attribute)
    {
        if ($this->timeFormat === self::$timeFormatDatetime) {
            return $attribute == static::$initDatetime || $attribute == null;
        }
        if ($this->timeFormat === self::$timeFormatTimestamp) {
            return $attribute == static::$initTimestamp || $attribute == null;
        }
        return false;
    }

    /**
     * Get the current date & time in format of "Y-m-d H:i:s".
     * This method is ONLY used for being triggered by event. DO NOT call,
     * override or modify it directly, unless you know the consequences.
     * @param ModelEvent $event
     * @return string Date & Time.
     * @since 1.1
     */
    public function onUpdateCurrentDatetime($event)
    {
        return self::getCurrentDatetime($event);
    }

    /**
     * Behaviors associated with timestamp.
     * @return array behaviors
     */
    public function getTimestampBehaviors()
    {
        return [
            [
                'class' => TimestampBehavior::className(),
                'createdAtAttribute' => $this->createdAtAttribute,
                'updatedAtAttribute' => $this->updatedAtAttribute,
                'value' => [$this, 'onUpdateCurrentDatetime'],
            ]
        ];
    }

    /**
     * Get createdAt.
     * @return string timestamp
     */
    public function getCreatedAt()
    {
        $createdAtAttribute = $this->createdAtAttribute;
        if (!is_string($createdAtAttribute)) {
            return null;
        }
        return $this->$createdAtAttribute;
    }

    /**
     * Get rules associated with createdAtAttribute.
     * @return array rules
     */
    public function getCreatedAtRules()
    {
        if (!$this->createdAtAttribute) {
            return [];
        }
        return [
            [[$this->createdAtAttribute], 'safe'],
        ];
    }

    /**
     * Get updatedAt.
     * @return string timestamp
     */
    public function getUpdatedAt()
    {
        $updatedAtAttribute = $this->updatedAtAttribute;
        if (!is_string($updatedAtAttribute)) {
            return null;
        }
        return $this->$updatedAtAttribute;
    }

    /**
     * Get rules associated with updatedAtAttribute.
     * @return array rules
     */
    public function getUpdatedAtRules()
    {
        if (!$this->updatedAtAttribute) {
            return [];
        }
        return [
            [[$this->updatedAtAttribute], 'safe'],
        ];
    }

    public function enabledTimestampFields()
    {
        $fields = [];
        if (is_string($this->createdAtAttribute)) {
            $fields[] = $this->createdAtAttribute;
        }

        if (is_string($this->updatedAtAttribute)) {
            $fields[] = $this->updatedAtAttribute;
        }
        return $fields;
    }
}