vistart/yii2-models

View on GitHub
traits/IDTrait.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

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

namespace vistart\Models\traits;

use vistart\helpers\Number;
use Yii;
use yii\base\ModelEvent;

/**
 * Entity features concerning ID.
 * @property-read array $idRules
 * @property mixed $id
 * @version 2.0
 * @author vistart <i@vistart.name>
 */
trait IDTrait
{

    /**
     * @var string OPTIONAL.The attribute that will receive the IDentifier No.
     * You can set this property to false if you don't use this feature.
     * @since 1.1
     */
    public $idAttribute = 'id';
    public static $idTypeString = 0;
    public static $idTypeInteger = 1;
    public static $idTypeAutoIncrement = 2;

    /**
     * @var integer type of id attribute.
     * @since 2.0
     */
    public $idAttributeType = 0;

    /**
     * @var boolean Determines whether its id has been pre-assigned. It will not
     * generate or assign ID if true.
     */
    public $idPreassigned = false;

    /**
     * @var string The prefix of ID. When ID type is Auto Increment, this feature
     * is skipped.
     * @since 2.0
     */
    public $idAttributePrefix = '';

    /**
     * @var integer OPTIONAL. The length of id attribute value, and max length
     * of this attribute in rules. If you set $idAttribute to false or ID type
     * to Auto Increment, this property will be ignored.
     * @since 1.1
     */
    public $idAttributeLength = 4;

    /**
     * @var boolean Determine whether the ID is safe for validation.
     * @since 1.1
     */
    protected $idAttributeSafe = false;

    /**
     * Get id.
     * @return string|integer
     */
    public function getId()
    {
        $idAttribute = $this->idAttribute;
        return is_string($idAttribute) ? $this->$idAttribute : null;
    }

    /**
     * Set id.
     * @param string|integer $identity
     * @return string|integer
     */
    public function setId($identity)
    {
        $idAttribute = $this->idAttribute;
        return is_string($idAttribute) ? $this->$idAttribute = $identity : null;
    }

    /**
     * Attach `onInitGuidAttribute` event.
     * @param string $eventName
     */
    protected function attachInitIdEvent($eventName)
    {
        $this->on($eventName, [$this, 'onInitIdAttribute']);
    }

    /**
     * Initialize the ID attribute with new generated ID.
     * If the model's id is pre-assigned, then it will return directly.
     * If the model's id is auto-increment, the id attribute will be marked safe.
     * 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
     * @since 1.1
     */
    public function onInitIdAttribute($event)
    {
        $sender = $event->sender;
        if ($sender->idPreassigned) {
            return;
        }
        if ($sender->idAttributeType === self::$idTypeAutoIncrement) {
            $sender->idAttributeSafe = true;
            return;
        }
        if (is_string($sender->idAttribute) &&
            is_int($sender->idAttributeLength) &&
            $sender->idAttributeLength > 0) {
            $idAttribute = $sender->idAttribute;
            $sender->$idAttribute = $sender->generateId();
        }
    }

    /**
     * Generate the ID. You can override this method to implement your own
     * generation algorithm.
     * @return string the generated ID.
     */
    public function generateId()
    {
        if ($this->idAttributeType == self::$idTypeInteger) {
            do {
                $result = Number::randomNumber($this->idAttributePrefix, $this->idAttributeLength);
            } while ($this->checkIdExists((int) $result));
            return $result;
        }
        if ($this->idAttributeType == self::$idTypeString) {
            return $this->idAttributePrefix .
                Yii::$app->security->generateRandomString($this->idAttributeLength - strlen($this->idAttributePrefix));
        }
        if ($this->idAttributeType == self::$idTypeAutoIncrement) {
            return null;
        }
        return false;
    }

    /**
     * Check if $identity existed.
     * @param mixed $identity
     * @return boolean
     */
    public function checkIdExists($identity)
    {
        if ($identity == null) {
            return false;
        }
        return (static::findOne([$this->idAttribute => $identity]) !== null);
    }

    /**
     * Get the rules associated with id attribute.
     * @return array
     */
    public function getIdRules()
    {
        if ($this->idAttribute == false) {
            return [];
        }
        if ($this->idAttributeSafe) {
            return [
                [[$this->idAttribute], 'safe'],
            ];
        }
        if (is_string($this->idAttribute) &&
            is_int($this->idAttributeLength) &&
            $this->idAttributeLength > 0) {
            $rules = [
                [[$this->idAttribute], 'required'],
                'id' => [[$this->idAttribute], 'unique'],
            ];
            if ($this->idAttributeType === self::$idTypeInteger) {
                $rules[] = [
                    [$this->idAttribute], 'number', 'integerOnly' => true
                ];
            }
            if ($this->idAttributeType === self::$idTypeString) {
                $rules[] = [[$this->idAttribute], 'string',
                    'max' => $this->idAttributeLength,];
            }
            if ($this->idAttributeType === self::$idTypeAutoIncrement) {
                $rules[] = [
                    [$this->idAttribute], 'safe',
                ];
            }
            return $rules;
        }
        return [];
    }
}