├── .gitattributes ├── src ├── ExceptionInterface.php ├── StringifyCallbackTrait.php ├── Output │ ├── Structure.php │ ├── Rule.php │ └── Subject.php ├── Rule │ ├── Digits.php │ ├── Numeric.php │ ├── Email.php │ ├── Boolean.php │ ├── IsArray.php │ ├── IsFloat.php │ ├── IsString.php │ ├── Json.php │ ├── Alnum.php │ ├── Alpha.php │ ├── Equal.php │ ├── Regex.php │ ├── Phone.php │ ├── Integer.php │ ├── LessThan.php │ ├── GreaterThan.php │ ├── Length.php │ ├── Url.php │ ├── InArray.php │ ├── CreditCard.php │ ├── LengthBetween.php │ ├── Callback.php │ ├── Datetime.php │ ├── Each.php │ ├── Between.php │ ├── Hash.php │ ├── Uuid.php │ ├── Required.php │ └── NotEmpty.php ├── Exception │ └── InvalidValueException.php ├── Failure.php ├── ValidationResult.php ├── Value │ └── Container.php ├── MessageStack.php ├── Rule.php ├── Validator.php └── Chain.php ├── composer.json ├── README.md └── composer.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | /.github export-ignore 2 | /docs export-ignore 3 | /.gitignore export-ignore 4 | /.scrutinizer.yml export-ignore 5 | /.travis.yml export-ignore 6 | /tests export-ignore 7 | /mkdocs.yml export-ignore 8 | /phpunit.xml export-ignore 9 | -------------------------------------------------------------------------------- /src/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | subjects[] = $subject; 31 | } 32 | 33 | /** 34 | * Returns an array of all subjects. 35 | * 36 | * @return Subject[] 37 | */ 38 | public function getSubjects() 39 | { 40 | return $this->subjects; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Rule/Digits.php: -------------------------------------------------------------------------------- 1 | '{{ name }} may only consist out of digits', 32 | ]; 33 | 34 | /** 35 | * Validates if each character in $value is a decimal digit. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (ctype_digit((string) $value)) { 43 | return true; 44 | } 45 | return $this->error(self::NOT_DIGITS); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Rule/Numeric.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be numeric', 32 | ]; 33 | 34 | /** 35 | * Validates if $value represents an integer or a float value. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (is_numeric($value)) { 43 | return true; 44 | } 45 | return $this->error(self::NOT_NUMERIC); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Exception/InvalidValueException.php: -------------------------------------------------------------------------------- 1 | message = $message; 38 | $this->identifier = $identifier; 39 | 40 | parent::__construct($message, 0, $previous); 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getIdentifier() 47 | { 48 | return $this->identifier; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Rule/Email.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid email address', 32 | ]; 33 | 34 | /** 35 | * Validates if the value is a valid email address. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (filter_var($value, FILTER_VALIDATE_EMAIL) !== false) { 43 | return true; 44 | } 45 | return $this->error(self::INVALID_FORMAT); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Rule/Boolean.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be either true or false', 32 | ]; 33 | 34 | /** 35 | * Validates if $value is either true or false. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | return is_bool($value) ?: $this->error(self::NOT_BOOL); 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function shouldBreakChainOnError() 49 | { 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Rule/IsArray.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be an array', 32 | ]; 33 | 34 | /** 35 | * Validates if $value is an array. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (is_array($value)) { 43 | return true; 44 | } 45 | 46 | return $this->error(self::NOT_AN_ARRAY); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function shouldBreakChainOnError() 53 | { 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Rule/IsFloat.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a float', 32 | ]; 33 | 34 | /** 35 | * Validates if $value represents a float. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (is_float($value)) { 43 | return true; 44 | } 45 | 46 | return $this->error(self::NOT_A_FLOAT); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function shouldBreakChainOnError() 53 | { 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Rule/IsString.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a string', 32 | ]; 33 | 34 | /** 35 | * Validates if $value represents a string. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (is_string($value)) { 43 | return true; 44 | } 45 | 46 | return $this->error(self::NOT_A_STRING); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function shouldBreakChainOnError() 53 | { 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Rule/Json.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid JSON string', 32 | ]; 33 | 34 | /** 35 | * Validates if the value is a valid JSON string. 36 | * 37 | * @param mixed $value 38 | * @return bool 39 | */ 40 | public function validate($value) 41 | { 42 | if (!is_string($value)) { 43 | return $this->error(self::INVALID_FORMAT); 44 | } 45 | 46 | json_decode($value); 47 | if (json_last_error() !== JSON_ERROR_NONE) { 48 | return $this->error(self::INVALID_FORMAT); 49 | } 50 | 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "particle/validator", 3 | "type": "library", 4 | "description": "Flexible and highly usable validation library with no dependencies.", 5 | "keywords": ["validation", "validator"], 6 | "homepage": "http://github.com/particle-php/validator", 7 | "license" : "BSD-3-Clause", 8 | "authors" : [ 9 | { 10 | "name": "Berry Langerak", 11 | "email": "berry@berryllium.nl", 12 | "role": "developer" 13 | }, 14 | { 15 | "name": "Rick van der Staaij", 16 | "homepage": "http://rickvanderstaaij.nl", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.4" 22 | }, 23 | "suggest": { 24 | "byrokrat/checkdigit": "If you want to use CreditCard validation rule, this library must be installed.", 25 | "giggsey/libphonenumber-for-php": "If you want to use Phone validation rule, this library must be installed." 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "~4.0", 29 | "squizlabs/php_codesniffer": "2.*", 30 | "byrokrat/checkdigit": "^1.0", 31 | "giggsey/libphonenumber-for-php": "^7.2" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Particle\\Validator\\": "src/" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Particle\\Validator\\Tests\\": "tests/" 41 | } 42 | }, 43 | "extra": { 44 | "branch-alias": { 45 | "dev-master": "2.0-dev" 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Output/Rule.php: -------------------------------------------------------------------------------- 1 | name = $name; 41 | $this->messages = $messages; 42 | $this->parameters = $parameters; 43 | } 44 | 45 | /** 46 | * Returns the name (short class name) for this rule. 47 | * 48 | * @return string 49 | */ 50 | public function getName() 51 | { 52 | return $this->name; 53 | } 54 | 55 | /** 56 | * Returns all messages for this rule. 57 | * 58 | * @return array 59 | */ 60 | public function getMessages() 61 | { 62 | return $this->messages; 63 | } 64 | 65 | /** 66 | * Returns all parameters for this rule. 67 | * 68 | * @return array 69 | */ 70 | public function getParameters() 71 | { 72 | return $this->parameters; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Output/Subject.php: -------------------------------------------------------------------------------- 1 | key = $key; 40 | $this->name = $name; 41 | } 42 | 43 | /** 44 | * Adds a rule for this subject. 45 | * 46 | * @param Rule $rule 47 | */ 48 | public function addRule(Rule $rule) 49 | { 50 | $this->rules[] = $rule; 51 | } 52 | 53 | /** 54 | * Returns the key for this subject. 55 | * 56 | * @return string 57 | */ 58 | public function getKey() 59 | { 60 | return $this->key; 61 | } 62 | 63 | /** 64 | * Returns the name for this subject. 65 | * 66 | * @return string 67 | */ 68 | public function getName() 69 | { 70 | return $this->name; 71 | } 72 | 73 | /** 74 | * Returns an array of all rules in this subject. 75 | * 76 | * @return Rule[] 77 | */ 78 | public function getRules() 79 | { 80 | return $this->rules; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Rule/Alnum.php: -------------------------------------------------------------------------------- 1 | '{{ name }} may only consist out of numeric and alphabetic characters' 40 | ]; 41 | 42 | /** 43 | * Construct the validation rule. 44 | * 45 | * @param bool $allowSpaces 46 | */ 47 | public function __construct($allowSpaces = self::DISALLOW_SPACES) 48 | { 49 | parent::__construct($allowSpaces ? '~^[\p{L}0-9\s]*$~iu' : '~^[\p{L}0-9]*$~iu'); 50 | } 51 | 52 | /** 53 | * Checks whether $value consists solely out of alphanumeric characters. 54 | * 55 | * @param mixed $value 56 | * @return bool 57 | */ 58 | public function validate($value) 59 | { 60 | return $this->match($this->regex, $value, self::NOT_ALNUM); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Rule/Alpha.php: -------------------------------------------------------------------------------- 1 | '{{ name }} may only consist out of alphabetic characters' 40 | ]; 41 | 42 | /** 43 | * Construct the Alpha rule. 44 | * 45 | * @param bool $allowWhitespace 46 | */ 47 | public function __construct($allowWhitespace = self::DISALLOW_SPACES) 48 | { 49 | parent::__construct($allowWhitespace ? '~^[\p{L}\s]*$~iu' : '~^[\p{L}]*$~ui'); 50 | } 51 | 52 | /** 53 | * Checks whether $value consists solely out of alphabetic characters. 54 | * 55 | * @param mixed $value 56 | * @return bool 57 | */ 58 | public function validate($value) 59 | { 60 | return $this->match($this->regex, $value, self::NOT_ALPHA); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Rule/Equal.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be equal to "{{ testvalue }}"' 32 | ]; 33 | 34 | /** 35 | * @var mixed 36 | */ 37 | protected $value; 38 | 39 | /** 40 | * Construct the equal validator. 41 | * 42 | * @param mixed $value 43 | */ 44 | public function __construct($value) 45 | { 46 | $this->value = $value; 47 | } 48 | 49 | /** 50 | * Validates if each character in $value is a decimal digit. 51 | * 52 | * @param mixed $value 53 | * @return bool 54 | */ 55 | public function validate($value) 56 | { 57 | if ($this->value === $value) { 58 | return true; 59 | } 60 | return $this->error(self::NOT_EQUAL); 61 | } 62 | 63 | /** 64 | * Returns the parameters that may be used in a validation message. 65 | * 66 | * @return array 67 | */ 68 | protected function getMessageParameters() 69 | { 70 | return array_merge(parent::getMessageParameters(), [ 71 | 'testvalue' => $this->value 72 | ]); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Rule/Regex.php: -------------------------------------------------------------------------------- 1 | '{{ name }} is invalid' 32 | ]; 33 | 34 | /** 35 | * The regex that should be matched. 36 | * 37 | * @var string 38 | */ 39 | protected $regex; 40 | 41 | /** 42 | * Construct the Regex rule. 43 | * 44 | * @param string $regex 45 | */ 46 | public function __construct($regex) 47 | { 48 | $this->regex = $regex; 49 | } 50 | 51 | /** 52 | * Validates that the value matches the predefined regex. 53 | * 54 | * @param mixed $value 55 | * @return bool 56 | */ 57 | public function validate($value) 58 | { 59 | return $this->match($this->regex, $value, self::NO_MATCH); 60 | } 61 | 62 | /** 63 | * A method to match against a regex. If it doesn't match, it will log the message $reason. 64 | * 65 | * @param string $regex 66 | * @param mixed $value 67 | * @param string $reason 68 | * @return bool 69 | */ 70 | protected function match($regex, $value, $reason) 71 | { 72 | $result = preg_match($regex, $value); 73 | 74 | if ($result === 0) { 75 | return $this->error($reason); 76 | } 77 | return true; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Rule/Phone.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid phone number', 35 | self::INVALID_FORMAT => '{{ name }} must have a valid phone number format', 36 | ]; 37 | 38 | /** 39 | * @var string 40 | */ 41 | protected $countryCode; 42 | 43 | /** 44 | * Construct the Phone validator. 45 | * 46 | * @param string $countryCode 47 | */ 48 | public function __construct($countryCode) 49 | { 50 | $this->countryCode = $countryCode; 51 | } 52 | 53 | /** 54 | * Validates if $value is a valid phone number. 55 | * 56 | * @param mixed $value 57 | * @return bool 58 | */ 59 | public function validate($value) 60 | { 61 | $phoneUtil = PhoneNumberUtil::getInstance(); 62 | 63 | try { 64 | $numberProto = $phoneUtil->parse($value, $this->countryCode); 65 | if (!$phoneUtil->isValidNumberForRegion($numberProto, $this->countryCode)) { 66 | return $this->error(self::INVALID_VALUE); 67 | } 68 | } catch (NumberParseException $e) { 69 | return $this->error(self::INVALID_FORMAT); 70 | } 71 | 72 | return true; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Rule/Integer.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be an integer', 32 | ]; 33 | 34 | /** 35 | * A constant indicated the integer check is strict 36 | */ 37 | const STRICT = true; 38 | 39 | /** 40 | * A constant indicating the integer check is *not* strict. 41 | */ 42 | const NOT_STRICT = false; 43 | 44 | /** 45 | * A bool denoting whether or not strict checking should be done. 46 | * 47 | * @var bool 48 | */ 49 | private $strict; 50 | 51 | /** 52 | * @param bool $strict 53 | */ 54 | public function __construct($strict = self::NOT_STRICT) 55 | { 56 | $this->strict = $strict; 57 | } 58 | 59 | /** 60 | * Validates if $value represents an integer. 61 | * 62 | * @param mixed $value 63 | * @return bool 64 | */ 65 | public function validate($value) 66 | { 67 | if ($this->strict && is_int($value)) { 68 | return true; 69 | } 70 | 71 | if (!$this->strict && false !== filter_var($value, FILTER_VALIDATE_INT)) { 72 | return true; 73 | } 74 | 75 | return $this->error(self::NOT_AN_INTEGER); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function shouldBreakChainOnError() 82 | { 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Rule/LessThan.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be less than {{ max }}', 32 | ]; 33 | 34 | /** 35 | * The upper boundary. 36 | * 37 | * @var int 38 | */ 39 | protected $max; 40 | 41 | /** 42 | * Construct the LessThan rule. 43 | * 44 | * @param int $max 45 | */ 46 | public function __construct($max) 47 | { 48 | $this->max = $max; 49 | } 50 | 51 | /** 52 | * Checks whether or not $value is less than the max for this rule. 53 | * 54 | * @param mixed $value 55 | * @return bool 56 | */ 57 | public function validate($value) 58 | { 59 | return !$this->notLessThan($value, self::NOT_LESS_THAN); 60 | } 61 | 62 | /** 63 | * Returns whether or not the value is less than the max, and logs an error if it isn't. 64 | * 65 | * @param mixed $value 66 | * @param string $error 67 | * @return bool 68 | */ 69 | protected function notLessThan($value, $error) 70 | { 71 | if ($value >= $this->max) { 72 | $this->error($error); 73 | return true; 74 | } 75 | return false; 76 | } 77 | 78 | /** 79 | * Returns the parameters that may be used in a validation message. 80 | * 81 | * @return array 82 | */ 83 | protected function getMessageParameters() 84 | { 85 | return array_merge(parent::getMessageParameters(), [ 86 | 'max' => $this->max, 87 | ]); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Rule/GreaterThan.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be greater than {{ min }}', 32 | ]; 33 | 34 | /** 35 | * The lower boundary. 36 | * 37 | * @var int 38 | */ 39 | protected $min; 40 | 41 | /** 42 | * Construct the GreaterThan rule. 43 | * 44 | * @param int $min 45 | */ 46 | public function __construct($min) 47 | { 48 | $this->min = $min; 49 | } 50 | 51 | /** 52 | * Checks whether or not $value is greater than the min for this rule. 53 | * 54 | * @param mixed $value 55 | * @return bool 56 | */ 57 | public function validate($value) 58 | { 59 | return !$this->notGreaterThan($value, self::NOT_GREATER_THAN); 60 | } 61 | 62 | /** 63 | * Returns whether or not the value is greater than the min, and logs an error if it isn't. 64 | * 65 | * @param mixed $value 66 | * @param string $error 67 | * @return bool 68 | */ 69 | protected function notGreaterThan($value, $error) 70 | { 71 | if ($value <= $this->min) { 72 | $this->error($error); 73 | return true; 74 | } 75 | return false; 76 | } 77 | 78 | /** 79 | * Returns the parameters that may be used in a validation message. 80 | * 81 | * @return array 82 | */ 83 | protected function getMessageParameters() 84 | { 85 | return array_merge(parent::getMessageParameters(), [ 86 | 'min' => $this->min, 87 | ]); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Failure.php: -------------------------------------------------------------------------------- 1 | key = $key; 42 | $this->reason = $reason; 43 | $this->template = $template; 44 | $this->parameters = $parameters; 45 | } 46 | 47 | /** 48 | * Formats and returns the error message for this failure. 49 | * 50 | * @return string 51 | */ 52 | public function format() 53 | { 54 | $replace = function ($matches) { 55 | if (array_key_exists($matches[1], $this->parameters)) { 56 | return $this->parameters[$matches[1]]; 57 | } 58 | return $matches[0]; 59 | }; 60 | 61 | return preg_replace_callback('~{{\s*([^}\s]+)\s*}}~', $replace, $this->template); 62 | } 63 | 64 | /** 65 | * Returns the key for this failure. 66 | * 67 | * @return string 68 | */ 69 | public function getKey() 70 | { 71 | return $this->key; 72 | } 73 | 74 | /** 75 | * Returns the reason for failure. 76 | * 77 | * @return string 78 | */ 79 | public function getReason() 80 | { 81 | return $this->reason; 82 | } 83 | 84 | /** 85 | * Overwrites the message template. 86 | * 87 | * @param string $template 88 | */ 89 | public function overwriteMessageTemplate($template) 90 | { 91 | $this->template = $template; 92 | } 93 | 94 | /** 95 | * @param string $key 96 | */ 97 | public function overwriteKey($key) 98 | { 99 | $this->key = $key; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Rule/Length.php: -------------------------------------------------------------------------------- 1 | '{{ name }} is too short and must be {{ length }} characters long', 37 | self::TOO_LONG => '{{ name }} is too long and must be {{ length }} characters long', 38 | ]; 39 | 40 | /** 41 | * The length the value should have. 42 | * 43 | * @var int 44 | */ 45 | protected $length; 46 | 47 | /** 48 | * Construct the Length validator. 49 | * 50 | * @param int $length 51 | */ 52 | public function __construct($length) 53 | { 54 | $this->length = $length; 55 | } 56 | 57 | /** 58 | * Attempts to see if the length of the value is exactly the number expected and returns the result as a bool. 59 | * 60 | * @param mixed $value 61 | * @return bool 62 | */ 63 | public function validate($value) 64 | { 65 | $actualLength = strlen($value); 66 | 67 | if ($actualLength > $this->length) { 68 | return $this->error(self::TOO_LONG); 69 | } 70 | if ($actualLength < $this->length) { 71 | return $this->error(self::TOO_SHORT); 72 | } 73 | return true; 74 | } 75 | 76 | /** 77 | * Returns the parameters that may be used in a validation message. 78 | * 79 | * @return array 80 | */ 81 | protected function getMessageParameters() 82 | { 83 | return array_merge(parent::getMessageParameters(), [ 84 | 'length' => $this->length 85 | ]); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Rule/Url.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid URL', 37 | self::INVALID_SCHEME => '{{ name }} must have one of the following schemes: {{ schemes }}', 38 | ]; 39 | 40 | /** 41 | * @var array 42 | */ 43 | protected $schemes = []; 44 | 45 | /** 46 | * Construct the URL rule. 47 | * 48 | * @param array $schemes 49 | */ 50 | public function __construct(array $schemes = []) 51 | { 52 | $this->schemes = $schemes; 53 | } 54 | 55 | /** 56 | * Validates if the value is a valid URL. 57 | * 58 | * @param mixed $value 59 | * @return bool 60 | */ 61 | public function validate($value) 62 | { 63 | $url = filter_var($value, FILTER_VALIDATE_URL); 64 | 65 | if ($url !== false) { 66 | return $this->validateScheme($value); 67 | } 68 | return $this->error(self::INVALID_URL); 69 | } 70 | 71 | /** 72 | * Validates and returns whether or not the URL has a certain scheme. 73 | * 74 | * @param string $value 75 | * @return bool 76 | */ 77 | protected function validateScheme($value) 78 | { 79 | if (count($this->schemes) > 0 && !in_array(parse_url($value, PHP_URL_SCHEME), $this->schemes)) { 80 | return $this->error(self::INVALID_SCHEME); 81 | } 82 | return true; 83 | } 84 | 85 | /** 86 | * @return array 87 | */ 88 | protected function getMessageParameters() 89 | { 90 | return array_merge(parent::getMessageParameters(), [ 91 | 'schemes' => implode(', ', $this->schemes) 92 | ]); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/ValidationResult.php: -------------------------------------------------------------------------------- 1 | isValid = $isValid; 48 | $this->failures = $failures; 49 | $this->values = $values; 50 | } 51 | 52 | /** 53 | * Returns whether or not the validator has validated the values. 54 | * 55 | * @return bool 56 | */ 57 | public function isValid() 58 | { 59 | return $this->isValid; 60 | } 61 | 62 | /** 63 | * Returns whether or not the validator has validated the values. 64 | * 65 | * @return bool 66 | */ 67 | public function isNotValid() 68 | { 69 | return !$this->isValid; 70 | } 71 | 72 | /** 73 | * Returns the array of messages that were collected during validation. 74 | * 75 | * @return array 76 | */ 77 | public function getMessages() 78 | { 79 | if ($this->messages === null) { 80 | $this->messages = []; 81 | foreach ($this->failures as $failure) { 82 | $this->messages[$failure->getKey()][$failure->getReason()] = $failure->format(); 83 | } 84 | } 85 | return $this->messages; 86 | } 87 | 88 | /** 89 | * @return Failure[] 90 | */ 91 | public function getFailures() 92 | { 93 | return $this->failures; 94 | } 95 | 96 | /** 97 | * Returns all validated values 98 | * 99 | * @return array 100 | */ 101 | public function getValues() 102 | { 103 | return $this->values; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Rule/InArray.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be in the defined set of values', 42 | ]; 43 | 44 | /** 45 | * The array that contains the values to check. 46 | * 47 | * @var array 48 | */ 49 | protected $array = []; 50 | 51 | /** 52 | * A bool denoting whether or not strict checking should be done. 53 | * 54 | * @var bool 55 | */ 56 | protected $strict; 57 | 58 | /** 59 | * Construct the InArray rule. 60 | * 61 | * @param array $array 62 | * @param bool $strict 63 | */ 64 | public function __construct(array $array, $strict = self::STRICT) 65 | { 66 | $this->array = $array; 67 | $this->strict = $strict; 68 | } 69 | 70 | /** 71 | * Validates if $value is in the predefined array. 72 | * 73 | * @param mixed $value 74 | * @return bool 75 | */ 76 | public function validate($value) 77 | { 78 | if (in_array($value, $this->array, $this->strict)) { 79 | return true; 80 | } 81 | return $this->error(self::NOT_IN_ARRAY); 82 | } 83 | 84 | /** 85 | * Returns the parameters that may be used in a validation message. 86 | * 87 | * @return array 88 | */ 89 | protected function getMessageParameters() 90 | { 91 | $quote = function ($value) { 92 | return '"' . $value . '"'; 93 | }; 94 | 95 | return array_merge(parent::getMessageParameters(), [ 96 | 'values' => implode(', ', array_map($quote, $this->array)) 97 | ]); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Rule/CreditCard.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must have a valid credit card number format', 48 | self::INVALID_CHECKSUM => '{{ name }} must be a valid credit card number', 49 | ]; 50 | 51 | /** 52 | * Validates if the value is a valid credit card number. 53 | * 54 | * @param mixed $value 55 | * @return bool 56 | */ 57 | public function validate($value) 58 | { 59 | if (!$this->validateFormat($value)) { 60 | return $this->error(self::INVALID_FORMAT); 61 | } elseif (!$this->validateChecksum($value)) { 62 | return $this->error(self::INVALID_CHECKSUM); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | /** 69 | * @param $value 70 | * 71 | * @return bool 72 | */ 73 | private function validateChecksum($value) 74 | { 75 | $luhn = new Luhn(); 76 | 77 | return $luhn->isValid($value); 78 | } 79 | 80 | /** 81 | * @param $value 82 | * 83 | * @return bool 84 | */ 85 | private function validateFormat($value) 86 | { 87 | foreach ($this->validationRegExps as $validationRegExp) { 88 | if (preg_match($validationRegExp, $value) === 1) { 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![image](https://cloud.githubusercontent.com/assets/6495166/7207286/8b48105e-e538-11e4-9dfa-97c7fb2398aa.png)](http://validator.particle-php.com) 2 | === 3 | 4 | [![Travis-CI](https://img.shields.io/travis/particle-php/Validator/master.svg)](https://travis-ci.org/particle-php/Validator) 5 | [![Packagist](https://img.shields.io/packagist/v/particle/validator.svg)](https://packagist.org/packages/particle/validator) 6 | [![Packagist downloads](https://img.shields.io/packagist/dt/particle/validator.svg)](https://packagist.org/packages/particle/validator) 7 | [![Scrutinizer](https://img.shields.io/scrutinizer/g/particle-php/Validator.svg)](https://scrutinizer-ci.com/g/particle-php/Validator/?branch=master) 8 | [![Scrutinizer](https://img.shields.io/scrutinizer/coverage/g/particle-php/Validator/master.svg)](https://scrutinizer-ci.com/g/particle-php/Validator/?branch=master) 9 | 10 | *Particle\Validator* is a very small validation library, with the easiest and most usable API we could possibly create. 11 | 12 | ## Install 13 | To easily include *Particle\Validator* into your project, install it via [composer](https://getcomposer.org) using the command line: 14 | 15 | ```bash 16 | composer require particle/validator 17 | ``` 18 | 19 | ## Small usage example 20 | 21 | ```php 22 | use Particle\Validator\Validator; 23 | 24 | $v = new Validator; 25 | 26 | $v->required('user.first_name')->lengthBetween(2, 50)->alpha(); 27 | $v->required('user.last_name')->lengthBetween(2, 50)->alpha(); 28 | $v->required('newsletter')->bool(); 29 | 30 | $result = $v->validate([ 31 | 'user' => [ 32 | 'first_name' => 'John', 33 | 'last_name' => 'D', 34 | ], 35 | 'newsletter' => true, 36 | ]); 37 | 38 | $result->isValid(); // bool(false). 39 | $result->getMessages(); 40 | /** 41 | * array(1) { 42 | * ["user.last_name"]=> array(1) { 43 | * ["Length::TOO_SHORT"]=> string(53) "last_name is too short and must be 2 characters long." 44 | * } 45 | * } 46 | */ 47 | ``` 48 | 49 | ## Functional features 50 | 51 | * Validate an array of data 52 | * Get an array of error messages 53 | * Overwrite the default error messages on rules, or error messages on specific values 54 | * Get the validated values of an array 55 | * Validate different contexts (insert, update, etc.) inheriting validations of the default context 56 | * [A large set of default validation rules](http://validator.particle-php.com/en/latest/rules/) 57 | * Ability to extend the validator to add your own custom rules 58 | 59 | ## Non functional features 60 | 61 | * Easy to write (IDE auto-completion for easy development) 62 | * Easy to read (improves peer review) 63 | * Ability to separate controller and view logic 64 | * Fully documented: [validator.particle-php.com](http://validator.particle-php.com) 65 | * Fully tested: [Scrutinizer](https://scrutinizer-ci.com/g/particle-php/Validator/) 66 | * Zero dependencies 67 | 68 | === 69 | 70 | Find more information and advanced usage examples at [validator.particle-php.com](http://validator.particle-php.com) 71 | -------------------------------------------------------------------------------- /src/Rule/LengthBetween.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be {{ max }} characters or shorter', 37 | self::TOO_SHORT => '{{ name }} must be {{ min }} characters or longer' 38 | ]; 39 | 40 | /** 41 | * The upper boundary for the length of the value. 42 | * 43 | * @var int 44 | */ 45 | protected $max; 46 | 47 | /** 48 | * The lower boundary for the length of the value. 49 | * 50 | * @var int 51 | */ 52 | protected $min; 53 | 54 | /** 55 | * @param int $min 56 | * @param int|null $max 57 | */ 58 | public function __construct($min, $max) 59 | { 60 | $this->min = $min; 61 | $this->max = $max; 62 | } 63 | 64 | /** 65 | * Validates that the length of the value is between min and max. 66 | * 67 | * @param mixed $value 68 | * @return bool 69 | */ 70 | public function validate($value) 71 | { 72 | $length = strlen($value); 73 | 74 | return !$this->tooSmall($length, self::TOO_SHORT) && !$this->tooLarge($length, self::TOO_LONG); 75 | } 76 | 77 | /** 78 | * Returns whether or not the value is too long, and logs an error if it is. 79 | * 80 | * @param mixed $value 81 | * @param string $error 82 | * @return bool 83 | */ 84 | protected function tooLarge($value, $error) 85 | { 86 | if ($this->max !== null) { 87 | return parent::tooLarge($value, $error); 88 | } 89 | return false; 90 | } 91 | 92 | /** 93 | * Returns the parameters that may be used in a validation message. 94 | * 95 | * @return array 96 | */ 97 | protected function getMessageParameters() 98 | { 99 | return array_merge(parent::getMessageParameters(), [ 100 | 'min' => $this->min, 101 | 'max' => $this->max 102 | ]); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Rule/Callback.php: -------------------------------------------------------------------------------- 1 | '{{ name }} is invalid', 37 | ]; 38 | 39 | /** 40 | * @var callable 41 | */ 42 | protected $callback; 43 | 44 | /** 45 | * @var Container 46 | */ 47 | protected $input; 48 | 49 | /** 50 | * Construct the Callback validator. 51 | * 52 | * @param callable $callback 53 | */ 54 | public function __construct(callable $callback) 55 | { 56 | $this->callback = $callback; 57 | } 58 | 59 | /** 60 | * Validates $value by calling the callback. 61 | * 62 | * @param mixed $value 63 | * @return bool 64 | */ 65 | public function validate($value) 66 | { 67 | try { 68 | $result = call_user_func($this->callback, $value, $this->values); 69 | 70 | if ($result === true) { 71 | return true; 72 | } 73 | return $this->error(self::INVALID_VALUE); 74 | } catch (InvalidValueException $exception) { 75 | $reason = $exception->getIdentifier(); 76 | $this->messageTemplates[$reason] = $exception->getMessage(); 77 | 78 | return $this->error($reason); 79 | } 80 | } 81 | 82 | /** 83 | * {@inheritdoc} 84 | */ 85 | protected function getMessageParameters() 86 | { 87 | return array_merge(parent::getMessageParameters(), [ 88 | 'callback' => $this->getCallbackAsString($this->callback), 89 | ]); 90 | } 91 | 92 | /** 93 | * Validates the value according to this rule, and returns the result as a bool. 94 | * 95 | * @param string $key 96 | * @param Container $input 97 | * @return bool 98 | */ 99 | public function isValid($key, Container $input) 100 | { 101 | $this->values = $input->getArrayCopy(); 102 | 103 | return parent::isValid($key, $input); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Rule/Datetime.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid date', 32 | ]; 33 | 34 | /** 35 | * @var string 36 | */ 37 | protected $format; 38 | 39 | /** 40 | * Construct the Datetime validator. 41 | * 42 | * @param string $format 43 | */ 44 | public function __construct($format = null) 45 | { 46 | $this->format = $format; 47 | } 48 | 49 | /** 50 | * Validates if $value is in the correct date / time format and that it's a valid date. 51 | * 52 | * @param mixed $value 53 | * @return bool 54 | */ 55 | public function validate($value) 56 | { 57 | if (!($this->datetime($value, $this->format) instanceof \DateTime)) { 58 | return $this->error(self::INVALID_VALUE); 59 | } 60 | return true; 61 | } 62 | 63 | /** 64 | * Takes $value and $format and attempts to build a valid DateTime object with it. 65 | * 66 | * @param string $value 67 | * @param string $format 68 | * @return \DateTime|false 69 | */ 70 | protected function datetime($value, $format = null) 71 | { 72 | if ($format !== null) { 73 | $dateTime = date_create_from_format($format, $value); 74 | 75 | if ($dateTime instanceof \DateTime) { 76 | return $this->checkDate($dateTime, $format, $value); 77 | } 78 | return false; 79 | } 80 | return @date_create($value); 81 | } 82 | 83 | /** 84 | * Checks if $dateTime is a valid date-time object, and if the formatted date is the same as the value passed. 85 | * 86 | * @param \DateTime $dateTime 87 | * @param string $format 88 | * @param mixed $value 89 | * @return \DateTime|false 90 | */ 91 | protected function checkDate($dateTime, $format, $value) 92 | { 93 | $equal = (string) $dateTime->format($format) === (string) $value; 94 | 95 | $warningCount = $dateTime->getLastErrors()['warning_count'] ?? 0; 96 | if ($warningCount === 0 && $equal) { 97 | return $dateTime; 98 | } 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Rule/Each.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be an array', 33 | self::NOT_AN_ARRAY_ITEM => 'Each {{ name }} item must be an array', 34 | ]; 35 | 36 | /** 37 | * @var callable 38 | */ 39 | protected $callback; 40 | 41 | /** 42 | * @param callable $callback 43 | */ 44 | public function __construct(callable $callback) 45 | { 46 | $this->callback = $callback; 47 | } 48 | 49 | /** 50 | * Validates if $value is array, validate each inner array of $value, and return result. 51 | * 52 | * @param mixed $value 53 | * @return bool 54 | */ 55 | public function validate($value) 56 | { 57 | if (!is_array($value)) { 58 | return $this->error(self::NOT_AN_ARRAY); 59 | } 60 | 61 | $result = true; 62 | foreach ($value as $index => $innerValue) { 63 | if (!is_array($innerValue)) { 64 | return $this->error(self::NOT_AN_ARRAY_ITEM); 65 | } 66 | 67 | $result = $this->validateValue($index, $innerValue) && $result; 68 | } 69 | return $result; 70 | } 71 | 72 | /** 73 | * This method will spawn a new validator, validate an inner array, and return its result. 74 | * 75 | * @param string $index 76 | * @param mixed $value 77 | * @return bool 78 | */ 79 | protected function validateValue($index, $value) 80 | { 81 | $innerValidator = new Validator(); 82 | 83 | call_user_func($this->callback, $innerValidator); 84 | 85 | $result = $innerValidator->validate($value); 86 | 87 | if (!$result->isValid()) { 88 | $this->handleError($index, $result); 89 | return false; 90 | } 91 | 92 | return true; 93 | } 94 | 95 | /** 96 | * @param mixed $index 97 | * @param ValidationResult $result 98 | */ 99 | protected function handleError($index, $result) 100 | { 101 | foreach ($result->getFailures() as $failure) { 102 | $failure->overwriteKey( 103 | sprintf('%s.%s.%s', $this->key, $index, $failure->getKey()) 104 | ); 105 | 106 | $this->messageStack->append($failure); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Rule/Between.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be less than or equal to {{ max }}', 37 | self::TOO_SMALL => '{{ name }} must be greater than or equal to {{ min }}', 38 | ]; 39 | 40 | /** 41 | * The lower boundary. 42 | * 43 | * @var int 44 | */ 45 | protected $min; 46 | 47 | /** 48 | * The upper boundary. 49 | * 50 | * @var int 51 | */ 52 | protected $max; 53 | 54 | /** 55 | * Construct the Between rule. 56 | * 57 | * @param int $min 58 | * @param int $max 59 | */ 60 | public function __construct($min, $max) 61 | { 62 | $this->min = $min; 63 | $this->max = $max; 64 | } 65 | 66 | /** 67 | * Checks whether or not $value is between min and max for this rule. 68 | * 69 | * @param mixed $value 70 | * @return bool 71 | */ 72 | public function validate($value) 73 | { 74 | return !$this->tooSmall($value, self::TOO_SMALL) && !$this->tooLarge($value, self::TOO_BIG); 75 | } 76 | 77 | /** 78 | * Returns whether or not the value is too small, and logs an error if it is. 79 | * 80 | * @param mixed $value 81 | * @param string $error 82 | * @return bool 83 | */ 84 | protected function tooSmall($value, $error) 85 | { 86 | if ($value < $this->min) { 87 | $this->error($error); 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | /** 94 | * Returns whether or not the value is too large, and logs an error if it is. 95 | * 96 | * @param mixed $value 97 | * @param string $error 98 | * @return bool 99 | */ 100 | protected function tooLarge($value, $error) 101 | { 102 | if ($value > $this->max) { 103 | $this->error($error); 104 | return true; 105 | } 106 | return false; 107 | } 108 | 109 | /** 110 | * Returns the parameters that may be used in a validation message. 111 | * 112 | * @return array 113 | */ 114 | protected function getMessageParameters() 115 | { 116 | return array_merge(parent::getMessageParameters(), [ 117 | 'min' => $this->min, 118 | 'max' => $this->max 119 | ]); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Value/Container.php: -------------------------------------------------------------------------------- 1 | values = $values; 33 | } 34 | 35 | /** 36 | * Determines whether or not the container has a value for key $key. 37 | * 38 | * @param string $key 39 | * @return bool 40 | */ 41 | public function has($key) 42 | { 43 | return $this->traverse($key, false); 44 | } 45 | 46 | /** 47 | * Returns the value for the key $key, or null if the value doesn't exist. 48 | * 49 | * @param string $key 50 | * @return mixed 51 | */ 52 | public function get($key) 53 | { 54 | return $this->traverse($key, true); 55 | } 56 | 57 | /** 58 | * Set the value of $key to $value. 59 | * 60 | * @param string $key 61 | * @param mixed $value 62 | * @return $this 63 | */ 64 | public function set($key, $value) 65 | { 66 | if (strpos($key, '.') !== false) { 67 | return $this->setTraverse($key, $value); 68 | } 69 | $this->values[$key] = $value; 70 | return $this; 71 | } 72 | 73 | /** 74 | * Returns a plain array representation of the Value\Container object. 75 | * 76 | * @return array 77 | */ 78 | public function getArrayCopy() 79 | { 80 | return $this->values; 81 | } 82 | 83 | /** 84 | * Traverses the key using dot notation. Based on the second parameter, it will return the value or if it was set. 85 | * 86 | * @param string $key 87 | * @param bool $returnValue 88 | * @return mixed 89 | */ 90 | protected function traverse($key, $returnValue = true) 91 | { 92 | $value = $this->values; 93 | foreach (explode('.', $key) as $part) { 94 | if (!is_array($value) || !array_key_exists($part, $value)) { 95 | return false; 96 | } 97 | $value = $value[$part]; 98 | } 99 | return $returnValue ? $value : true; 100 | } 101 | 102 | /** 103 | * Uses dot-notation to set a value. 104 | * 105 | * @param string $key 106 | * @param mixed $value 107 | * @return $this 108 | */ 109 | protected function setTraverse($key, $value) 110 | { 111 | $parts = explode('.', $key); 112 | $ref = &$this->values; 113 | 114 | foreach ($parts as $i => $part) { 115 | if ($i < count($parts) - 1 && (!isset($ref[$part]) || !is_array($ref[$part]))) { 116 | $ref[$part] = []; 117 | } 118 | $ref = &$ref[$part]; 119 | } 120 | 121 | $ref = $value; 122 | return $this; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Rule/Hash.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must be a valid hash' 49 | ]; 50 | 51 | /** 52 | * @var string 53 | */ 54 | protected $hashAlgorithm; 55 | 56 | /** 57 | * @var bool 58 | */ 59 | protected $allowUppercase; 60 | 61 | /** 62 | * Construct the Hash validator. 63 | * 64 | * @param string $hashAlgorithm 65 | * @param bool $allowUppercase 66 | */ 67 | public function __construct($hashAlgorithm, $allowUppercase = self::DISALLOW_UPPERCASE) 68 | { 69 | $this->hashAlgorithm = $hashAlgorithm; 70 | $this->allowUppercase = $allowUppercase; 71 | 72 | $this->messageTemplates = [ 73 | self::INVALID_FORMAT => sprintf('{{ name }} must be a valid %s hash', $hashAlgorithm) 74 | ]; 75 | } 76 | 77 | /** 78 | * Validates if the value is a valid cryptographic hash. 79 | * 80 | * @param mixed $value 81 | * @return bool 82 | * @throws Exception 83 | */ 84 | public function validate($value) 85 | { 86 | $algorithmsLengths = [ 87 | self::ALGO_MD5 => 32, 88 | self::ALGO_SHA1 => 40, 89 | self::ALGO_SHA256 => 64, 90 | self::ALGO_SHA512 => 128, 91 | self::ALGO_CRC32 => 8, 92 | ]; 93 | 94 | if (!isset($algorithmsLengths[$this->hashAlgorithm])) { 95 | throw new Exception('an invalid hashAlgorithm has been provided.'); 96 | } 97 | 98 | if ($this->validateHexString($value, $algorithmsLengths[$this->hashAlgorithm])) { 99 | return true; 100 | } 101 | 102 | return $this->error(self::INVALID_FORMAT); 103 | } 104 | 105 | /** 106 | * @param string $value 107 | * @param int $length 108 | * 109 | * @return bool 110 | */ 111 | private function validateHexString($value, $length) 112 | { 113 | $caseSensitive = $this->allowUppercase ? 'i' : ''; 114 | 115 | return preg_match(sprintf('/^[0-9a-f]{%s}$/%s', $length, $caseSensitive), $value) === 1; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/Rule/Uuid.php: -------------------------------------------------------------------------------- 1 | '~^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$~i', 41 | self::UUID_NIL => '~^[0]{8}-[0]{4}-[0]{4}-[0]{4}-[0]{12}$~i', 42 | self::UUID_V1 => '~^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', 43 | self::UUID_V2 => '~^[0-9a-f]{8}-[0-9a-f]{4}-2[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', 44 | self::UUID_V3 => '~^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', 45 | self::UUID_V4 => '~^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', 46 | self::UUID_V5 => '~^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', 47 | ]; 48 | 49 | /** 50 | * An array of names for all the versions 51 | * 52 | * @var array 53 | */ 54 | protected $versionNames = [ 55 | self::UUID_VALID => 'valid format', 56 | self::UUID_NIL => 'NIL', 57 | self::UUID_V1 => 'v1', 58 | self::UUID_V2 => 'v2', 59 | self::UUID_V3 => 'v3', 60 | self::UUID_V4 => 'v4', 61 | self::UUID_V5 => 'v5', 62 | ]; 63 | 64 | /** 65 | * The message templates which can be returned by this validator. 66 | * 67 | * @var array 68 | */ 69 | protected $messageTemplates = [ 70 | self::INVALID_UUID => '{{ name }} must be a valid UUID ({{ version }})' 71 | ]; 72 | 73 | /** 74 | * The version of the UUID you'd like to check. 75 | * 76 | * @var int 77 | */ 78 | protected $version; 79 | 80 | /** 81 | * Construct the UUID validation rule. 82 | * 83 | * @param int $version 84 | */ 85 | public function __construct($version = self::UUID_VALID) 86 | { 87 | if ($version >= (self::UUID_V5 * 2) || $version < 0) { 88 | throw new \InvalidArgumentException( 89 | 'Invalid UUID version mask given. Please choose one of the constants on the Uuid class.' 90 | ); 91 | } 92 | 93 | $this->version = $version; 94 | } 95 | 96 | /** 97 | * Validates if the value is a valid UUID of an allowed version. 98 | * 99 | * @param string $value 100 | * @return bool 101 | */ 102 | public function validate($value) 103 | { 104 | foreach ($this->regexes as $version => $regex) { 105 | if (($version & $this->version) === $version && preg_match($regex, $value) > 0) { 106 | return true; 107 | } 108 | } 109 | return $this->error(self::INVALID_UUID); 110 | } 111 | 112 | /** 113 | * Returns the parameters that may be used in a validation message. 114 | * 115 | * @return array 116 | */ 117 | protected function getMessageParameters() 118 | { 119 | $versions = []; 120 | foreach (array_keys($this->regexes) as $version) { 121 | if (($version & $this->version) === $version) { 122 | $versions[] = $this->versionNames[$version]; 123 | } 124 | } 125 | 126 | return array_merge(parent::getMessageParameters(), [ 127 | 'version' => implode(', ', $versions) 128 | ]); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Rule/Required.php: -------------------------------------------------------------------------------- 1 | '{{ key }} must be provided, but does not exist' 36 | ]; 37 | 38 | /** 39 | * Denotes whether or not the chain should be stopped after this rule. 40 | * 41 | * @var bool 42 | */ 43 | protected $shouldBreak = false; 44 | 45 | /** 46 | * Indicates if the value is required. 47 | * 48 | * @var bool 49 | */ 50 | protected $required; 51 | 52 | /** 53 | * Optionally contains a callable to overwrite the required requirement on time of validation. 54 | * 55 | * @var callable 56 | */ 57 | protected $requiredCallback; 58 | 59 | /** 60 | * Contains the input container. 61 | * 62 | * @var Container 63 | */ 64 | protected $input; 65 | 66 | /** 67 | * Construct the Required validator. 68 | * 69 | * @param bool $required 70 | */ 71 | public function __construct($required) 72 | { 73 | $this->required = $required; 74 | } 75 | 76 | /** 77 | * @return bool 78 | */ 79 | public function shouldBreakChain() 80 | { 81 | return $this->shouldBreak; 82 | } 83 | 84 | /** 85 | * Does nothing, because validity is determined in isValid. 86 | * 87 | * @param mixed $value 88 | * @return bool 89 | */ 90 | public function validate($value) 91 | { 92 | return true; 93 | } 94 | 95 | /** 96 | * Determines whether or not the key is set when required, and if there is a value if allow empty is false. 97 | * 98 | * @param string $key 99 | * @param Container $input 100 | * @return bool 101 | */ 102 | public function isValid($key, Container $input) 103 | { 104 | $this->shouldBreak = false; 105 | $this->required = $this->isRequired($input); 106 | 107 | if (!$input->has($key)) { 108 | $this->shouldBreak = true; 109 | 110 | if ($this->required) { 111 | return $this->error(self::NON_EXISTENT_KEY); 112 | } 113 | } 114 | 115 | return $this->validate($input->get($key)); 116 | } 117 | 118 | /** 119 | * Set a callable to potentially alter the required requirement at the time of validation. 120 | * 121 | * This may be incredibly useful for conditional validation. 122 | * 123 | * @param callable|bool $required 124 | * @return $this 125 | */ 126 | public function setRequired($required) 127 | { 128 | if (is_callable($required)) { 129 | return $this->setRequiredCallback($required); 130 | } 131 | 132 | return $this->overwriteRequired((bool) $required); 133 | } 134 | 135 | /** 136 | * Overwrite the required requirement after instantiation of this object. 137 | * 138 | * @param bool $required 139 | * @return $this 140 | */ 141 | protected function overwriteRequired($required) 142 | { 143 | $this->required = $required; 144 | return $this; 145 | } 146 | 147 | /** 148 | * Set the required callback, and return $this. 149 | * 150 | * @param callable $requiredCallback 151 | * @return $this 152 | */ 153 | protected function setRequiredCallback(callable $requiredCallback) 154 | { 155 | $this->requiredCallback = $requiredCallback; 156 | return $this; 157 | } 158 | 159 | /** 160 | * {@inheritdoc} 161 | */ 162 | protected function getMessageParameters() 163 | { 164 | return array_merge(parent::getMessageParameters(), [ 165 | 'required' => $this->required, 166 | 'callback' => $this->getCallbackAsString($this->requiredCallback) 167 | ]); 168 | } 169 | 170 | /** 171 | * Determines if the value is required. 172 | * 173 | * @param Container $input 174 | * @return bool 175 | */ 176 | protected function isRequired(Container $input) 177 | { 178 | if (isset($this->requiredCallback)) { 179 | $this->required = call_user_func_array($this->requiredCallback, [$input->getArrayCopy()]); 180 | } 181 | return $this->required; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/MessageStack.php: -------------------------------------------------------------------------------- 1 | getKey(); 52 | $reason = $failure->getReason(); 53 | 54 | if (isset($this->defaultMessages[$reason])) { 55 | $failure->overwriteMessageTemplate($this->defaultMessages[$reason]); 56 | } 57 | 58 | if (isset($this->overwrites[$key][$reason])) { 59 | $failure->overwriteMessageTemplate($this->overwrites[$key][$reason]); 60 | } 61 | 62 | $this->failures[] = $failure; 63 | } 64 | 65 | /** 66 | * Returns an overwrite (either default or specific message) for the reason and key, or false. 67 | * 68 | * @param string $reason 69 | * @param string $key 70 | * @return string|bool 71 | */ 72 | public function getOverwrite($reason, $key) 73 | { 74 | if ($this->hasOverwrite($key, $reason)) { 75 | return $this->overwrites[$key][$reason]; 76 | } 77 | 78 | if (array_key_exists($reason, $this->defaultMessages)) { 79 | return $this->defaultMessages[$reason]; 80 | } 81 | 82 | return false; 83 | } 84 | 85 | /** 86 | * Overwrite key-validator specific messages (so [first_name => [Length::TOO_SHORT => 'Message']]). 87 | * 88 | * @param array $messages 89 | * @return $this 90 | */ 91 | public function overwriteMessages(array $messages) 92 | { 93 | $this->overwrites = $messages; 94 | return $this; 95 | } 96 | 97 | /** 98 | * Overwrite the default validator-specific messages (so [Length::TOO_SHORT => 'Generic message']. 99 | * 100 | * @param array $messages 101 | * @return $this 102 | */ 103 | public function overwriteDefaultMessages(array $messages) 104 | { 105 | $this->defaultMessages = $messages; 106 | return $this; 107 | } 108 | 109 | /** 110 | * Merges an existing MessageStack into this one by taking over it's overwrites and defaults. 111 | * 112 | * @param MessageStack $messageStack 113 | */ 114 | public function merge(MessageStack $messageStack) 115 | { 116 | $this->mergeDefaultMessages($messageStack); 117 | $this->mergeOverwrites($messageStack); 118 | } 119 | 120 | /** 121 | * Reset the messages to an empty array. 122 | * 123 | * @return $this 124 | */ 125 | public function reset() 126 | { 127 | $this->failures = []; 128 | return $this; 129 | } 130 | 131 | /** 132 | * Merges the default messages from $messageStack to this MessageStack. 133 | * 134 | * @param MessageStack $messageStack 135 | */ 136 | protected function mergeDefaultMessages(MessageStack $messageStack) 137 | { 138 | foreach ($messageStack->defaultMessages as $key => $message) { 139 | if (!array_key_exists($key, $this->defaultMessages)) { 140 | $this->defaultMessages[$key] = $message; 141 | } 142 | } 143 | } 144 | 145 | /** 146 | * Merges the message overwrites from $messageStack to this MessageStack. 147 | * 148 | * @param MessageStack $messageStack 149 | */ 150 | protected function mergeOverwrites(MessageStack $messageStack) 151 | { 152 | foreach ($messageStack->overwrites as $key => $reasons) { 153 | foreach ($reasons as $reason => $message) { 154 | if (!$this->hasOverwrite($key, $reason)) { 155 | $this->overwrites[$key][$reason] = $message; 156 | } 157 | } 158 | } 159 | } 160 | 161 | /** 162 | * Returns whether an overwrite exists for the key $key with reason $reason. 163 | * 164 | * @param string $key 165 | * @param string $reason 166 | * @return bool 167 | */ 168 | protected function hasOverwrite($key, $reason) 169 | { 170 | return isset($this->overwrites[$key][$reason]); 171 | } 172 | 173 | /** 174 | * Returns an array of all failures of the last validation run. 175 | * 176 | * @return Failure[] 177 | */ 178 | public function getFailures() 179 | { 180 | return $this->failures; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/Rule/NotEmpty.php: -------------------------------------------------------------------------------- 1 | '{{ name }} must not be empty', 36 | ]; 37 | 38 | /** 39 | * Denotes whether or not the chain should be stopped after this rule. 40 | * 41 | * @var bool 42 | */ 43 | protected $shouldBreak = false; 44 | 45 | /** 46 | * Indicates if the value can be empty. 47 | * 48 | * @var bool 49 | */ 50 | protected $allowEmpty; 51 | 52 | /** 53 | * Optionally contains a callable to overwrite the allow empty requirement on time of validation. 54 | * 55 | * @var callable 56 | */ 57 | protected $allowEmptyCallback; 58 | 59 | /** 60 | * Contains the input container. 61 | * 62 | * @var Container 63 | */ 64 | protected $input; 65 | 66 | /** 67 | * Construct the NotEmpty validator. 68 | * 69 | * @param bool $allowEmpty 70 | */ 71 | public function __construct($allowEmpty) 72 | { 73 | $this->allowEmpty = (bool) $allowEmpty; 74 | } 75 | 76 | /** 77 | * @return bool 78 | */ 79 | public function shouldBreakChain() 80 | { 81 | return $this->shouldBreak; 82 | } 83 | 84 | /** 85 | * Ensures a certain key has a value. 86 | * 87 | * @param mixed $value 88 | * @return bool 89 | */ 90 | public function validate($value) 91 | { 92 | $this->shouldBreak = false; 93 | if ($this->isEmpty($value)) { 94 | $this->shouldBreak = true; 95 | 96 | return !$this->allowEmpty($this->input) ? $this->error(self::EMPTY_VALUE) : true; 97 | } 98 | return true; 99 | } 100 | 101 | /** 102 | * Determines whether or not value $value is to be considered "empty". 103 | * 104 | * @param mixed $value 105 | * @return bool 106 | */ 107 | protected function isEmpty($value) 108 | { 109 | if (is_string($value) && strlen($value) === 0) { 110 | return true; 111 | } elseif ($value === null) { 112 | return true; 113 | } elseif (is_array($value) && count($value) === 0) { 114 | return true; 115 | } 116 | 117 | return false; 118 | } 119 | 120 | /** 121 | * @inheritdoc 122 | * 123 | * @param string $key 124 | * @param Container $input 125 | * @return bool 126 | */ 127 | public function isValid($key, Container $input) 128 | { 129 | $this->input = $input; 130 | 131 | return $this->validate($input->get($key)); 132 | } 133 | 134 | /** 135 | * Set a callable or boolean value to potentially alter the allow empty requirement at the time of validation. 136 | * 137 | * This may be incredibly useful for conditional validation. 138 | * 139 | * @param callable|bool $allowEmpty 140 | * @return $this 141 | */ 142 | public function setAllowEmpty($allowEmpty) 143 | { 144 | if (is_callable($allowEmpty)) { 145 | return $this->setAllowEmptyCallback($allowEmpty); 146 | } 147 | return $this->overwriteAllowEmpty($allowEmpty); 148 | } 149 | 150 | /** 151 | * {@inheritdoc} 152 | */ 153 | protected function getMessageParameters() 154 | { 155 | return array_merge(parent::getMessageParameters(), [ 156 | 'allowEmpty' => $this->allowEmpty, 157 | 'callback' => $this->getCallbackAsString($this->allowEmptyCallback) 158 | ]); 159 | } 160 | 161 | /** 162 | * Overwrite the allow empty requirement after instantiation of this rule. 163 | * 164 | * @param bool $allowEmpty 165 | * @return $this 166 | */ 167 | protected function overwriteAllowEmpty($allowEmpty) 168 | { 169 | $this->allowEmpty = $allowEmpty; 170 | return $this; 171 | } 172 | 173 | /** 174 | * Set the callback to execute to determine whether or not the rule should allow empty. 175 | * 176 | * @param callable $allowEmptyCallback 177 | * @return $this 178 | */ 179 | protected function setAllowEmptyCallback(callable $allowEmptyCallback) 180 | { 181 | $this->allowEmptyCallback = $allowEmptyCallback; 182 | return $this; 183 | } 184 | 185 | /** 186 | * Determines whether or not the value may be empty. 187 | * 188 | * @param Container $input 189 | * @return bool 190 | */ 191 | protected function allowEmpty(Container $input) 192 | { 193 | if (isset($this->allowEmptyCallback)) { 194 | $this->allowEmpty = call_user_func($this->allowEmptyCallback, $input->getArrayCopy()); 195 | } 196 | return $this->allowEmpty; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/Rule.php: -------------------------------------------------------------------------------- 1 | messageStack = $messageStack; 93 | return $this; 94 | } 95 | 96 | /** 97 | * Sets the default parameters for each validation rule (key and name). 98 | * 99 | * @param string $key 100 | * @param string $name 101 | * @return $this 102 | */ 103 | public function setParameters($key, $name) 104 | { 105 | $this->key = $key; 106 | $this->name = $name; 107 | return $this; 108 | } 109 | 110 | /** 111 | * Determines whether or not the value of $key is valid in the array $values and returns the result as a bool. 112 | * 113 | * @param string $key 114 | * @param Container $input 115 | * @return bool 116 | */ 117 | public function isValid($key, Container $input) 118 | { 119 | return $this->validate($input->get($key)); 120 | } 121 | 122 | /** 123 | * Attach a representation of this rule to the Output\Subject $subject. 124 | * 125 | * @internal 126 | * @param Subject $subject 127 | * @param MessageStack $messageStack 128 | */ 129 | public function output(Subject $subject, MessageStack $messageStack) 130 | { 131 | $this->setParameters($subject->getKey(), $subject->getName()); 132 | 133 | $outputRule = new Output\Rule( 134 | $this->getShortName(), 135 | $this->getMessageTemplates($messageStack), 136 | $this->getMessageParameters() 137 | ); 138 | 139 | $subject->addRule($outputRule); 140 | } 141 | 142 | /** 143 | * Appends the error for reason $reason to the MessageStack. 144 | * 145 | * @param string $reason 146 | * @return bool 147 | */ 148 | protected function error($reason) 149 | { 150 | $this->messageStack->append( 151 | new Failure( 152 | $this->key, 153 | $reason, 154 | $this->getMessage($reason), 155 | $this->getMessageParameters() 156 | ) 157 | ); 158 | 159 | return false; 160 | } 161 | 162 | /** 163 | * Return an array of all parameters that might be replaced in the validation error messages. 164 | * 165 | * @return array 166 | */ 167 | protected function getMessageParameters() 168 | { 169 | $name = isset($this->name) ? $this->name : str_replace('_', ' ', $this->key); 170 | 171 | return [ 172 | 'key' => $this->key, 173 | 'name' => $name, 174 | ]; 175 | } 176 | 177 | /** 178 | * Returns an error message for the reason $reason, or an empty string if it doesn't exist. 179 | * 180 | * @param mixed $reason 181 | * @return string 182 | */ 183 | protected function getMessage($reason) 184 | { 185 | $messageTemplate = ''; 186 | if (array_key_exists($reason, $this->messageTemplates)) { 187 | $messageTemplate = $this->messageTemplates[$reason]; 188 | } 189 | 190 | return $messageTemplate; 191 | } 192 | 193 | /** 194 | * Returns the name of this class, without the namespace. 195 | * 196 | * @return string 197 | */ 198 | protected function getShortName() 199 | { 200 | return substr(get_class($this), strrpos(get_class($this), '\\') + 1); 201 | } 202 | 203 | /** 204 | * Get an array of Message Templates to be returned in output. 205 | * 206 | * @param MessageStack $messageStack 207 | * @return array 208 | */ 209 | protected function getMessageTemplates(MessageStack $messageStack) 210 | { 211 | $messages = $this->messageTemplates; 212 | foreach ($messages as $reason => $message) { 213 | $overwrite = $messageStack->getOverwrite($reason, $this->key); 214 | 215 | if (is_string($overwrite)) { 216 | $messages[$reason] = $overwrite; 217 | } 218 | } 219 | 220 | return $messages; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/Validator.php: -------------------------------------------------------------------------------- 1 | Chain objects. 22 | * 23 | * @var array 24 | */ 25 | protected $chains = [ 26 | self::DEFAULT_CONTEXT => [], 27 | ]; 28 | 29 | /** 30 | * Contains an array of context => MessageStack. 31 | * 32 | * @var MessageStack[] 33 | */ 34 | protected $messageStacks = []; 35 | 36 | /** 37 | * Contains the name of the current context. 38 | * 39 | * @var string 40 | */ 41 | protected $context; 42 | 43 | /** 44 | * Construct the validator. 45 | */ 46 | public function __construct() 47 | { 48 | $this->context = self::DEFAULT_CONTEXT; 49 | $this->messageStacks[$this->context] = new MessageStack(); 50 | } 51 | 52 | /** 53 | * Creates a new required Validation Chain for the key $key. 54 | * 55 | * @param string $key 56 | * @param string|null $name 57 | * @param bool $allowEmpty 58 | * @return Chain 59 | */ 60 | public function required($key, $name = null, $allowEmpty = false) 61 | { 62 | return $this->getChain($key, $name, true, $allowEmpty); 63 | } 64 | 65 | /** 66 | * Creates a new optional Validation Chain for the key $key. 67 | * 68 | * @param string $key 69 | * @param string|null $name 70 | * @param bool $allowEmpty 71 | * @return Chain 72 | */ 73 | public function optional($key, $name = null, $allowEmpty = true) 74 | { 75 | return $this->getChain($key, $name, false, $allowEmpty); 76 | } 77 | 78 | /** 79 | * Validates the values in the $values array and returns a ValidationResult. 80 | * 81 | * @param array $values 82 | * @param string $context 83 | * @return ValidationResult 84 | */ 85 | public function validate(array $values, $context = self::DEFAULT_CONTEXT) 86 | { 87 | $isValid = true; 88 | $output = new Container(); 89 | $input = new Container($values); 90 | $stack = $this->getMergedMessageStack($context); 91 | 92 | foreach ($this->chains[$context] as $chain) { 93 | /** @var Chain $chain */ 94 | $isValid = $chain->validate($stack, $input, $output) && $isValid; 95 | } 96 | 97 | $result = new ValidationResult( 98 | $isValid, 99 | $stack->getFailures(), 100 | $output->getArrayCopy() 101 | ); 102 | 103 | $stack->reset(); 104 | 105 | return $result; 106 | } 107 | 108 | /** 109 | * Copy the rules and messages of the context $otherContext to the current context. 110 | * 111 | * @param string $otherContext 112 | * @param callable|null $callback 113 | * @return $this 114 | */ 115 | public function copyContext($otherContext, ?callable $callback = null) 116 | { 117 | $this->copyChains($otherContext, $callback); 118 | if ($otherContext !== self::DEFAULT_CONTEXT) { 119 | $this->getMessageStack($this->context)->merge($this->getMessageStack($otherContext)); 120 | } 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Create a new validation context with the callback $callback. 127 | * 128 | * @param string $name 129 | * @param callable $callback 130 | */ 131 | public function context($name, callable $callback) 132 | { 133 | $this->addMessageStack($name); 134 | 135 | $this->context = $name; 136 | call_user_func($callback, $this); 137 | $this->context = self::DEFAULT_CONTEXT; 138 | } 139 | 140 | /** 141 | * Output the structure of the Validator by calling the $output callable with a representation of Validators' 142 | * internal structure. 143 | * 144 | * @param callable $output 145 | * @param string $context 146 | * @return mixed 147 | */ 148 | public function output(callable $output, $context = self::DEFAULT_CONTEXT) 149 | { 150 | $stack = $this->getMessageStack($context); 151 | 152 | $structure = new Output\Structure(); 153 | if (array_key_exists($context, $this->chains)) { 154 | /* @var Chain $chain */ 155 | foreach ($this->chains[$context] as $chain) { 156 | $chain->output($structure, $stack); 157 | } 158 | } 159 | 160 | return call_user_func($output, $structure); 161 | } 162 | 163 | /** 164 | * Overwrite the messages for specific keys. 165 | * 166 | * @param array $messages 167 | * @return $this 168 | */ 169 | public function overwriteMessages(array $messages) 170 | { 171 | $this->getMessageStack($this->context)->overwriteMessages($messages); 172 | return $this; 173 | } 174 | 175 | /** 176 | * Overwrite the default messages with custom messages. 177 | * 178 | * @param array $messages 179 | * @return $this 180 | */ 181 | public function overwriteDefaultMessages(array $messages) 182 | { 183 | $this->getMessageStack($this->context)->overwriteDefaultMessages($messages); 184 | return $this; 185 | } 186 | 187 | /** 188 | * Retrieves a Chain object, or builds one if it doesn't exist yet. 189 | * 190 | * @param string $key 191 | * @param string $name 192 | * @param bool $required 193 | * @param bool $allowEmpty 194 | * @return Chain 195 | */ 196 | protected function getChain($key, $name, $required, $allowEmpty) 197 | { 198 | if (isset($this->chains[$this->context][$key])) { 199 | /** @var Chain $chain */ 200 | $chain = $this->chains[$this->context][$key]; 201 | $chain->required($required); 202 | $chain->allowEmpty($allowEmpty); 203 | 204 | return $chain; 205 | } 206 | return $this->chains[$this->context][$key] = $this->buildChain($key, $name, $required, $allowEmpty); 207 | } 208 | 209 | /** 210 | * Build a new Chain object and return it. 211 | * 212 | * @param string $key 213 | * @param string $name 214 | * @param bool $required 215 | * @param bool $allowEmpty 216 | * @return Chain 217 | */ 218 | protected function buildChain($key, $name, $required, $allowEmpty) 219 | { 220 | return new Chain($key, $name, $required, $allowEmpty); 221 | } 222 | 223 | /** 224 | * Copies the chains of the context $otherContext to the current context. 225 | * 226 | * @param string $otherContext 227 | * @param callable|null $callback 228 | */ 229 | protected function copyChains($otherContext, $callback) 230 | { 231 | if (isset($this->chains[$otherContext])) { 232 | $clonedChains = []; 233 | foreach ($this->chains[$otherContext] as $key => $chain) { 234 | $clonedChains[$key] = clone $chain; 235 | } 236 | 237 | $this->chains[$this->context] = $this->runChainCallback($clonedChains, $callback); 238 | } 239 | } 240 | 241 | /** 242 | * Executes the callback $callback and returns the resulting chains. 243 | * 244 | * @param Chain[] $chains 245 | * @param callable|null $callback 246 | * @return Chain[] 247 | */ 248 | protected function runChainCallback($chains, $callback) 249 | { 250 | if ($callback !== null) { 251 | $callback($chains); 252 | } 253 | 254 | return $chains; 255 | } 256 | 257 | /** 258 | * Returns a message stack for the context $context. 259 | * 260 | * @param string $context 261 | * @return MessageStack 262 | */ 263 | protected function getMessageStack($context) 264 | { 265 | return $this->messageStacks[$context]; 266 | } 267 | 268 | /** 269 | * Adds a message stack. 270 | * 271 | * @param string $name 272 | */ 273 | protected function addMessageStack($name) 274 | { 275 | $messageStack = new MessageStack(); 276 | 277 | $this->messageStacks[$name] = $messageStack; 278 | } 279 | 280 | /** 281 | * Returns the message stack. If the context isn't the default context, it will merge the message of the default 282 | * context first. 283 | * 284 | * @param string $context 285 | * @return MessageStack 286 | */ 287 | protected function getMergedMessageStack($context) 288 | { 289 | $stack = $this->getMessageStack($context); 290 | 291 | if ($context !== self::DEFAULT_CONTEXT) { 292 | $stack->merge($this->getMessageStack(self::DEFAULT_CONTEXT)); 293 | } 294 | 295 | return $stack; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/Chain.php: -------------------------------------------------------------------------------- 1 | key = $key; 61 | $this->name = $name; 62 | 63 | $this->addRule(new Rule\Required($required)); 64 | $this->addRule(new Rule\NotEmpty($allowEmpty)); 65 | } 66 | 67 | /** 68 | * Overwrite the default __clone behaviour to make sure the rules are cloned too. 69 | */ 70 | public function __clone() 71 | { 72 | $rules = []; 73 | foreach ($this->rules as $rule) { 74 | $rules[] = clone $rule; 75 | } 76 | $this->rules = $rules; 77 | } 78 | 79 | /** 80 | * Set a callable or boolean value which may be used to alter the allow empty requirement on validation time. 81 | * 82 | * This may be incredibly helpful when doing conditional validation. 83 | * 84 | * @param callable|bool $allowEmpty 85 | * @return $this 86 | */ 87 | public function allowEmpty($allowEmpty) 88 | { 89 | $this->getNotEmptyRule()->setAllowEmpty($allowEmpty); 90 | return $this; 91 | } 92 | 93 | /** 94 | * Validate the value to consist only out of alphanumeric characters. 95 | * 96 | * @param bool $allowWhitespace 97 | * @return $this 98 | */ 99 | public function alnum($allowWhitespace = Rule\Alnum::DISALLOW_SPACES) 100 | { 101 | return $this->addRule(new Rule\Alnum($allowWhitespace)); 102 | } 103 | 104 | /** 105 | * Validate that the value only consists our of alphabetic characters. 106 | * 107 | * @param bool $allowWhitespace 108 | * @return $this 109 | */ 110 | public function alpha($allowWhitespace = Rule\Alpha::DISALLOW_SPACES) 111 | { 112 | return $this->addRule(new Rule\Alpha($allowWhitespace)); 113 | } 114 | 115 | /** 116 | * Validate that the value is between $min and $max (inclusive). 117 | * 118 | * @param int $min 119 | * @param int $max 120 | * @return $this 121 | */ 122 | public function between($min, $max) 123 | { 124 | return $this->addRule(new Rule\Between($min, $max)); 125 | } 126 | 127 | /** 128 | * Validate that the value is a boolean. 129 | * 130 | * @return $this 131 | */ 132 | public function bool() 133 | { 134 | return $this->addRule(new Rule\Boolean()); 135 | } 136 | 137 | /** 138 | * Validate by executing a callback function, and returning its result. 139 | * 140 | * @param callable $callable 141 | * @return $this 142 | */ 143 | public function callback(callable $callable) 144 | { 145 | return $this->addRule(new Rule\Callback($callable)); 146 | } 147 | 148 | /** 149 | * Validates that the value is a valid credit card number. 150 | * @return $this 151 | */ 152 | public function creditCard() 153 | { 154 | return $this->addRule(new Rule\CreditCard()); 155 | } 156 | 157 | /** 158 | * Validates that the value is a date. If format is passed, it *must* be in that format. 159 | * 160 | * @param string|null $format 161 | * @return $this 162 | */ 163 | public function datetime($format = null) 164 | { 165 | return $this->addRule(new Rule\Datetime($format)); 166 | } 167 | 168 | /** 169 | * Validates that all characters of the value are decimal digits. 170 | * 171 | * @return $this 172 | */ 173 | public function digits() 174 | { 175 | return $this->addRule(new Rule\Digits()); 176 | } 177 | 178 | /** 179 | * Validates a value to be a nested array, which can then be validated using a new Validator instance. 180 | * 181 | * @param callable $callback 182 | * @return $this 183 | */ 184 | public function each(callable $callback) 185 | { 186 | return $this->addRule(new Rule\Each($callback)); 187 | } 188 | 189 | /** 190 | * Validates that the value is a valid email address (format only). 191 | * @return $this 192 | */ 193 | public function email() 194 | { 195 | return $this->addRule(new Rule\Email()); 196 | } 197 | 198 | /** 199 | * Validates that the value is equal to $value. 200 | * 201 | * @param string $value 202 | * @return $this 203 | */ 204 | public function equals($value) 205 | { 206 | return $this->addRule(new Rule\Equal($value)); 207 | } 208 | 209 | /** 210 | * Validates that the value represents a float. 211 | * 212 | * @return $this 213 | */ 214 | public function float() 215 | { 216 | return $this->addRule(new Rule\IsFloat()); 217 | } 218 | 219 | /** 220 | * Validates that the value is greater than $value. 221 | * 222 | * @param int $value 223 | * @return $this 224 | */ 225 | public function greaterThan($value) 226 | { 227 | return $this->addRule(new Rule\GreaterThan($value)); 228 | } 229 | 230 | /** 231 | * Validates that the value is in the array with optional "loose" checking. 232 | * 233 | * @param string $hashAlgorithm 234 | * @param bool $allowUppercase 235 | * @return $this 236 | * @see \Particle\Validator\Rule\Hash 237 | */ 238 | public function hash($hashAlgorithm, $allowUppercase = Rule\Hash::DISALLOW_UPPERCASE) 239 | { 240 | return $this->addRule(new Rule\Hash($hashAlgorithm, $allowUppercase)); 241 | } 242 | 243 | /** 244 | * Validates that the value is in the array with optional "loose" checking. 245 | * 246 | * @param array $array 247 | * @param bool $strict 248 | * @return $this 249 | */ 250 | public function inArray(array $array, $strict = Rule\InArray::STRICT) 251 | { 252 | return $this->addRule(new Rule\InArray($array, $strict)); 253 | } 254 | 255 | /** 256 | * Validates the value represents a valid integer 257 | * 258 | * @param bool $strict 259 | * @return $this 260 | * @see \Particle\Validator\Rule\Integer 261 | */ 262 | public function integer($strict = false) 263 | { 264 | return $this->addRule(new Rule\Integer($strict)); 265 | } 266 | 267 | /** 268 | * Validates the value is an array 269 | * 270 | * @return $this 271 | * @see \Particle\Validator\Rule\IsArray 272 | */ 273 | public function isArray() 274 | { 275 | return $this->addRule(new Rule\IsArray()); 276 | } 277 | 278 | /** 279 | * Validates that the value represents a valid JSON string 280 | * 281 | * @return $this 282 | * @see \Particle\Validator\Rule\Json 283 | */ 284 | public function json() 285 | { 286 | return $this->addRule(new Rule\Json()); 287 | } 288 | 289 | /** 290 | * Validate the value to be of precisely length $length. 291 | * 292 | * @param int $length 293 | * @return $this 294 | */ 295 | public function length($length) 296 | { 297 | return $this->addRule(new Rule\Length($length)); 298 | } 299 | 300 | /** 301 | * Validates that the length of the value is between $min and $max. 302 | * 303 | * If $max is null, it has no upper limit. The default is inclusive. 304 | * 305 | * @param int $min 306 | * @param int|null $max 307 | * @return $this 308 | */ 309 | public function lengthBetween($min, $max) 310 | { 311 | return $this->addRule(new Rule\LengthBetween($min, $max)); 312 | } 313 | 314 | /** 315 | * Validates that the value is less than $value. 316 | * 317 | * @param int $value 318 | * @return $this 319 | */ 320 | public function lessThan($value) 321 | { 322 | return $this->addRule(new Rule\LessThan($value)); 323 | } 324 | 325 | /** 326 | * Mount a rule object onto this chain. 327 | * 328 | * @param Rule $rule 329 | * @return $this 330 | */ 331 | public function mount(Rule $rule) 332 | { 333 | return $this->addRule($rule); 334 | } 335 | 336 | /** 337 | * Validates that the value is either a integer or a float. 338 | * 339 | * @return $this 340 | */ 341 | public function numeric() 342 | { 343 | return $this->addRule(new Rule\Numeric()); 344 | } 345 | 346 | /** 347 | * Validates that the value is a valid phone number for $countryCode. 348 | * 349 | * @param string $countryCode 350 | * @see \Particle\Validator\Rule\Phone 351 | * @return $this 352 | */ 353 | public function phone($countryCode) 354 | { 355 | return $this->addRule(new Rule\Phone($countryCode)); 356 | } 357 | 358 | /** 359 | * Validates that the value matches the regular expression $regex. 360 | * 361 | * @param string $regex 362 | * @return $this 363 | */ 364 | public function regex($regex) 365 | { 366 | return $this->addRule(new Rule\Regex($regex)); 367 | } 368 | 369 | /** 370 | * Set a callable or boolean value which may be used to alter the required requirement on validation time. 371 | * 372 | * This may be incredibly helpful when doing conditional validation. 373 | * 374 | * @param callable|bool $required 375 | * @return $this 376 | */ 377 | public function required($required) 378 | { 379 | $this->getRequiredRule()->setRequired($required); 380 | return $this; 381 | } 382 | 383 | /** 384 | * Validates that the value represents a string. 385 | * 386 | * @return $this 387 | */ 388 | public function string() 389 | { 390 | return $this->addRule(new Rule\IsString()); 391 | } 392 | 393 | /** 394 | * Validates that the value is a valid URL. The schemes array is to selectively whitelist URL schemes. 395 | * 396 | * @param array $schemes 397 | * @return $this 398 | */ 399 | public function url(array $schemes = []) 400 | { 401 | return $this->addRule(new Rule\Url($schemes)); 402 | } 403 | 404 | /** 405 | * Validates that the value is a valid UUID 406 | * 407 | * @param int $version 408 | * @return $this 409 | */ 410 | public function uuid($version = Rule\Uuid::UUID_VALID) 411 | { 412 | return $this->addRule(new Rule\Uuid($version)); 413 | } 414 | 415 | /** 416 | * Attach a representation of this Chain to the Output\Structure $structure. 417 | * 418 | * @internal 419 | * @param Structure $structure 420 | * @param MessageStack $messageStack 421 | * @return Structure 422 | */ 423 | public function output(Structure $structure, MessageStack $messageStack) 424 | { 425 | $subject = new Subject($this->key, $this->name); 426 | 427 | foreach ($this->rules as $rule) { 428 | $rule->output($subject, $messageStack); 429 | } 430 | 431 | $structure->addSubject($subject); 432 | 433 | return $structure; 434 | } 435 | 436 | /** 437 | * Validates the values in the $values array and appends messages to $messageStack. Returns the result as a bool. 438 | * 439 | * @param MessageStack $messageStack 440 | * @param Container $input 441 | * @param Container $output 442 | * @return bool 443 | */ 444 | public function validate(MessageStack $messageStack, Container $input, Container $output) 445 | { 446 | $valid = true; 447 | foreach ($this->rules as $rule) { 448 | $rule->setMessageStack($messageStack); 449 | $rule->setParameters($this->key, $this->name); 450 | 451 | $valid = $rule->isValid($this->key, $input) && $valid; 452 | 453 | if (!$valid && $rule->shouldBreakChainOnError() || $rule->shouldBreakChain()) { 454 | break; 455 | } 456 | } 457 | 458 | if ($valid && $input->has($this->key)) { 459 | $output->set($this->key, $input->get($this->key)); 460 | } 461 | return $valid; 462 | } 463 | 464 | /** 465 | * Shortcut method for storing a rule on this chain, and returning the chain. 466 | * 467 | * @param Rule $rule 468 | * @return $this 469 | */ 470 | protected function addRule(Rule $rule) 471 | { 472 | $this->rules[] = $rule; 473 | 474 | return $this; 475 | } 476 | 477 | /** 478 | * Returns the first rule, which is always the required rule. 479 | * 480 | * @return Rule\Required 481 | */ 482 | protected function getRequiredRule() 483 | { 484 | return $this->rules[0]; 485 | } 486 | 487 | /** 488 | * Returns the second rule, which is always the allow empty rule. 489 | * 490 | * @return Rule\NotEmpty 491 | */ 492 | protected function getNotEmptyRule() 493 | { 494 | return $this->rules[1]; 495 | } 496 | } 497 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "8ecffde530fe6f6f9734923672b62a8e", 8 | "content-hash": "247a4b1271cc9fe279257f7d1a19308d", 9 | "packages": [ 10 | { 11 | "name": "byrokrat/checkdigit", 12 | "version": "1.1.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/byrokrat/checkdigit.git", 16 | "reference": "0570359e5ac51685d8700b0acd81e2ed0f2bcc79" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/byrokrat/checkdigit/zipball/0570359e5ac51685d8700b0acd81e2ed0f2bcc79", 21 | "reference": "0570359e5ac51685d8700b0acd81e2ed0f2bcc79", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "ext-bcmath": "*", 26 | "php": ">=5.4" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "~5.0" 30 | }, 31 | "type": "library", 32 | "autoload": { 33 | "psr-4": { 34 | "byrokrat\\checkdigit\\": "src/" 35 | } 36 | }, 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "WTFPL" 40 | ], 41 | "authors": [ 42 | { 43 | "name": "Hannes Forsgård", 44 | "email": "hannes.forsgard@fripost.org" 45 | } 46 | ], 47 | "description": "Helper classes to calculate and validate ckecksums", 48 | "homepage": "https://github.com/byrokrat/checkdigit", 49 | "keywords": [ 50 | "Check digit", 51 | "luhn", 52 | "modulo 10", 53 | "modulo 11", 54 | "modulo 97" 55 | ], 56 | "time": "2016-03-02 13:17:54" 57 | }, 58 | { 59 | "name": "giggsey/libphonenumber-for-php", 60 | "version": "7.2.7", 61 | "source": { 62 | "type": "git", 63 | "url": "https://github.com/giggsey/libphonenumber-for-php.git", 64 | "reference": "26680b8a22728181ea8e77f4627a323aba480b99" 65 | }, 66 | "dist": { 67 | "type": "zip", 68 | "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/26680b8a22728181ea8e77f4627a323aba480b99", 69 | "reference": "26680b8a22728181ea8e77f4627a323aba480b99", 70 | "shasum": "" 71 | }, 72 | "require": { 73 | "ext-mbstring": "*" 74 | }, 75 | "require-dev": { 76 | "pear/pear-core-minimal": "^1.9", 77 | "pear/pear_exception": "^1.0", 78 | "pear/versioncontrol_git": "dev-master", 79 | "phing/phing": "~2.7", 80 | "phpunit/phpunit": "~4.0", 81 | "satooshi/php-coveralls": "~0.6", 82 | "symfony/console": "^2.5" 83 | }, 84 | "suggest": { 85 | "ext-intl": "To use the geocoder and carrier mapping" 86 | }, 87 | "type": "library", 88 | "extra": { 89 | "branch-alias": { 90 | "dev-master": "7.x-dev" 91 | } 92 | }, 93 | "autoload": { 94 | "psr-0": { 95 | "libphonenumber": "src/" 96 | } 97 | }, 98 | "notification-url": "https://packagist.org/downloads/", 99 | "license": [ 100 | "Apache-2.0" 101 | ], 102 | "authors": [ 103 | { 104 | "name": "Joshua Gigg", 105 | "email": "giggsey@gmail.com", 106 | "homepage": "http://giggsey.com/" 107 | } 108 | ], 109 | "description": "PHP Port of Google's libphonenumber", 110 | "homepage": "https://github.com/giggsey/libphonenumber-for-php", 111 | "keywords": [ 112 | "geocoding", 113 | "geolocation", 114 | "libphonenumber", 115 | "mobile", 116 | "phonenumber", 117 | "validation" 118 | ], 119 | "time": "2016-03-09 15:03:21" 120 | } 121 | ], 122 | "packages-dev": [ 123 | { 124 | "name": "doctrine/instantiator", 125 | "version": "1.0.5", 126 | "source": { 127 | "type": "git", 128 | "url": "https://github.com/doctrine/instantiator.git", 129 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 130 | }, 131 | "dist": { 132 | "type": "zip", 133 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 134 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 135 | "shasum": "" 136 | }, 137 | "require": { 138 | "php": ">=5.3,<8.0-DEV" 139 | }, 140 | "require-dev": { 141 | "athletic/athletic": "~0.1.8", 142 | "ext-pdo": "*", 143 | "ext-phar": "*", 144 | "phpunit/phpunit": "~4.0", 145 | "squizlabs/php_codesniffer": "~2.0" 146 | }, 147 | "type": "library", 148 | "extra": { 149 | "branch-alias": { 150 | "dev-master": "1.0.x-dev" 151 | } 152 | }, 153 | "autoload": { 154 | "psr-4": { 155 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 156 | } 157 | }, 158 | "notification-url": "https://packagist.org/downloads/", 159 | "license": [ 160 | "MIT" 161 | ], 162 | "authors": [ 163 | { 164 | "name": "Marco Pivetta", 165 | "email": "ocramius@gmail.com", 166 | "homepage": "http://ocramius.github.com/" 167 | } 168 | ], 169 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 170 | "homepage": "https://github.com/doctrine/instantiator", 171 | "keywords": [ 172 | "constructor", 173 | "instantiate" 174 | ], 175 | "time": "2015-06-14 21:17:01" 176 | }, 177 | { 178 | "name": "phpdocumentor/reflection-docblock", 179 | "version": "2.0.4", 180 | "source": { 181 | "type": "git", 182 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 183 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" 184 | }, 185 | "dist": { 186 | "type": "zip", 187 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", 188 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", 189 | "shasum": "" 190 | }, 191 | "require": { 192 | "php": ">=5.3.3" 193 | }, 194 | "require-dev": { 195 | "phpunit/phpunit": "~4.0" 196 | }, 197 | "suggest": { 198 | "dflydev/markdown": "~1.0", 199 | "erusev/parsedown": "~1.0" 200 | }, 201 | "type": "library", 202 | "extra": { 203 | "branch-alias": { 204 | "dev-master": "2.0.x-dev" 205 | } 206 | }, 207 | "autoload": { 208 | "psr-0": { 209 | "phpDocumentor": [ 210 | "src/" 211 | ] 212 | } 213 | }, 214 | "notification-url": "https://packagist.org/downloads/", 215 | "license": [ 216 | "MIT" 217 | ], 218 | "authors": [ 219 | { 220 | "name": "Mike van Riel", 221 | "email": "mike.vanriel@naenius.com" 222 | } 223 | ], 224 | "time": "2015-02-03 12:10:50" 225 | }, 226 | { 227 | "name": "phpspec/prophecy", 228 | "version": "v1.6.0", 229 | "source": { 230 | "type": "git", 231 | "url": "https://github.com/phpspec/prophecy.git", 232 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" 233 | }, 234 | "dist": { 235 | "type": "zip", 236 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", 237 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", 238 | "shasum": "" 239 | }, 240 | "require": { 241 | "doctrine/instantiator": "^1.0.2", 242 | "php": "^5.3|^7.0", 243 | "phpdocumentor/reflection-docblock": "~2.0", 244 | "sebastian/comparator": "~1.1", 245 | "sebastian/recursion-context": "~1.0" 246 | }, 247 | "require-dev": { 248 | "phpspec/phpspec": "~2.0" 249 | }, 250 | "type": "library", 251 | "extra": { 252 | "branch-alias": { 253 | "dev-master": "1.5.x-dev" 254 | } 255 | }, 256 | "autoload": { 257 | "psr-0": { 258 | "Prophecy\\": "src/" 259 | } 260 | }, 261 | "notification-url": "https://packagist.org/downloads/", 262 | "license": [ 263 | "MIT" 264 | ], 265 | "authors": [ 266 | { 267 | "name": "Konstantin Kudryashov", 268 | "email": "ever.zet@gmail.com", 269 | "homepage": "http://everzet.com" 270 | }, 271 | { 272 | "name": "Marcello Duarte", 273 | "email": "marcello.duarte@gmail.com" 274 | } 275 | ], 276 | "description": "Highly opinionated mocking framework for PHP 5.3+", 277 | "homepage": "https://github.com/phpspec/prophecy", 278 | "keywords": [ 279 | "Double", 280 | "Dummy", 281 | "fake", 282 | "mock", 283 | "spy", 284 | "stub" 285 | ], 286 | "time": "2016-02-15 07:46:21" 287 | }, 288 | { 289 | "name": "phpunit/php-code-coverage", 290 | "version": "2.2.4", 291 | "source": { 292 | "type": "git", 293 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 294 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" 295 | }, 296 | "dist": { 297 | "type": "zip", 298 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", 299 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", 300 | "shasum": "" 301 | }, 302 | "require": { 303 | "php": ">=5.3.3", 304 | "phpunit/php-file-iterator": "~1.3", 305 | "phpunit/php-text-template": "~1.2", 306 | "phpunit/php-token-stream": "~1.3", 307 | "sebastian/environment": "^1.3.2", 308 | "sebastian/version": "~1.0" 309 | }, 310 | "require-dev": { 311 | "ext-xdebug": ">=2.1.4", 312 | "phpunit/phpunit": "~4" 313 | }, 314 | "suggest": { 315 | "ext-dom": "*", 316 | "ext-xdebug": ">=2.2.1", 317 | "ext-xmlwriter": "*" 318 | }, 319 | "type": "library", 320 | "extra": { 321 | "branch-alias": { 322 | "dev-master": "2.2.x-dev" 323 | } 324 | }, 325 | "autoload": { 326 | "classmap": [ 327 | "src/" 328 | ] 329 | }, 330 | "notification-url": "https://packagist.org/downloads/", 331 | "license": [ 332 | "BSD-3-Clause" 333 | ], 334 | "authors": [ 335 | { 336 | "name": "Sebastian Bergmann", 337 | "email": "sb@sebastian-bergmann.de", 338 | "role": "lead" 339 | } 340 | ], 341 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 342 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 343 | "keywords": [ 344 | "coverage", 345 | "testing", 346 | "xunit" 347 | ], 348 | "time": "2015-10-06 15:47:00" 349 | }, 350 | { 351 | "name": "phpunit/php-file-iterator", 352 | "version": "1.4.1", 353 | "source": { 354 | "type": "git", 355 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 356 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" 357 | }, 358 | "dist": { 359 | "type": "zip", 360 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 361 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 362 | "shasum": "" 363 | }, 364 | "require": { 365 | "php": ">=5.3.3" 366 | }, 367 | "type": "library", 368 | "extra": { 369 | "branch-alias": { 370 | "dev-master": "1.4.x-dev" 371 | } 372 | }, 373 | "autoload": { 374 | "classmap": [ 375 | "src/" 376 | ] 377 | }, 378 | "notification-url": "https://packagist.org/downloads/", 379 | "license": [ 380 | "BSD-3-Clause" 381 | ], 382 | "authors": [ 383 | { 384 | "name": "Sebastian Bergmann", 385 | "email": "sb@sebastian-bergmann.de", 386 | "role": "lead" 387 | } 388 | ], 389 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 390 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 391 | "keywords": [ 392 | "filesystem", 393 | "iterator" 394 | ], 395 | "time": "2015-06-21 13:08:43" 396 | }, 397 | { 398 | "name": "phpunit/php-text-template", 399 | "version": "1.2.1", 400 | "source": { 401 | "type": "git", 402 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 403 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 404 | }, 405 | "dist": { 406 | "type": "zip", 407 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 408 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 409 | "shasum": "" 410 | }, 411 | "require": { 412 | "php": ">=5.3.3" 413 | }, 414 | "type": "library", 415 | "autoload": { 416 | "classmap": [ 417 | "src/" 418 | ] 419 | }, 420 | "notification-url": "https://packagist.org/downloads/", 421 | "license": [ 422 | "BSD-3-Clause" 423 | ], 424 | "authors": [ 425 | { 426 | "name": "Sebastian Bergmann", 427 | "email": "sebastian@phpunit.de", 428 | "role": "lead" 429 | } 430 | ], 431 | "description": "Simple template engine.", 432 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 433 | "keywords": [ 434 | "template" 435 | ], 436 | "time": "2015-06-21 13:50:34" 437 | }, 438 | { 439 | "name": "phpunit/php-timer", 440 | "version": "1.0.7", 441 | "source": { 442 | "type": "git", 443 | "url": "https://github.com/sebastianbergmann/php-timer.git", 444 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" 445 | }, 446 | "dist": { 447 | "type": "zip", 448 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 449 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 450 | "shasum": "" 451 | }, 452 | "require": { 453 | "php": ">=5.3.3" 454 | }, 455 | "type": "library", 456 | "autoload": { 457 | "classmap": [ 458 | "src/" 459 | ] 460 | }, 461 | "notification-url": "https://packagist.org/downloads/", 462 | "license": [ 463 | "BSD-3-Clause" 464 | ], 465 | "authors": [ 466 | { 467 | "name": "Sebastian Bergmann", 468 | "email": "sb@sebastian-bergmann.de", 469 | "role": "lead" 470 | } 471 | ], 472 | "description": "Utility class for timing", 473 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 474 | "keywords": [ 475 | "timer" 476 | ], 477 | "time": "2015-06-21 08:01:12" 478 | }, 479 | { 480 | "name": "phpunit/php-token-stream", 481 | "version": "1.4.8", 482 | "source": { 483 | "type": "git", 484 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 485 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" 486 | }, 487 | "dist": { 488 | "type": "zip", 489 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 490 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 491 | "shasum": "" 492 | }, 493 | "require": { 494 | "ext-tokenizer": "*", 495 | "php": ">=5.3.3" 496 | }, 497 | "require-dev": { 498 | "phpunit/phpunit": "~4.2" 499 | }, 500 | "type": "library", 501 | "extra": { 502 | "branch-alias": { 503 | "dev-master": "1.4-dev" 504 | } 505 | }, 506 | "autoload": { 507 | "classmap": [ 508 | "src/" 509 | ] 510 | }, 511 | "notification-url": "https://packagist.org/downloads/", 512 | "license": [ 513 | "BSD-3-Clause" 514 | ], 515 | "authors": [ 516 | { 517 | "name": "Sebastian Bergmann", 518 | "email": "sebastian@phpunit.de" 519 | } 520 | ], 521 | "description": "Wrapper around PHP's tokenizer extension.", 522 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 523 | "keywords": [ 524 | "tokenizer" 525 | ], 526 | "time": "2015-09-15 10:49:45" 527 | }, 528 | { 529 | "name": "phpunit/phpunit", 530 | "version": "4.8.24", 531 | "source": { 532 | "type": "git", 533 | "url": "https://github.com/sebastianbergmann/phpunit.git", 534 | "reference": "a1066c562c52900a142a0e2bbf0582994671385e" 535 | }, 536 | "dist": { 537 | "type": "zip", 538 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", 539 | "reference": "a1066c562c52900a142a0e2bbf0582994671385e", 540 | "shasum": "" 541 | }, 542 | "require": { 543 | "ext-dom": "*", 544 | "ext-json": "*", 545 | "ext-pcre": "*", 546 | "ext-reflection": "*", 547 | "ext-spl": "*", 548 | "php": ">=5.3.3", 549 | "phpspec/prophecy": "^1.3.1", 550 | "phpunit/php-code-coverage": "~2.1", 551 | "phpunit/php-file-iterator": "~1.4", 552 | "phpunit/php-text-template": "~1.2", 553 | "phpunit/php-timer": ">=1.0.6", 554 | "phpunit/phpunit-mock-objects": "~2.3", 555 | "sebastian/comparator": "~1.1", 556 | "sebastian/diff": "~1.2", 557 | "sebastian/environment": "~1.3", 558 | "sebastian/exporter": "~1.2", 559 | "sebastian/global-state": "~1.0", 560 | "sebastian/version": "~1.0", 561 | "symfony/yaml": "~2.1|~3.0" 562 | }, 563 | "suggest": { 564 | "phpunit/php-invoker": "~1.1" 565 | }, 566 | "bin": [ 567 | "phpunit" 568 | ], 569 | "type": "library", 570 | "extra": { 571 | "branch-alias": { 572 | "dev-master": "4.8.x-dev" 573 | } 574 | }, 575 | "autoload": { 576 | "classmap": [ 577 | "src/" 578 | ] 579 | }, 580 | "notification-url": "https://packagist.org/downloads/", 581 | "license": [ 582 | "BSD-3-Clause" 583 | ], 584 | "authors": [ 585 | { 586 | "name": "Sebastian Bergmann", 587 | "email": "sebastian@phpunit.de", 588 | "role": "lead" 589 | } 590 | ], 591 | "description": "The PHP Unit Testing framework.", 592 | "homepage": "https://phpunit.de/", 593 | "keywords": [ 594 | "phpunit", 595 | "testing", 596 | "xunit" 597 | ], 598 | "time": "2016-03-14 06:16:08" 599 | }, 600 | { 601 | "name": "phpunit/phpunit-mock-objects", 602 | "version": "2.3.8", 603 | "source": { 604 | "type": "git", 605 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 606 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" 607 | }, 608 | "dist": { 609 | "type": "zip", 610 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", 611 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", 612 | "shasum": "" 613 | }, 614 | "require": { 615 | "doctrine/instantiator": "^1.0.2", 616 | "php": ">=5.3.3", 617 | "phpunit/php-text-template": "~1.2", 618 | "sebastian/exporter": "~1.2" 619 | }, 620 | "require-dev": { 621 | "phpunit/phpunit": "~4.4" 622 | }, 623 | "suggest": { 624 | "ext-soap": "*" 625 | }, 626 | "type": "library", 627 | "extra": { 628 | "branch-alias": { 629 | "dev-master": "2.3.x-dev" 630 | } 631 | }, 632 | "autoload": { 633 | "classmap": [ 634 | "src/" 635 | ] 636 | }, 637 | "notification-url": "https://packagist.org/downloads/", 638 | "license": [ 639 | "BSD-3-Clause" 640 | ], 641 | "authors": [ 642 | { 643 | "name": "Sebastian Bergmann", 644 | "email": "sb@sebastian-bergmann.de", 645 | "role": "lead" 646 | } 647 | ], 648 | "description": "Mock Object library for PHPUnit", 649 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 650 | "keywords": [ 651 | "mock", 652 | "xunit" 653 | ], 654 | "time": "2015-10-02 06:51:40" 655 | }, 656 | { 657 | "name": "sebastian/comparator", 658 | "version": "1.2.0", 659 | "source": { 660 | "type": "git", 661 | "url": "https://github.com/sebastianbergmann/comparator.git", 662 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" 663 | }, 664 | "dist": { 665 | "type": "zip", 666 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", 667 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", 668 | "shasum": "" 669 | }, 670 | "require": { 671 | "php": ">=5.3.3", 672 | "sebastian/diff": "~1.2", 673 | "sebastian/exporter": "~1.2" 674 | }, 675 | "require-dev": { 676 | "phpunit/phpunit": "~4.4" 677 | }, 678 | "type": "library", 679 | "extra": { 680 | "branch-alias": { 681 | "dev-master": "1.2.x-dev" 682 | } 683 | }, 684 | "autoload": { 685 | "classmap": [ 686 | "src/" 687 | ] 688 | }, 689 | "notification-url": "https://packagist.org/downloads/", 690 | "license": [ 691 | "BSD-3-Clause" 692 | ], 693 | "authors": [ 694 | { 695 | "name": "Jeff Welch", 696 | "email": "whatthejeff@gmail.com" 697 | }, 698 | { 699 | "name": "Volker Dusch", 700 | "email": "github@wallbash.com" 701 | }, 702 | { 703 | "name": "Bernhard Schussek", 704 | "email": "bschussek@2bepublished.at" 705 | }, 706 | { 707 | "name": "Sebastian Bergmann", 708 | "email": "sebastian@phpunit.de" 709 | } 710 | ], 711 | "description": "Provides the functionality to compare PHP values for equality", 712 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 713 | "keywords": [ 714 | "comparator", 715 | "compare", 716 | "equality" 717 | ], 718 | "time": "2015-07-26 15:48:44" 719 | }, 720 | { 721 | "name": "sebastian/diff", 722 | "version": "1.4.1", 723 | "source": { 724 | "type": "git", 725 | "url": "https://github.com/sebastianbergmann/diff.git", 726 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 727 | }, 728 | "dist": { 729 | "type": "zip", 730 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 731 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 732 | "shasum": "" 733 | }, 734 | "require": { 735 | "php": ">=5.3.3" 736 | }, 737 | "require-dev": { 738 | "phpunit/phpunit": "~4.8" 739 | }, 740 | "type": "library", 741 | "extra": { 742 | "branch-alias": { 743 | "dev-master": "1.4-dev" 744 | } 745 | }, 746 | "autoload": { 747 | "classmap": [ 748 | "src/" 749 | ] 750 | }, 751 | "notification-url": "https://packagist.org/downloads/", 752 | "license": [ 753 | "BSD-3-Clause" 754 | ], 755 | "authors": [ 756 | { 757 | "name": "Kore Nordmann", 758 | "email": "mail@kore-nordmann.de" 759 | }, 760 | { 761 | "name": "Sebastian Bergmann", 762 | "email": "sebastian@phpunit.de" 763 | } 764 | ], 765 | "description": "Diff implementation", 766 | "homepage": "https://github.com/sebastianbergmann/diff", 767 | "keywords": [ 768 | "diff" 769 | ], 770 | "time": "2015-12-08 07:14:41" 771 | }, 772 | { 773 | "name": "sebastian/environment", 774 | "version": "1.3.5", 775 | "source": { 776 | "type": "git", 777 | "url": "https://github.com/sebastianbergmann/environment.git", 778 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf" 779 | }, 780 | "dist": { 781 | "type": "zip", 782 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 783 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 784 | "shasum": "" 785 | }, 786 | "require": { 787 | "php": ">=5.3.3" 788 | }, 789 | "require-dev": { 790 | "phpunit/phpunit": "~4.4" 791 | }, 792 | "type": "library", 793 | "extra": { 794 | "branch-alias": { 795 | "dev-master": "1.3.x-dev" 796 | } 797 | }, 798 | "autoload": { 799 | "classmap": [ 800 | "src/" 801 | ] 802 | }, 803 | "notification-url": "https://packagist.org/downloads/", 804 | "license": [ 805 | "BSD-3-Clause" 806 | ], 807 | "authors": [ 808 | { 809 | "name": "Sebastian Bergmann", 810 | "email": "sebastian@phpunit.de" 811 | } 812 | ], 813 | "description": "Provides functionality to handle HHVM/PHP environments", 814 | "homepage": "http://www.github.com/sebastianbergmann/environment", 815 | "keywords": [ 816 | "Xdebug", 817 | "environment", 818 | "hhvm" 819 | ], 820 | "time": "2016-02-26 18:40:46" 821 | }, 822 | { 823 | "name": "sebastian/exporter", 824 | "version": "1.2.1", 825 | "source": { 826 | "type": "git", 827 | "url": "https://github.com/sebastianbergmann/exporter.git", 828 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e" 829 | }, 830 | "dist": { 831 | "type": "zip", 832 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", 833 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e", 834 | "shasum": "" 835 | }, 836 | "require": { 837 | "php": ">=5.3.3", 838 | "sebastian/recursion-context": "~1.0" 839 | }, 840 | "require-dev": { 841 | "phpunit/phpunit": "~4.4" 842 | }, 843 | "type": "library", 844 | "extra": { 845 | "branch-alias": { 846 | "dev-master": "1.2.x-dev" 847 | } 848 | }, 849 | "autoload": { 850 | "classmap": [ 851 | "src/" 852 | ] 853 | }, 854 | "notification-url": "https://packagist.org/downloads/", 855 | "license": [ 856 | "BSD-3-Clause" 857 | ], 858 | "authors": [ 859 | { 860 | "name": "Jeff Welch", 861 | "email": "whatthejeff@gmail.com" 862 | }, 863 | { 864 | "name": "Volker Dusch", 865 | "email": "github@wallbash.com" 866 | }, 867 | { 868 | "name": "Bernhard Schussek", 869 | "email": "bschussek@2bepublished.at" 870 | }, 871 | { 872 | "name": "Sebastian Bergmann", 873 | "email": "sebastian@phpunit.de" 874 | }, 875 | { 876 | "name": "Adam Harvey", 877 | "email": "aharvey@php.net" 878 | } 879 | ], 880 | "description": "Provides the functionality to export PHP variables for visualization", 881 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 882 | "keywords": [ 883 | "export", 884 | "exporter" 885 | ], 886 | "time": "2015-06-21 07:55:53" 887 | }, 888 | { 889 | "name": "sebastian/global-state", 890 | "version": "1.1.1", 891 | "source": { 892 | "type": "git", 893 | "url": "https://github.com/sebastianbergmann/global-state.git", 894 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 895 | }, 896 | "dist": { 897 | "type": "zip", 898 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 899 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 900 | "shasum": "" 901 | }, 902 | "require": { 903 | "php": ">=5.3.3" 904 | }, 905 | "require-dev": { 906 | "phpunit/phpunit": "~4.2" 907 | }, 908 | "suggest": { 909 | "ext-uopz": "*" 910 | }, 911 | "type": "library", 912 | "extra": { 913 | "branch-alias": { 914 | "dev-master": "1.0-dev" 915 | } 916 | }, 917 | "autoload": { 918 | "classmap": [ 919 | "src/" 920 | ] 921 | }, 922 | "notification-url": "https://packagist.org/downloads/", 923 | "license": [ 924 | "BSD-3-Clause" 925 | ], 926 | "authors": [ 927 | { 928 | "name": "Sebastian Bergmann", 929 | "email": "sebastian@phpunit.de" 930 | } 931 | ], 932 | "description": "Snapshotting of global state", 933 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 934 | "keywords": [ 935 | "global state" 936 | ], 937 | "time": "2015-10-12 03:26:01" 938 | }, 939 | { 940 | "name": "sebastian/recursion-context", 941 | "version": "1.0.2", 942 | "source": { 943 | "type": "git", 944 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 945 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791" 946 | }, 947 | "dist": { 948 | "type": "zip", 949 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", 950 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791", 951 | "shasum": "" 952 | }, 953 | "require": { 954 | "php": ">=5.3.3" 955 | }, 956 | "require-dev": { 957 | "phpunit/phpunit": "~4.4" 958 | }, 959 | "type": "library", 960 | "extra": { 961 | "branch-alias": { 962 | "dev-master": "1.0.x-dev" 963 | } 964 | }, 965 | "autoload": { 966 | "classmap": [ 967 | "src/" 968 | ] 969 | }, 970 | "notification-url": "https://packagist.org/downloads/", 971 | "license": [ 972 | "BSD-3-Clause" 973 | ], 974 | "authors": [ 975 | { 976 | "name": "Jeff Welch", 977 | "email": "whatthejeff@gmail.com" 978 | }, 979 | { 980 | "name": "Sebastian Bergmann", 981 | "email": "sebastian@phpunit.de" 982 | }, 983 | { 984 | "name": "Adam Harvey", 985 | "email": "aharvey@php.net" 986 | } 987 | ], 988 | "description": "Provides functionality to recursively process PHP variables", 989 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 990 | "time": "2015-11-11 19:50:13" 991 | }, 992 | { 993 | "name": "sebastian/version", 994 | "version": "1.0.6", 995 | "source": { 996 | "type": "git", 997 | "url": "https://github.com/sebastianbergmann/version.git", 998 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" 999 | }, 1000 | "dist": { 1001 | "type": "zip", 1002 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 1003 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 1004 | "shasum": "" 1005 | }, 1006 | "type": "library", 1007 | "autoload": { 1008 | "classmap": [ 1009 | "src/" 1010 | ] 1011 | }, 1012 | "notification-url": "https://packagist.org/downloads/", 1013 | "license": [ 1014 | "BSD-3-Clause" 1015 | ], 1016 | "authors": [ 1017 | { 1018 | "name": "Sebastian Bergmann", 1019 | "email": "sebastian@phpunit.de", 1020 | "role": "lead" 1021 | } 1022 | ], 1023 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1024 | "homepage": "https://github.com/sebastianbergmann/version", 1025 | "time": "2015-06-21 13:59:46" 1026 | }, 1027 | { 1028 | "name": "squizlabs/php_codesniffer", 1029 | "version": "2.5.1", 1030 | "source": { 1031 | "type": "git", 1032 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 1033 | "reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8" 1034 | }, 1035 | "dist": { 1036 | "type": "zip", 1037 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6731851d6aaf1d0d6c58feff1065227b7fda3ba8", 1038 | "reference": "6731851d6aaf1d0d6c58feff1065227b7fda3ba8", 1039 | "shasum": "" 1040 | }, 1041 | "require": { 1042 | "ext-tokenizer": "*", 1043 | "ext-xmlwriter": "*", 1044 | "php": ">=5.1.2" 1045 | }, 1046 | "require-dev": { 1047 | "phpunit/phpunit": "~4.0" 1048 | }, 1049 | "bin": [ 1050 | "scripts/phpcs", 1051 | "scripts/phpcbf" 1052 | ], 1053 | "type": "library", 1054 | "extra": { 1055 | "branch-alias": { 1056 | "dev-master": "2.x-dev" 1057 | } 1058 | }, 1059 | "autoload": { 1060 | "classmap": [ 1061 | "CodeSniffer.php", 1062 | "CodeSniffer/CLI.php", 1063 | "CodeSniffer/Exception.php", 1064 | "CodeSniffer/File.php", 1065 | "CodeSniffer/Fixer.php", 1066 | "CodeSniffer/Report.php", 1067 | "CodeSniffer/Reporting.php", 1068 | "CodeSniffer/Sniff.php", 1069 | "CodeSniffer/Tokens.php", 1070 | "CodeSniffer/Reports/", 1071 | "CodeSniffer/Tokenizers/", 1072 | "CodeSniffer/DocGenerators/", 1073 | "CodeSniffer/Standards/AbstractPatternSniff.php", 1074 | "CodeSniffer/Standards/AbstractScopeSniff.php", 1075 | "CodeSniffer/Standards/AbstractVariableSniff.php", 1076 | "CodeSniffer/Standards/IncorrectPatternException.php", 1077 | "CodeSniffer/Standards/Generic/Sniffs/", 1078 | "CodeSniffer/Standards/MySource/Sniffs/", 1079 | "CodeSniffer/Standards/PEAR/Sniffs/", 1080 | "CodeSniffer/Standards/PSR1/Sniffs/", 1081 | "CodeSniffer/Standards/PSR2/Sniffs/", 1082 | "CodeSniffer/Standards/Squiz/Sniffs/", 1083 | "CodeSniffer/Standards/Zend/Sniffs/" 1084 | ] 1085 | }, 1086 | "notification-url": "https://packagist.org/downloads/", 1087 | "license": [ 1088 | "BSD-3-Clause" 1089 | ], 1090 | "authors": [ 1091 | { 1092 | "name": "Greg Sherwood", 1093 | "role": "lead" 1094 | } 1095 | ], 1096 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1097 | "homepage": "http://www.squizlabs.com/php-codesniffer", 1098 | "keywords": [ 1099 | "phpcs", 1100 | "standards" 1101 | ], 1102 | "time": "2016-01-19 23:39:10" 1103 | }, 1104 | { 1105 | "name": "symfony/yaml", 1106 | "version": "v2.8.3", 1107 | "source": { 1108 | "type": "git", 1109 | "url": "https://github.com/symfony/yaml.git", 1110 | "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995" 1111 | }, 1112 | "dist": { 1113 | "type": "zip", 1114 | "url": "https://api.github.com/repos/symfony/yaml/zipball/2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", 1115 | "reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995", 1116 | "shasum": "" 1117 | }, 1118 | "require": { 1119 | "php": ">=5.3.9" 1120 | }, 1121 | "type": "library", 1122 | "extra": { 1123 | "branch-alias": { 1124 | "dev-master": "2.8-dev" 1125 | } 1126 | }, 1127 | "autoload": { 1128 | "psr-4": { 1129 | "Symfony\\Component\\Yaml\\": "" 1130 | }, 1131 | "exclude-from-classmap": [ 1132 | "/Tests/" 1133 | ] 1134 | }, 1135 | "notification-url": "https://packagist.org/downloads/", 1136 | "license": [ 1137 | "MIT" 1138 | ], 1139 | "authors": [ 1140 | { 1141 | "name": "Fabien Potencier", 1142 | "email": "fabien@symfony.com" 1143 | }, 1144 | { 1145 | "name": "Symfony Community", 1146 | "homepage": "https://symfony.com/contributors" 1147 | } 1148 | ], 1149 | "description": "Symfony Yaml Component", 1150 | "homepage": "https://symfony.com", 1151 | "time": "2016-02-23 07:41:20" 1152 | } 1153 | ], 1154 | "aliases": [], 1155 | "minimum-stability": "stable", 1156 | "stability-flags": [], 1157 | "prefer-stable": false, 1158 | "prefer-lowest": false, 1159 | "platform": { 1160 | "php": ">=5.4" 1161 | }, 1162 | "platform-dev": [] 1163 | } 1164 | --------------------------------------------------------------------------------