创建验证器
@param string $name
@param \Abstracts\Model $object
@param array $attributes
@param array $params
@return \Abstracts\Validator
@throws \Helper\Exception
@throws \ReflectionException
354251
static public function create($name, $object, $attributes, $params = [])
    {
        // 将属性转换成数组
        if (is_string($attributes)) {
            $attributes = str_explode($attributes, ',');
        }
        // 分析规则适用的场景（scenario）
        if (isset($params['on'])) {
            if (is_array($params['on'])) {
                $on = $params['on'];
            } else {
                $on = str_explode($params['on'], ',');
            }
        } else {
            $on = [];
        }
        // 分析规则不适用的场景（scenario）
        if (isset($params['except'])) {
            if (is_array($params['except'])) {
                $except = $params['except'];
            } else {
                $except = str_explode($params['except'], ',');
            }
        } else {
            $except = [];
        }
        $params['attributes'] = $attributes;
        $params['on'] = empty($on) ? [] : array_combine($on, $on); // 绑定支持的 scenario
        $params['except'] = empty($except) ? [] : array_combine($except, $except); // 绑定拒绝的 scenario

        if (method_exists($object, $name)) {
            $params['class'] = '\ModelSupports\validators\InlineValidator';
            $params['method'] = $name;
        } else if (isset(self::$builtInValidators[$name])) {
            $params['class'] = self::$builtInValidators[$name];
        } else {
            $params['class'] = $name;
        }
        return Unit::createObject($params);
    }
1193073
protected function parse($object)
    {
        if (! is_object($object)) {
            throw new ValidationException('Attributes has to be an object, "' . gettype($object) . '" given.');
        }

        if (property_exists($object, 'type') or property_exists($object, 'id') or property_exists($object, 'relationships') or property_exists($object, 'links')) {
            throw new ValidationException('These properties are not allowed in attributes: `type`, `id`, `relationships`, `links`');
        }

        $object_vars = get_object_vars($object);

        if (count($object_vars) === 0) {
            return $this;
        }

        foreach ($object_vars as $name => $value) {
            $this->set($name, $value);
        }
    }
1100268
public function error($name, $attributes = []) {
		if (!isset($this->_errors[$name])) return '';

		list($attributes) = $this->_prepare($name, $attributes);

		$attributes['data-error-for'] = $attributes['id'];
		unset($attributes['id']);
		$attributes = $this->_arrayToAttributesString($attributes);

		// show only the first error. The others could be consequential error
		$value = $this->_escape(current($this->_errors[$name]));

		return "<span{$attributes}>{$value}</span>";
	}
384335
public function invokeMethod($name, array $args = array(), $object = null)
    {
        return $this->getMethod($name)->invokeArgs($this->getObject($object), $args);
    }
251634
public static function factory(string $name, array $attributes = []): Custom
    {
        $instance = new static();
        $instance->name = $name;
        $instance->customAttributes = $attributes;

        return $instance;
    }
528701
public function build($name = null, array $attributes = [], $callback = null)
    {
        if (!$this->validator->isValid($attributes)) {
            throw new Exception\InvalidAttributesException('Invalid validator class');
        }
        unset($attributes['form']);

        $field = new Fluent([
            'name'       => $name,
            'value'      => isset($attributes['value']) ? $attributes['value'] : '',
            'attributes' => $attributes,
        ]);

        if ($callback instanceof Closure) {
            call_user_func($callback, $field);
        }

        $params  = $this->attributes($field);
        $this->extractor->generateScripts($params);
        $this->memorize($field);
        $hiddens = [
            app('form')->hidden('validator', $attributes['validator'])
        ];

        return view($this->config['view'], ['hiddens' => $hiddens, 'element' => app('form')->button($attributes['title'], $params)])->render();
    }
34456
public function buildPropertyPreg($named, $attributes)
    {
        if ($named) {
            $this->resultOffsets['named'] = $this->startOffset + 3;
            $this->propertyPreg .= "([\$]smarty[.]{$this->tagName}[.]{$attributes['name']}[.](";
            $properties = $this->nameProperties;
        } else {
            $this->resultOffsets['item'] = $this->startOffset + 3;
            $this->propertyPreg .= "([\$]{$attributes['item']}[@](";
            $properties = $this->itemProperties;
        }
        $this->startOffset += count($properties) + 2;
        $propName = reset($properties);
        while ($propName) {
            $this->propertyPreg .= "({$propName})";
            $propName = next($properties);
            if ($propName) {
                $this->propertyPreg .= '|';
            }
        }
        $this->propertyPreg .= '))';
    }
893704
public static function create( $name, $content = NULL, $attributes = array(), $data = array() )
	{
		if( !strlen( $name	= trim( $name ) ) )
			throw new InvalidArgumentException( 'Missing tag name' );
		$name		= strtolower( $name );
		try{
			$attributes	= self::renderAttributes( $attributes );
			$data		= self::renderData( $data );
		}
		catch( InvalidArgumentException $e ) {
			if( version_compare( PHP_VERSION, '5.3.0', '>=' ) )
				throw new RuntimeException( 'Invalid attributes', NULL, $e );						//  throw exception and transport inner exception
			throw new RuntimeException( 'Invalid attributes', NULL );								//  throw exception
		}
		if( $content === NULL || $content === FALSE )												//  no node content defined, not even an empty string
			if( !in_array( $name, self::$shortTagExcludes ) )										//  node name is allowed to be a short tag
				return "<".$name.$attributes.$data."/>";											//  build and return short tag
		if( is_array( $content ) )																	//  content is an array, may be nested
			$content	= self::flattenArray( $content, '' );
		if( is_numeric( $content ) )
			$content	= (string) $content;
		if( is_object( $content ) ){
			if( !method_exists( $content, '__toString' ) ){											//  content is not a renderable object
				$message	= 'Object of class "'.get_class( $content ).'" cannot be rendered';		//  prepare message about not renderable object
				throw new InvalidArgumentException( $message ); 									//  break with error message
			}
			$content	= (string) $content;														//  render object to string
		}
		if( !is_null( $content ) && !is_string( $content ) ){										//  content is neither NULL nor string so far
			$message	= 'Content type "'.gettype( $content ).'" is not supported';				//  prepare message about wrong content data type
			throw new InvalidArgumentException( $message ); 										//  break with error message
		}
		return "<".$name.$attributes.$data.">".$content."</".$name.">";								//  build and return full tag
	}
973637
protected function getAttributes($name, array $attributes)
    {
        $attributes = $this->filterRelationshipAttributes($attributes);

        $factory = $this->triggerFakerOnAttributes(
            $this->getFixture($name)->attributes
        );

        return array_merge($factory, $attributes);
    }
251311
public function addFilter($name, $attributes = array())
    {
        // name is "filtername:method:alias".
        $names = explode(':', $name);
        $filter = array_shift($names);
        $method = array_shift($names);
        $alias = array_shift($names);
        if (! $alias) $alias = $filter;
        if (! is_array($attributes)) $attributes = [];

        // method miss match, when return.
        if ($method && strtoupper($method) !== $this->Request->getMethod()) return;

        // register.
        if (isset($this->filters[$alias])) {
            $this->filters[$alias]['attributes'] = $this->arrayUtil->merge($this->filters[$alias]['attributes'], $attributes);
        } else {
            $this->filter_names[] = $alias;
            $this->filters[$alias] = array('name' => $filter, 'attributes' => (array)$attributes);
        }

        // if action filter.
        if (strtolower($filter) === 'action') {
            $this->has_action_filter = true;
        }
    }
187187
protected function validateAttribute($object, $attribute)
    {
        $value = $object->{$attribute};
        if ($this->isEmpty($value)) {
            $this->validateEmpty($object, $attribute);
            return;
        }
        if (!is_array($this->range)) {
            throw new Exception('属性"range"必须定义为数组', 101400301);
        }

        if (is_array($value)) {
            $noIn = [];
            foreach ($value as $v) {
                if (false === $this->inArray($v)) {
                    $noIn[] = $v;
                }
            }
            $isIn = empty($noIn);
        } else {
            $isIn = $this->inArray($value);
        }

        if (!$isIn) {
            $this->addError($object, $attribute, $this->message);
            return;
        }
    }
646981
public function validateClass($attribute, $params)
    {
        $className = @\Yii::import($this->$attribute, true);

        if (!is_string($className) || !$this->classExists($className)) {
            $this->addError($attribute, "Class '$className' does not exist or has syntax error.");
        } elseif (isset($params['extends'])
            && ltrim($className, '\\') !== ltrim($params['extends'], '\\')
            && !is_subclass_of($className, $params['extends'])) {
            $this->addError('baseClass', "Class '$className' must extend from {$params['extends']}.");
        }
    }
986326
public function select($name, array $options, $selected = null, array $attributes = [])
    {
        $tag = new Tag('select', $attributes);
        $tag->name = $name;
        
        if ($selected === null)
            $selected = $this->getDefaultValue($name);

        foreach ($options as $value => $label)
        {
            $option = new Tag('option');
            $option->value = $value;
            $option->setText($label);

            if ($selected !== null && $value == $selected)
                $option->selected = true;

            $tag->addChild($option);
        }

        return $tag;
    }
937497
private function getValue(array $attributes, $name, $default = null)
    {
        if (array_key_exists($name, $attributes) && !empty($attributes[$name])) {
            return $attributes[$name];
        }

        return $default;
    }
241942
public function select($name, $options = null, $attributes = array())
    {
        $attributes['name'] = $name;

        if (!isset($attributes['id'])) {
            $attributes['id'] = str_replace(array('[', ']'), array('_', ''), $name);
        }

        if (is_array($options)) {
            $options = array_merge(array('options' => array(), 'selected' => null), $options);
            $options = $this->options($options['options'], @$options['selected']);
        }

        return $this->tag('select', (string) $options, $attributes);
    }
338490
protected function validate(array $attributes, string $name, array $parameters): bool
    {
        if (! isset($parameters['is']) &&
            ! isset($parameters['min']) &&
            ! isset($parameters['max'])
        ) {
            throw new ValidationException('长度限制条件必须填写');
        }

        $len = mb_strlen($attributes[$name]);

        if (isset($parameters['is'])) {
            if ($len === (int) $parameters['is']) {
                return true;
            }
        }

        if (isset($parameters['min']) && isset($parameters['max'])) {
            if ($len >= (int) $parameters['min'] && $len <= (int) $parameters['max']) {
                return true;
            }
        } elseif (isset($parameters['min'])) {
            if ($len >= (int) $parameters['min']) {
                return true;
            }
        } elseif (isset($parameters['max'])) {
            if ($len <= (int) $parameters['max']) {
                return true;
            }
        }

        $this->addError($name, $parameters, '%s 长度不符合');

        return false;
    }
79098
public function register(string $name, $object, array $params = array())
	{
		if (is_string($object)) {
			$this->store[$name] = new Object();
			$this->store[$name]->setClassName($object);
			foreach ($params as $key => $value) {
				$this->store[$name]->parameter($key, $value);
			}
		} else if (is_object($object)) {
			$this->store[$name] = new Object();
			$this->store[$name]->setInstance($object);
		} else {
			throw new \Exception('$object must be a string or an object');
		}
		if (!$this->isRegistered($name)) {
			$this->keys[] = $name;
		}
		$this->store[$name]->setName($name);
		return $this->store[$name];
	}