@param array|null|object $values
@param array             $ruleSet
@param string|null       $prefix

@return bool
973314
public function validate($values, array $ruleSet, string $prefix = null) : bool
    {
        // If there are no rules, there is nothing to validate
        if(empty($ruleSet)) {
            return true;
        }
        if ($prefix !== null) {
            $this->prefix .= $prefix . '.';
        }

        // For each pattern and its rules
        foreach ($ruleSet as $pattern => $rules) {
            if (is_string($rules)) {
                $rules = explode('|', $rules);
            }
            foreach ($rules as $rule) {
                list($rule, $parameters) = array_pad(explode(':', $rule, 2), 2, '');
                $parameters = array_map('trim', explode(',', $parameters));

                if (Arr::exists($this->rules, $rule)) {
                    call_user_func($this->rules[$rule], $this, $values, $pattern, $rule, $parameters);
                }
            }
        }
        $this->prefix = '';

        return $this->hasErrors();
    }
1050037
public static function fromRuleSet(RuleSet $ruleSet, array $overrideRules = [])
    {
        if (\PHP_VERSION_ID < $ruleSet->targetPhpVersion()) {
            throw new \RuntimeException(\sprintf(
                'Current PHP version "%s is less than targeted PHP version "%s".',
                \PHP_VERSION_ID,
                $ruleSet->targetPhpVersion()
            ));
        }

        $config = new Config($ruleSet->name());

        $config->setRiskyAllowed(true);
        $config->setRules(\array_merge(
            $ruleSet->rules(),
            $overrideRules
        ));

        return $config;
    }
1293440
public function getRules($ruleset)
    {
        if ($ruleset == self::YANDEX) {

            $russianRules = parent::getRules('russian');
            /**
             * @see http://translit-online.ru/yandex.html
             */
            return array_merge($russianRules, [
                //kh после букв c,s,e,h ; в остальных случаях - h
                /*'цх' => 'ckh',
                'ЦХ' => 'CKh',
                'Цх' => 'Ckh',
                'цХ' => 'cKh',

                'сх'  => 'skh',
                'СХ'  => 'SKh',
                'Сх'  => 'Skh',
                'сХ'  => 'sKh',

                //TODO: доделать комбинации больших маленьких букв
                'ех'  => 'еkh',
                'ёх'  => 'еkh',
                'эх'  => 'еkh',

                'чх' => 'chkh',
                'хх' => 'khkh',
                'шх' => 'shkh',
                'щх' => 'shchkh',
                'жх' => 'zhkh',

                'хх' => 'hkh',

                'hх' => 'hkh',*/

                'ё' => 'yo',
                'Ё' => 'Yo',

                'й' => 'j',
                'Й' => 'J',

                /*'х' => 'h',
                'Х' => 'H',*/

                'х' => 'х',
                'Х' => 'Х',

                'ц' => 'c',
                'Ц' => 'C',

                'щ' => 'shch',
                'Щ' => 'Shch',

                'э' => 'eh',
                'Э' => 'Eh',
            ]);
        }

        return parent::getRules($ruleset);
    }
75478
protected function parseRuleString($ruleString)
    {
        if (is_string($ruleString)) {
            // Parse for @charset rule
            if (preg_match('/^@charset\s+(["\'])([-a-zA-Z0-9_]+)\g{1}/i', rtrim($ruleString), $matches)) {
                $this->setValue($matches[2]);
            } else {
                throw new \InvalidArgumentException("Invalid format for @charset rule.");
            }
        } else {
            throw new \InvalidArgumentException(
                "Invalid type '" . gettype($ruleString) . "' for argument 'ruleString' given. String expected."
            );
        }
    }
184959
public static function parse( string $parse, array $properties = [] ): RuleCollection
	{
		$clt = new RuleCollection();

		if( preg_match('/^(https?):\/\/(.+?)(\/$)$/', $parse, $m) )
		{
			$parse = $m[3];
			$clt[] = self::getRuleHost($m[2], $m[1]);
		}
		else if( preg_match('/^\/\/(.+?)(\/$)$/', $parse, $m) )
		{
			$parse = $m[2];
			$clt[] = self::getRuleHost($m[1]);
		}

		$parse  = ltrim($parse, "/");
		$end_of = strrpos($parse, "/");
		$close  = $end_of !== false && $end_of === strlen($parse) - 1;
		$get    = '';
		$names  = [];

		if($close)
		{
			$parse = rtrim($parse, "/");
		}

		$parse = explode("/", $parse);
		$cnt = count($parse);

		for($i = 0; $i < $cnt; $i++)
		{
			$item = trim($parse[$i]);
			$last = $i + 1 === $cnt;

			if( $item[0] === "{" )
			{
				$end_of = strpos($item, "}");
				if( $end_of === false )
				{
					throw new \InvalidArgumentException("Parser error, invalid segment value '{$item}'");
				}

				$rule = self::getRuleSegment(substr($item, 1, $end_of - 2), $properties);
				if( in_array($rule->getName(), $names, true) )
				{
					throw new \InvalidArgumentException("Duplicate data name '" . $rule->getName() . "'");
				}
				else
				{
					$names[] = $rule->getName();
				}

				$clt[] = $rule;
				$end = $end_of + 1;
				$len = strlen($item);

				if( $end > $len )
				{
					// start GET queries
					if( $last && $item[$end] === "?" && $end + 1 < $len )
					{
						$get = substr($item, $end);
						$close = false;
					}
					else
					{
						throw new \InvalidArgumentException("Parser error, invalid segment value '{$item}'");
					}
				}
			}

			// start GET queries
			else if( $item[0] === "?" )
			{
				if( $last && strlen($item) > 1 )
				{
					if( $i > 0 )
					{
						$close = true;
					}
					$get = substr($item, 1);
				}
				else
				{
					throw new \InvalidArgumentException("Parser error, invalid segment value '{$item}'");
				}

				break;
			}

			// static ...
			else
			{
				$clt[] = new RuleStatic($item);
			}
		}

		if( ! $close )
		{
			$last = $clt->last();
			if( $last instanceof RuleStatic || $last instanceof RuleSegment )
			{
				$last->setOpen();
			}
		}

		if( strlen($get) )
		{
			if( strpos($get, '&amp;') !== false )
			{
				$all = explode("&amp;", $get);
			}
			else
			{
				$all = explode("&", $get);
			}

			$queries = [];

			foreach( $all as $item )
			{
				$item = trim($item);
				if( !strlen($item) )
				{
					throw new \InvalidArgumentException("Parser error, query value is empty");
				}

				if( strpos($item, '{') === false )
				{
					$m = [
						1 => $item,
						2 => $item
					];
				}
				else if( ! preg_match('/^(.+?)=\{(.+)?\}$/', $item, $m) )
				{
					throw new \InvalidArgumentException("Parser error, invalid query value '{$item}'");
				}

				$rule = self::getRuleGet($m[1], $m[2], $properties);
				if( in_array($rule->getName(), $names, true) )
				{
					throw new \InvalidArgumentException("Duplicate data name '" . $rule->getName() . "'");
				}
				else
				{
					$names[] = $rule->getName();
				}

				if( in_array($rule->getQueryName(), $queries, true) )
				{
					throw new \InvalidArgumentException("Duplicate query name '" . $rule->getName() . "'");
				}
				else
				{
					$queries[] = $rule->getName();
				}

				$clt[] = $rule;
			}
		}

		return $clt;
	}
651884
public function setFilterRule($spec, $ruleSet)
    {
        $spec = $this->_normalizeSpec($spec);
        $this->rules[$spec] = [];
        return $this->addFilterRule($spec, $ruleSet);
    }
920279
public function isValidValue($rules, $value) {
        $result = [];
        foreach ($rules as $rule) {
            $parameters = $rule;
            $name       = array_shift($parameters);
            $valid      = $this->isValidRule($name, $parameters, $value);
            if ($valid !== null) {
                $result[] = $valid;
            }
        }
        return $result;
    }
454464
public function applyRules($field, $ruleset)
    {
        // Save previous values, just in case
        $acc = $this->acc;
        $crs = $this->current_ruleset;
        $this->bail_out = false;

        $this->acc = $this->get($field);
        $this->current_ruleset = $ruleset;

        while (!is_null($rule = $this->pullRule())) {
            $this->cast = false;
            $this->custom_error = null;

            if ($rule == 'required') {
                $is_required = true;
            }

            // For debugging
            $tmp = null;
            $this->consumed = array($rule);

            try {
                if ((is_object($rule) || is_array($rule)) && is_callable($rule)) {
                    $tmp = $rule($this, $this->acc, $field);
                } else {
                    // For to_XX rules
                    if (substr($rule, 0, 3) == 'to_') {
                        if (!$this->hasMethod('rule_'.$rule)) {
                            $rule = substr($rule, 3);
                        }

                        $this->cast = true;
                    }

                    if ($rule === '') {
                        if ($this->cast) {
                            $this->set($field, $this->acc);
                        }
                        continue;
                    }

                    $rule = $this->resolveRuleAlias($rule);

                    $tmp = $this->{'rule_'.$rule}($this->acc, $field);
                }

                if ($this->debug) {
                    echo "<font color=blue>rule_$rule({$this->acc},".
                    implode(',', $this->consumed).")=$tmp</font><br/>";
                }

                if (!is_null($tmp)) {
                    $this->acc = $tmp;
                }
                if ($this->cast) {
                    $this->set($field, $tmp);
                }
                if ($this->bail_out) {
                    break;
                }
            } catch (\Exception_ValidityCheck $e) {
                if ($this->debug) {
                    echo "<font color=red>rule_$rule({$this->acc},".
                        implode(',', $this->consumed).') failed</font><br/>';
                }
                $this->acc = $acc;
                $this->current_ruleset = $crs;
                throw $e
                    ->setField($field)
                    ->addMoreInfo('val', $this->acc)
                    ->addMoreInfo('rule', $rule);
            }
        }
        $this->acc = $acc;
        $this->current_ruleset = $crs;
    }
442069
private function validateValues(int $ruleIndex, iterable $values): iterable
    {
        foreach ($values as $key => $value) {
            $this->getCaptures()->clear();
            $this->validateAndAccumulateError($value, $ruleIndex);
            if ($this->getCaptures()->count() > 0) {
                yield $key => $this->readSingleCapturedValue();
            }
        }
    }
277764
protected function eachValue(array $values, $prefix = null)
    {
        foreach ($values as $key => $value):
            if (is_array($value)):
                $this->eachValue($value, $key); else:
                if (is_numeric($key)):
                    $key = $prefix.$key; elseif (is_string($prefix)):
                    $key = $prefix.':'.$key;
        endif;

        $this->html[] = $this->makeTag($key, $value);
        endif;
        endforeach;
    }
575968
public function validate(array $values, array $rules)
    {
        // Assume no validation and result success
        $result = true;

        if (true !== $valid = $this->validateByRules($rules, $values)) {
            foreach ($valid as $componentName => $error) {
                $this->setError($error, $componentName);
            }

            // Set general form error
            $this->setError(
                [
                    'error' => 'general',
                    'info'  => [],
                ],
                Doozr_Form_Service_Constant::ERROR_IDENTIFIER_FORM
            );

            $result = false;
        }

        return $result;
    }
354824
public static function getConstants( $prefix = '', $combineValues = false )
	{
		$list = ( new \ReflectionClass( static::class ) )->getConstants();
		
		foreach( $list as $key => $const ) {
			if( strpos( $key, $prefix ) !== 0 ) {
				unset( $list[ $key ] );
			}
		}
		
		return $combineValues
			? array_combine( $list, $list )
			: $list;
	}
544553
public function process(array $rules, array $data) {
        
        // If conditionning
        $this->rules[] = new Rule(
            'if_boolean', 
            'if:(\w+)', 
            '<?php if (isset($this->data[\'$1\']) && $this->data[\'$1\']): ?>'
        );
        $this->rules[] = new Rule(
        		'if_condition',
        		'if:(\w+)([!<>=]+)(\w+)',
        		'<?php if (isset($this->data[\'$1\'])){$base = $this->data[\'$1\'];}else{$base = \'$1\';};
        		if (isset($this->data[\'$3\'])){$value = $this->data[\'$3\'];}else{$value = \'$3\';}?>
        		<?php if ($base $2 $value): ?>'
        );
        $this->rules[] = new Rule(
            'ifnot', 
            'ifnot:(\w+)', 
            '<?php if (!isset($this->data[\'$1\']) || !$this->data[\'$1\']): ?>'
        );
        $this->rules[] = new Rule(
            'else', 
            'else', 
            '<?php else: ?>'
        );
        $this->rules[] = new Rule(
            'elseif_boolean', 
            'else:(\w+)', 
            '<?php elseif (isset($this->data[\'$1\']) && $this->data[\'$1\']): ?>'
        );
        $this->rules[] = new Rule(
            'elseif_condition', 
            'else:(\w+)([!<>=]+)(\w+)', 
            '<?php elseif (((isset($this->data[\'$1\']) && isset($this->data[\'$3\'])) && $this->data[\'$1\'] $2 $this->data[\'$3\']) ||
        		((isset($this->data[\'$1\']) && !isset($this->data[\'$3\'])) && $this->data[\'$1\'] $2 \'$3\') ||
        		((!isset($this->data[\'$1\']) && isset($this->data[\'$3\'])) && \'$1\' $2 $this->data[\'$3\']) ||
        		((!isset($this->data[\'$1\']) && !isset($this->data[\'$3\'])) && \'$1\' $2 \'$3\')): ?>'
        );
        $this->rules[] = new Rule(
            'endif', 
            'endif', 
            '<?php endif; ?>'
        );
        
        // Loops
        $this->rules[] = new Rule(
            'loop', 
            'loop:(\w+)', 
            '<?php foreach ($this->data[\'$1\'] as $element): $this->wrap($element); ?>'
        );
        $this->rules[] = new Rule(
            'endloop', 
            'endloop', 
            '<?php $this->unwrap(); endforeach; ?>'
        );
        
        // Importing
        $this->rules[] = new Rule(
            'import_view', 
            'import:(([^\/\s]+\/)?(.*))', 
            '<?php echo $this->importFile(\'$1\'); ?>'
        );
        
        // Clean variables
        $this->rules[] = new Rule(
            'escape_var', 
            'escape:(\w+)', 
            '<?php $this->showVariable(\'$1\', true); ?>'
        );
        
        // Custom rules
        $this->rules = array_merge($this->rules, $rules);
        
        // Variables
        $this->rules[] = new Rule(
            'variable', 
            '(\w+)', 
            '<?php $this->showVariable(\'$1\'); ?>'
        );
        
        // Arrays
        $this->rules[] = new Rule(
        		'variable_array',
        		'(\w+)\[(\w+)\]',
        		'<?php echo (isset($this->data[\'$1\'][\'$2\'])) ? $this->data[\'$1\'][\'$2\'] : "&#123;$1[$2]&#125"; ?>'
        );
        
        $this->rules[] = new Rule(
        		'variable_array_escape',
        		'escape:(\w+)\[(\w+)\]',
        		'<?php echo htmlentities($this->showVariable(\'$1\')[\'$2\']); ?>'
        );
        
        $this->data = $data;
        $this->stack = array();
        
        foreach ($this->rules as $rule) {
            $this->template = preg_replace('/\{' . $rule->rule() . '\}/', $rule->replacement(), $this->template);
        }
        
        $this->template = '?>' . $this->template;
        
        ob_start();
        eval($this->template);
        return ob_get_clean();
    }
521047
public function values($values) {
        ValuesImpl::values($this->context, $values);
        return new ExecRule($this->context);
    }
422600
public function fillSchemaFields($values, $map = null, $prefix = null)
    {
        //
        if (is_array($map)) {
            foreach ($map as $alias => $field) {
                if (isset($values[$alias])) {
                    $values[$field] = $values[$alias];
                }
            }
        }

        //
        foreach (static::getSchema() as $field => $aspects) {
            if (isset($aspects['Class']) && $aspects['Relation'] == '1:1') {
                $class = $aspects['Class'];

                $this->{$field} = $class::create(
                    $values,
                    $map,
                    $prefix.$field.'__'
                );
            }

            //
            $field = $prefix.$field;

            //
            if (isset($values[$field])) {
                $this->{$field} = $values[$field];
            }
        }

        //
        $key = $this->getPrimaryKey();

        //
        $field = $prefix.$key;

        //
        if ($key) {
            $this->{$key} = isset($values[$field])
                ? (int) $values[$field]
                : (int) $this->{$key};
        }
    }
161661
public static function create($values = null, $map = null, $prefix = null)
    {
        $object = new static();
        if ($values) {
            $object->fillSchemaFields($values, $map, $prefix);
        }

        return $object;
    }
1227856
public static function filterNullValues($properties, array $allowed = null)
    {
        // If provided, only use allowed properties
        $properties = static::only($properties, $allowed);

        return array_filter(
            $properties,
            function ($value) {
                return !is_null($value);
            }
        );
    }