<?php
/**
 * Created by PhpStorm.
 * User: Leo
 * Date: 2017/11/12
 * Time: 下午3:20
 */

namespace common\helpers;


use common\helpers\IDValidator\IDValidator;
use yii\base\InvalidConfigException;
use yii\base\Model;

class Validator extends \yii\validators\Validator {

    /**
     * 扩展的检验规则(最好与Yii自带的校验器区分开，优先使用这里的规则)
     * @var array
     * 例如：
     * 'zh' => ['/^[\x{4e00}-\x{9fa5}]+$/u', '请输入中文'], // 这里传值是正则和消息提示
     * 'idCard' => 'idCardValidate', // 这里传值是类里面存在的方法名
     */
    public static $extensionRule = [
        'chDate'	    =>	["#^\d{4}([/-])([0][0-9]|[1][0-2])\\1([0-2][0-9]|[3][0-1])$#", '必须为日期格式'],
        'chMonth'       =>  ["#^\d{4}([/-])([0][0-9]|[1][0-2]|[0-9])$#", '必须为年月格式'],
        'phone'			=>	["#^\d{3}-\d{8}|\d{4}-\d{7}|\d{4}-\d{8}$#", '必须为电话格式'],
        'mobile'        =>	["|^0[7-9]\d{9}$|", '格式输入不正确'],
        'alpha'         =>  ["|^[a-zA-Z]+$|", '必须为英文字母格式'],
        'zh'            =>  ['/^[\x{4e00}-\x{9fa5}]+$/u', '必须为中文'],
        'price'         =>  ["/^[0-9]+([.]{1}[0-9]{1,2})?$/", ' must be in the amount format'], // 必须为金额格式
        'fullPrice'         =>  ["/^\-?[0-9]+([.]{1}[0-9]{1,2})?$/", ' must be in the amount format'], // 必须为金额格式
        'simpleIdCard'  =>  ["/^\d{6}(19|2\d)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)?$/", '必须为身份证号码格式'],
        'userName'  =>  ["|^[a-z0-9]+$|", '只允许小写英文数字'],
        'realName'  =>  ["/^([\x{4E00}-\x{FA29}]|[\x{E7C7}-\x{E7F3}]|[a-zA-Z0-9. ])*$/u", '不允许包含特殊字符'],
        'idCard'        => 'idCardValidate',
        'yearMonth'       =>  ["/^\d{4}([0][0-9]|[1][0-2]|[0-9])$/", '必须为年月格式'],
    ];

    /**
     * 校验方法
     * @var
     */
    public $validateMethod;

    /**
     * init
     * @throws InvalidConfigException
     */
    public function init()
    {
        parent::init();
        if(!array_key_exists($this->validateMethod, self::$extensionRule)){
            $this->validateMethod = '';
            //throw new InvalidConfigException('校验方法不存在，请查看是否传值正确');
        }
    }

    /**
     * 用类的方法去校验
     * @param $methodName
     * @param $value
     * @return mixed
     * @throws InvalidConfigException
     */
    public function validateByMethod($methodName, $value){
        if(method_exists($this, $methodName)){
            return $this->$methodName($value);
        } else {
            throw new InvalidConfigException('校验方法不存在');
        }
    }

    /**
     * 用正则的方式去校验
     * @param $pattern
     * @param $value
     * @return int
     */
    public function validateByRegular($pattern, $value){
        return preg_match($pattern, $value);
    }

    /**
     * 校验值（主要用于表单model类里面的规则校验）
     * @param mixed $value
     * @return array|null
     * @throws InvalidConfigException
     */
    protected function validateValue($value)
    {
        if(!$this->validateMethod){
            throw new InvalidConfigException('校验方法不存在，请查看是否传值正确');
        }
        $rule = self::$extensionRule[$this->validateMethod];
        $valid = false;
        if(is_array($rule)){
            $valid = $this->validateByRegular($rule[0], $value);
            if ($this->message === null) {
                $this->message = \Yii::t('yii', '{attribute}'.$rule[1]);
            }
        } elseif(is_string($rule)){
            $valid = $this->validateByMethod($rule, $value);
        } else {
            throw new InvalidConfigException('校验规则不存在');
        }
        return $valid ? null : [$this->message, []];
    }

    /**
     * 单独校验某个值用快速的类方法
     * @param $method
     * @param $value
     * @return bool
     */
    public static function validateQuickLy($method, $value){
        $validator = new self();
        $validator->validateMethod = $method;
        $valid = $validator->validateValue($value);
        unset($validator);
        return $valid ? false : true;
    }

    // 以下为特殊的规则校验方法(用简单的正则无法实现的)

    /**
     * @param $value
     */
    private function idCardValidate($value){
        $iDValidator = IDValidator::getInstance();
        if(!$iDValidator->isValid($value)){
            if ($this->message === null) {
                $this->message = \Yii::t('yii', '{attribute}'.'不是真实有效的身份证号码');
            }
        }
    }

}