diff --git a/.travis.yml b/.travis.yml
index a5aa754..5610f7d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,13 @@
language: php
php:
- - 5.5
- - 5.6
- 7.0
+ - 7.1
+ - 7.2
before_script:
- - composer self-update
- - composer install --dev
+ - composer install
+ - ./vendor/bin/phpcs -n --standard=PSR2 src/ tests/
-script: phpunit --coverage-text
\ No newline at end of file
+script:
+ - phpunit --coverage-text
diff --git a/README.md b/README.md
index 0dc77ee..07e14e4 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,18 @@ Rakit Validation - PHP Standalone Validation Library
PHP Standalone library for validating data. Inspired by `Illuminate\Validation` Laravel.
+## Features
+
+* API like Laravel validation.
+* Array validation.
+* `$_FILES` validation with multiple file support.
+* Custom attribute aliases.
+* Custom validation messages.
+* Custom rule.
+
## Requirements
-* PHP 5.5 or higher
+* PHP 7.0 or higher
* Composer for installation
## Quick Start
@@ -258,52 +267,202 @@ $validation_a = $validator->make($dataset_a, [
$validation_a->validate();
```
+## Translation
+
+Translation is different with custom messages.
+Translation may needed when you use custom message for rule `in`, `not_in`, `mimes`, and `uploaded_file`.
+
+For example if you use rule `in:1,2,3` we will set invalid message like "The Attribute only allows '1', '2', or '3'"
+where part "'1', '2', or '3'" is comes from ":allowed_values" tag.
+So if you have custom Indonesian message ":attribute hanya memperbolehkan :allowed_values",
+we will set invalid message like "Attribute hanya memperbolehkan '1', '2', or '3'" which is the "or" word is not part of Indonesian language.
+
+So, to solve this problem, we can use translation like this:
+
+```php
+// Set translation for words 'and' and 'or'.
+$validator->setTranslations([
+ 'and' => 'dan',
+ 'or' => 'atau'
+]);
+
+// Set custom message for 'in' rule
+$validator->setMessage('in', ":attribute hanya memperbolehkan :allowed_values");
+
+// Validate
+$validation = $validator->validate($inputs, [
+ 'nomor' => 'in:1,2,3'
+]);
+
+$message = $validation->errors()->first('nomor'); // "Nomor hanya memperbolehkan '1', '2', atau '3'"
+```
+
+> Actually, our built-in rules only use words 'and' and 'or' that you may need to translates.
+
+## Working with Error Message
+
+Errors messages are collected in `Rakit\Validation\ErrorBag` object that you can get it using `errors()` method.
+
+```php
+$validation = $validator->validate($inputs, $rules);
+
+$errors = $validation->errors(); // << ErrorBag
+```
+
+Now you can use methods below to retrieves errors messages:
+
+#### `all(string $format = ':message')`
+
+Get all messages as flatten array.
+
+Examples:
+
+```php
+$messages = $errors->all();
+// [
+// 'Email is not valid email',
+// 'Password minimum 6 character',
+// 'Password must contains capital letters'
+// ]
+
+$messages = $errors->all('
:message
');
+// [
+// '
Email is not valid email
',
+// '
Password minimum 6 character
',
+// '
Password must contains capital letters
'
+// ]
+```
+
+#### `firstOfAll(string $format = ':message', bool $dotNotation = false)`
+
+Get only first message from all existing keys.
+
+Examples:
+
+```php
+$messages = $errors->firstOfAll();
+// [
+// 'email' => Email is not valid email',
+// 'password' => 'Password minimum 6 character',
+// ]
+
+$messages = $errors->firstOfAll('
:message
');
+// [
+// 'email' => '
Email is not valid email
',
+// 'password' => '
Password minimum 6 character
',
+// ]
+```
+
+Argument `$dotNotation` is for array validation.
+If it is `false` it will return original array structure, if it `true` it will return flatten array with dot notation keys.
+
+For example:
+
+```php
+$messages = $errors->firstOfAll(':message', false);
+// [
+// 'contacts' => [
+// 1 => [
+// 'email' => 'Email is not valid email',
+// 'phone' => 'Phone is not valid phone number'
+// ],
+// ],
+// ]
+
+$messages = $errors->firstOfAll(':message', true);
+// [
+// 'contacts.1.email' => 'Email is not valid email',
+// 'contacts.1.phone' => 'Email is not valid phone number',
+// ]
+```
+
+#### `first(string $key)`
+
+Get first message from given key. It will return `string` if key has any error message, or `null` if key has no errors.
+
+For example:
+
+```php
+if ($emailError = $errors->first('email')) {
+ echo $emailError;
+}
+```
+
+#### `toArray()`
+
+Get all messages grouped by it's keys.
+
+For example:
+
+```php
+$messages = $errors->toArray();
+// [
+// 'email' => [
+// 'Email is not valid email'
+// ],
+// 'password' => [
+// 'Password minimum 6 character',
+// 'Password must contains capital letters'
+// ]
+// ]
+```
+
+#### `count()`
+
+Get count messages.
+
+#### `has(string $key)`
+
+Check if given key has an error. It returns `bool` if a key has an error, and otherwise.
+
+
+## Getting Validated, Valid, and Invalid Data
+
+For example you have validation like this:
+
+```php
+$validation = $validator->validate([
+ 'title' => 'Lorem Ipsum',
+ 'body' => 'Lorem ipsum dolor sit amet ...',
+ 'published' => null,
+ 'something' => '-invalid-'
+], [
+ 'title' => 'required',
+ 'body' => 'required',
+ 'published' => 'default:1|required|in:0,1',
+ 'something' => 'required|numeric'
+]);
+```
+
+You can get validated data, valid data, or invalid data using methods in example below:
+
+```php
+$validatedData = $validation->getValidatedData();
+// [
+// 'title' => 'Lorem Ipsum',
+// 'body' => 'Lorem ipsum dolor sit amet ...',
+// 'published' => '1' // notice this
+// 'something' => '-invalid-'
+// ]
+
+$validData = $validation->getValidData();
+// [
+// 'title' => 'Lorem Ipsum',
+// 'body' => 'Lorem ipsum dolor sit amet ...',
+// 'published' => '1'
+// ]
+
+$invalidData = $validation->getInvalidData();
+// [
+// 'something' => '-invalid-'
+// ]
+```
+
## Available Rules
-Below is list of all available validation rules
-
-* [required](#rule-required)
-* [required_if](#rule-required_if)
-* [required_unless](#rule-required_unless)
-* [required_with](#rule-required_with)
-* [required_without](#rule-required_without)
-* [required_with_all](#rule-required_with_all)
-* [required_without_all](#rule-required_without_all)
-* [uploaded_file](#rule-uploaded_file)
-* [default/defaults](#rule-default)
-* [email](#rule-email)
-* [uppercase](#rule-uppercase)
-* [lowercase](#rule-lowercase)
-* [json](#rule-json)
-* [alpha](#rule-alpha)
-* [numeric](#rule-numeric)
-* [alpha_num](#rule-alpha_num)
-* [alpha_dash](#rule-alpha_dash)
-* [in](#rule-in)
-* [not_in](#rule-not_in)
-* [min](#rule-min)
-* [max](#rule-max)
-* [between](#rule-between)
-* [digits](#rule-digits)
-* [digits_between](#rule-digits_between)
-* [url](#rule-url)
-* [integer](#rule-integer)
-* [ip](#rule-ip)
-* [ipv4](#rule-ipv4)
-* [ipv6](#rule-ipv6)
-* [array](#rule-array)
-* [same](#rule-same)
-* [regex](#rule-regex)
-* [date](#rule-date)
-* [accepted](#rule-accepted)
-* [present](#rule-present)
-* [different](#rule-different)
-* [after](#after)
-* [before](#before)
-* [callback](#callback)
-
-
-#### required
+> Click to show details.
+
+required
The field under this validation must be present and not 'empty'.
@@ -322,43 +481,50 @@ Here are some examples:
For uploaded file, `$_FILES['key']['error']` must not `UPLOAD_ERR_NO_FILE`.
-
-#### required_if:another_field,value_1,value_2,...
+
+
+required_if:another_field,value_1,value_2,...
The field under this rule must be present and not empty if the anotherfield field is equal to any value.
For example `required_if:something,1,yes,on` will be required if `something` value is one of `1`, `'1'`, `'yes'`, or `'on'`.
-
-#### required_unless:another_field,value_1,value_2,...
+
+
+required_unless:another_field,value_1,value_2,...
The field under validation must be present and not empty unless the anotherfield field is equal to any value.
-
-#### required_with:field_1,field_2,...
+
+
+required_with:field_1,field_2,...
The field under validation must be present and not empty only if any of the other specified fields are present.
-
-#### required_without:field_1,field_2,...
+
+
+required_without:field_1,field_2,...
The field under validation must be present and not empty only when any of the other specified fields are not present.
-
-#### required_with_all:field_1,field_2,...
+
+
+required_with_all:field_1,field_2,...
The field under validation must be present and not empty only if all of the other specified fields are present.
-
-#### required_without_all:field_1,field_2,...
+
+
+required_without_all:field_1,field_2,...
The field under validation must be present and not empty only when all of the other specified fields are not present.
-
-#### uploaded_file:min_size,max_size,file_type_a,file_type_b,...
+
+
+uploaded_file:min_size,max_size,extension_a,extension_b,...
-This rule will validate `$_FILES` data, but not for multiple uploaded files.
-Field under this rule must be following rules below to be valid:
+This rule will validate data from `$_FILES`.
+Field under this rule must be follows rules below to be valid:
* `$_FILES['key']['error']` must be `UPLOAD_ERR_OK` or `UPLOAD_ERR_NO_FILE`. For `UPLOAD_ERR_NO_FILE` you can validate it with `required` rule.
* If min size is given, uploaded file size **MUST NOT** be lower than min size.
@@ -372,8 +538,66 @@ Here are some example definitions and explanations:
* `uploaded_file:0,1M`: uploaded file size must be between 0 - 1 MB, but uploaded file is optional.
* `required|uploaded_file:0,1M,png,jpeg`: uploaded file size must be between 0 - 1MB and mime types must be `image/jpeg` or `image/png`.
-
-#### default/defaults
+Optionally, if you want to have separate error message between size and type validation.
+You can use `mimes` rule to validate file types, and `min`, `max`, or `between` to validate it's size.
+
+For multiple file upload, PHP will give you undesirable array `$_FILES` structure ([here](http://php.net/manual/en/features.file-upload.multiple.php#53240) is the topic). So we make `uploaded_file` rule to automatically resolve your `$_FILES` value to be well-organized array structure. That means, you cannot only use `min`, `max`, `between`, or `mimes` rules to validate multiple file upload. You should put `uploaded_file` just to resolve it's value and make sure that value is correct uploaded file value.
+
+For example if you have input files like this:
+
+```html
+
+
+
+```
+
+You can simply validate it like this:
+
+```php
+$validation = $validator->validate($_FILES, [
+ 'photos.*' => 'uploaded_file:0,2M,jpeg,png'
+]);
+
+// or
+
+$validation = $validator->validate($_FILES, [
+ 'photos.*' => 'uploaded_file|max:2M|mimes:jpeg,png'
+]);
+```
+
+Or if you have input files like this:
+
+```html
+
+
+```
+
+You can validate it like this:
+
+```php
+$validation = $validator->validate($_FILES, [
+ 'images.*' => 'uploaded_file|max:2M|mimes:jpeg,png',
+]);
+
+// or
+
+$validation = $validator->validate($_FILES, [
+ 'images.profile' => 'uploaded_file|max:2M|mimes:jpeg,png',
+ 'images.cover' => 'uploaded_file|max:5M|mimes:jpeg,png',
+]);
+```
+
+Now when you use `getValidData()` or `getInvalidData()` you will get well array structure just like single file upload.
+
+
+
+mimes:extension_a,extension_b,...
+
+The `$_FILES` item under validation must have a MIME type corresponding to one of the listed extensions.
+
+
+
+default/defaults
This is special rule that doesn't validate anything.
It just set default value to your attribute if that attribute is empty or not present.
@@ -393,48 +617,57 @@ $validation->passes(); // true
Validation passes because we sets default value for `enabled` and `published` to `1` and `0` which is valid.
-
-#### email
+
+
+email
The field under this validation must be valid email address.
-
-#### uppercase
+
+
+uppercase
The field under this validation must be valid uppercase.
-
-#### lowercase
+
+
+lowercase
The field under this validation must be valid lowercase.
-
-#### json
+
+
+json
The field under this validation must be valid JSON string.
-
-#### alpha
+
+
+alpha
The field under this rule must be entirely alphabetic characters.
-
-#### numeric
+
+
+numeric
The field under this rule must be numeric.
-
-#### alpha_num
+
+
+alpha_num
The field under this rule must be entirely alpha-numeric characters.
-
-#### alpha_dash
+
+
+alpha_dash
The field under this rule may have alpha-numeric characters, as well as dashes and underscores.
-
-#### in:value_1,value_2,...
+
+
+in:value_1,value_2,...
The field under this rule must be included in the given list of values.
@@ -454,44 +687,84 @@ $validation = $validator->validate($data, [
Then 'enabled' value should be boolean `true`, or int `1`.
-
-#### not_in:value_1,value_2,...
+
+
+not_in:value_1,value_2,...
The field under this rule must not be included in the given list of values.
This rule also using `in_array`. You can enable strict checking by invoking validator and call `strict()` like example in rule `in` above.
-
-#### min:number
+
+
+min:number
The field under this rule must have a size greater or equal than the given number.
For string data, value corresponds to the number of characters. For numeric data, value corresponds to a given integer value. For an array, size corresponds to the count of the array.
-
-#### max:number
+You can also validate uploaded file using this rule to validate minimum size of uploaded file.
+For example:
+
+```php
+$validation = $validator->validate([
+ 'photo' => $_FILES['photo']
+], [
+ 'photo' => 'required|min:1M'
+]);
+```
+
+
+
+max:number
The field under this rule must have a size lower or equal than the given number.
Value size calculated in same way like `min` rule.
-
-#### between:min,max
+You can also validate uploaded file using this rule to validate maximum size of uploaded file.
+For example:
+
+```php
+$validation = $validator->validate([
+ 'photo' => $_FILES['photo']
+], [
+ 'photo' => 'required|max:2M'
+]);
+```
+
+
+
+between:min,max
The field under this rule must have a size between min and max params.
Value size calculated in same way like `min` and `max` rule.
-
-#### digits:value
+You can also validate uploaded file using this rule to validate size of uploaded file.
+For example:
+
+```php
+$validation = $validator->validate([
+ 'photo' => $_FILES['photo']
+], [
+ 'photo' => 'required|between:1M,2M'
+]);
+```
+
+
+
+digits:value
The field under validation must be numeric and must have an exact length of `value`.
-
-#### digits_between:min,max
+
+
+digits_between:min,max
The field under validation must have a length between the given `min` and `max`.
-
-#### url
+
+
+url
The field under this rule must be valid url format.
By default it check common URL scheme format like `any_scheme://...`.
@@ -514,62 +787,74 @@ $validation = $validator->validate($inputs, [
> For common URL scheme and mailto, we combine `FILTER_VALIDATE_URL` to validate URL format and `preg_match` to validate it's scheme.
Except for JDBC URL, currently it just check a valid JDBC scheme.
-
-#### integer
-The field under this rule must be integer.
+
+
+integer
+The field under t rule must be integer.
+
+
-
-#### ip
+ip
The field under this rule must be valid ipv4 or ipv6.
-
-#### ipv4
+
+
+ipv4
The field under this rule must be valid ipv4.
-
-#### ipv6
+
+
+ipv6
The field under this rule must be valid ipv6.
-
-#### array
+
+
+array
The field under this rule must be array.
-
-#### same:another_field
+
+
+same:another_field
The field value under this rule must be same with `another_field` value.
-
-#### regex:/your-regex/
+
+
+regex:/your-regex/
The field under this rule must be match with given regex.
-
-#### date:format
+
+
+date:format
The field under this rule must be valid date format. Parameter `format` is optional, default format is `Y-m-d`.
-
-#### accepted
+
+
+accepted
The field under this rule must be one of `'on'`, `'yes'`, `'1'`, `'true'`, or `true`.
-
-#### present
+
+
+present
The field under this rule must be exists, whatever the value is.
-
-#### different:another_field
+
+
+different:another_field
Opposite of `same`. The field value under this rule must be different with `another_field` value.
-
-#### after:tomorrow
+
+
+after:tomorrow
Anything that can be parsed by `strtotime` can be passed as a parameter to this rule. Valid examples include :
- after:next week
@@ -577,13 +862,15 @@ Anything that can be parsed by `strtotime` can be passed as a parameter to this
- after:2016
- after:2016-12-31 09:56:02
-
-#### before:yesterday
+
+
+before:yesterday
This also works the same way as the [after rule](#after). Pass anything that can be parsed by `strtotime`
-
-#### callback
+
+
+callback
You can use this rule to define your own validation rule.
This rule can't be registered using string pipe.
@@ -626,7 +913,10 @@ $validation = $validator->validate($_POST, [
> Note: `Rakit\Validation\Rules\Callback` instance is binded into your Closure.
So you can access rule properties and methods using `$this`.
-## Register/Modify Rule
+
+
+
+## Register/Override Rule
Another way to use custom validation rule is to create a class extending `Rakit\Validation\Rule`.
Then register it using `setValidator` or `addValidator`.
@@ -653,7 +943,7 @@ class UniqueRule extends Rule
$this->pdo = $pdo;
}
- public function check($value)
+ public function check($value): bool
{
// make sure required parameters exists
$this->requireParameters(['table', 'column']);
@@ -765,45 +1055,82 @@ $validation = $validator->validate($_POST, [
]);
```
-## Getting Validated, Valid, and Invalid Data
+#### Implicit Rule
-For example you have validation like this:
+Implicit rule is a rule that if it's invalid, then next rules will be ignored. For example if attribute didn't pass `required*` rules, mostly it's next rules will also be invalids. So to prevent our next rules messages to get collected, we make `required*` rules to be implicit.
+
+To make your custom rule implicit, you can make `$implicit` property value to be `true`. For example:
```php
-$validation = $validator->validate([
- 'title' => 'Lorem Ipsum',
- 'body' => 'Lorem ipsum dolor sit amet ...',
- 'published' => null,
- 'something' => '-invalid-'
-], [
- 'title' => 'required',
- 'body' => 'required',
- 'published' => 'default:1|required|in:0,1',
- 'something' => 'required|numeric'
-]);
-```
+getValidatedData();
-// [
-// 'title' => 'Lorem Ipsum',
-// 'body' => 'Lorem ipsum dolor sit amet ...',
-// 'published' => '1' // notice this
-// 'something' => '-invalid-'
-// ]
+getValidData();
-// [
-// 'title' => 'Lorem Ipsum',
-// 'body' => 'Lorem ipsum dolor sit amet ...',
-// 'published' => '1'
-// ]
+use Rakit\Validation\Rule;
+use Rakit\Validation\Rules\Interfaces\ModifyValue;
-$invalidData = $validation->getInvalidData();
-// [
-// 'something' => '-invalid-'
-// ]
+class YourCustomRule extends Rule implements ModifyValue
+{
+ ...
+
+ public function modifyValue($value)
+ {
+ // Do something with $value
+
+ return $value;
+ }
+
+ ...
+}
```
+#### Before Validation Hook
+
+You may want to do some preparation before validation running. For example our `uploaded_file` rule will resolves attribute value that come from `$_FILES` (undesirable) array structure to be well-organized array structure, so we can validate multiple file upload just like validating other data.
+
+To do this, you should implements `Rakit\Validation\Rules\Interfaces\BeforeValidate` and create method `beforeValidate()` to your custom rule class.
+
+For example:
+
+```php
+getAttribute(); // Rakit\Validation\Attribute instance
+ $validation = $this->validation; // Rakit\Validation\Validation instance
+
+ // Do something with $attribute and $validation
+ // For example change attribute value
+ $validation->setValue($attribute->getKey(), "your custom value");
+ }
+
+ ...
+}
+```
diff --git a/composer.json b/composer.json
index c316baa..d61350f 100644
--- a/composer.json
+++ b/composer.json
@@ -13,11 +13,23 @@
"Rakit\\Validation\\": "src"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "Rakit\\Validation\\Tests\\": ["tests", "tests/Fixtures"]
+ }
+ },
"require": {
- "php": ">=5.5.0",
+ "php": ">=7.0",
"ext-mbstring": "*"
},
"require-dev": {
- "phpunit/phpunit": "4.*"
+ "phpunit/phpunit": "^6.5",
+ "squizlabs/php_codesniffer": "^3"
+ },
+ "scripts": {
+ "test": [
+ "phpunit",
+ "phpcs"
+ ]
}
-}
\ No newline at end of file
+}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..0858d1d
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,17 @@
+
+
+ Rakit validation coding standard
+
+
+
+
+
+
+
+
+
+
+
+ src
+ tests
+
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 61e0272..3390a42 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,13 +1,22 @@
-
+
+
-
+ ./tests
-
- ./src
+ ./src
-
\ No newline at end of file
+
diff --git a/src/Attribute.php b/src/Attribute.php
index 4d89162..56c06e0 100644
--- a/src/Attribute.php
+++ b/src/Attribute.php
@@ -5,65 +5,126 @@
class Attribute
{
+ /** @var array */
protected $rules = [];
+ /** @var string */
protected $key;
+ /** @var string|null */
protected $alias;
+ /** @var Rakit\Validation\Validation */
protected $validation;
+ /** @var bool */
protected $required = false;
+ /** @var Rakit\Validation\Validation|null */
protected $primaryAttribute = null;
+ /** @var array */
protected $otherAttributes = [];
+ /** @var array */
protected $keyIndexes = [];
- public function __construct(Validation $validation, $key, $alias = null, array $rules = array())
- {
+ /**
+ * Constructor
+ *
+ * @param Rakit\Validation\Validation $validation
+ * @param string $key
+ * @param string|null $alias
+ * @param array $rules
+ * @return void
+ */
+ public function __construct(
+ Validation $validation,
+ string $key,
+ $alias = null,
+ array $rules = []
+ ) {
$this->validation = $validation;
$this->alias = $alias;
$this->key = $key;
- foreach($rules as $rule) {
+ foreach ($rules as $rule) {
$this->addRule($rule);
}
}
+ /**
+ * Set the primary attribute
+ *
+ * @param Rakit\Validation\Attribute $primaryAttribute
+ * @return void
+ */
public function setPrimaryAttribute(Attribute $primaryAttribute)
{
$this->primaryAttribute = $primaryAttribute;
}
+ /**
+ * Set key indexes
+ *
+ * @param array $keyIndexes
+ * @return void
+ */
public function setKeyIndexes(array $keyIndexes)
{
$this->keyIndexes = $keyIndexes;
}
+ /**
+ * Get primary attributes
+ *
+ * @return Rakit\Validation\Attribute|null
+ */
public function getPrimaryAttribute()
{
return $this->primaryAttribute;
}
+ /**
+ * Set other attributes
+ *
+ * @param array $otherAttributes
+ * @return void
+ */
public function setOtherAttributes(array $otherAttributes)
{
$this->otherAttributes = [];
- foreach($otherAttributes as $otherAttribute) {
+ foreach ($otherAttributes as $otherAttribute) {
$this->addOtherAttribute($otherAttribute);
}
}
+ /**
+ * Add other attributes
+ *
+ * @param Rakit\Validation\Attribute $otherAttribute
+ * @return void
+ */
public function addOtherAttribute(Attribute $otherAttribute)
{
$this->otherAttributes[] = $otherAttribute;
}
- public function getOtherAttributes()
+ /**
+ * Get other attributes
+ *
+ * @return array
+ */
+ public function getOtherAttributes(): array
{
return $this->otherAttributes;
}
+ /**
+ * Add rule
+ *
+ * @param Rakit\Validation\Rule $rule
+ * @return void
+ */
public function addRule(Rule $rule)
{
$rule->setAttribute($this);
@@ -71,42 +132,86 @@ public function addRule(Rule $rule)
$this->rules[$rule->getKey()] = $rule;
}
- public function getRule($ruleKey)
+ /**
+ * Get rule
+ *
+ * @param string $ruleKey
+ * @return void
+ */
+ public function getRule(string $ruleKey)
{
return $this->hasRule($ruleKey)? $this->rules[$ruleKey] : null;
}
- public function getRules()
+ /**
+ * Get rules
+ *
+ * @return array
+ */
+ public function getRules(): array
{
return $this->rules;
}
- public function hasRule($ruleKey)
+ /**
+ * Check the $ruleKey has in the rule
+ *
+ * @param string $ruleKey
+ * @return bool
+ */
+ public function hasRule(string $ruleKey): bool
{
return isset($this->rules[$ruleKey]);
}
- public function setRequired($required)
+ /**
+ * Set required
+ *
+ * @param boolean $required
+ * @return void
+ */
+ public function setRequired(bool $required)
{
$this->required = $required;
}
- public function isRequired()
+ /**
+ * Set rule is required
+ *
+ * @return boolean
+ */
+ public function isRequired(): bool
{
- return $this->required === true;
+ return $this->required;
}
- public function getKey()
+ /**
+ * Get key
+ *
+ * @return string
+ */
+ public function getKey(): string
{
return $this->key;
}
- public function getKeyIndexes()
+ /**
+ * Get key indexes
+ *
+ * @return array
+ */
+ public function getKeyIndexes(): array
{
return $this->keyIndexes;
}
- public function getValue($key = null)
+ /**
+ * Get value
+ *
+ * @param string|null $key
+ * @return void
+ */
+ public function getValue(string $key = null)
{
if ($key && $this->isArrayAttribute()) {
$key = $this->resolveSiblingKey($key);
@@ -119,17 +224,33 @@ public function getValue($key = null)
return $this->validation->getValue($key);
}
- public function isArrayAttribute()
+ /**
+ * Get that is array attribute
+ *
+ * @return boolean
+ */
+ public function isArrayAttribute(): bool
{
return count($this->getKeyIndexes()) > 0;
}
- public function isUsingDotNotation()
+ /**
+ * Check this attribute is using dot notation
+ *
+ * @return boolean
+ */
+ public function isUsingDotNotation(): bool
{
return strpos($this->getKey(), '.') !== false;
}
- public function resolveSiblingKey($key)
+ /**
+ * Resolve sibling key
+ *
+ * @param string $key
+ * @return string
+ */
+ public function resolveSiblingKey(string $key): string
{
$indexes = $this->getKeyIndexes();
$keys = explode("*", $key);
@@ -141,6 +262,11 @@ public function resolveSiblingKey($key)
return call_user_func_array('sprintf', $args);
}
+ /**
+ * Get humanize key
+ *
+ * @return string
+ */
public function getHumanizedKey()
{
$primaryAttribute = $this->getPrimaryAttribute();
@@ -149,7 +275,7 @@ public function getHumanizedKey()
// Resolve key from array validation
if ($primaryAttribute) {
$split = explode('.', $key);
- $key = implode(' ', array_map(function($word) {
+ $key = implode(' ', array_map(function ($word) {
if (is_numeric($word)) {
$word = $word + 1;
}
@@ -160,14 +286,24 @@ public function getHumanizedKey()
return ucfirst($key);
}
- public function setAlias($alias)
+ /**
+ * Set alias
+ *
+ * @param string $alias
+ * @return void
+ */
+ public function setAlias(string $alias)
{
$this->alias = $alias;
}
+ /**
+ * Get alias
+ *
+ * @return string|null
+ */
public function getAlias()
{
return $this->alias;
}
-
}
diff --git a/src/ErrorBag.php b/src/ErrorBag.php
index 9ceecda..2836d4a 100644
--- a/src/ErrorBag.php
+++ b/src/ErrorBag.php
@@ -5,14 +5,29 @@
class ErrorBag
{
+ /** @var array */
protected $messages = [];
+ /**
+ * Constructor
+ *
+ * @param array $messages
+ * @return void
+ */
public function __construct(array $messages = [])
{
$this->messages = $messages;
}
- public function add($key, $rule, $message)
+ /**
+ * Add message for given key and rule
+ *
+ * @param string $key
+ * @param string $rule
+ * @param string $message
+ * @return void
+ */
+ public function add(string $key, string $rule, string $message)
{
if (!isset($this->messages[$key])) {
$this->messages[$key] = [];
@@ -21,12 +36,23 @@ public function add($key, $rule, $message)
$this->messages[$key][$rule] = $message;
}
- public function count()
+ /**
+ * Get messages count
+ *
+ * @return int
+ */
+ public function count(): int
{
return count($this->all());
}
- public function has($key)
+ /**
+ * Check given key is existed
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has(string $key): bool
{
list($key, $ruleName) = $this->parsekey($key);
if ($this->isWildcardKey($key)) {
@@ -38,12 +64,18 @@ public function has($key)
if (!$ruleName) {
return !empty($messages);
} else {
- return !empty($messages) AND isset($messages[$ruleName]);
+ return !empty($messages) and isset($messages[$ruleName]);
}
}
}
- public function first($key)
+ /**
+ * Get the first value of array
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function first(string $key)
{
list($key, $ruleName) = $this->parsekey($key);
if ($this->isWildcardKey($key)) {
@@ -65,21 +97,30 @@ public function first($key)
}
}
- public function get($key, $format = ':message')
+ /**
+ * Get messages from given key, can be use custom format
+ *
+ * @param string $key
+ * @param string $format
+ * @return array
+ */
+ public function get(string $key, string $format = ':message'): array
{
list($key, $ruleName) = $this->parsekey($key);
$results = [];
if ($this->isWildcardKey($key)) {
$messages = $this->filterMessagesForWildcardKey($key, $ruleName);
- foreach($messages as $explicitKey => $keyMessages) {
+ foreach ($messages as $explicitKey => $keyMessages) {
foreach ($keyMessages as $rule => $message) {
$results[$explicitKey][$rule] = $this->formatMessage($message, $format);
}
}
} else {
$keyMessages = isset($this->messages[$key])? $this->messages[$key] : [];
- foreach($keyMessages as $rule => $message) {
- if ($ruleName AND $ruleName != $rule) continue;
+ foreach ($keyMessages as $rule => $message) {
+ if ($ruleName and $ruleName != $rule) {
+ continue;
+ }
$results[$rule] = $this->formatMessage($message, $format);
}
}
@@ -87,34 +128,62 @@ public function get($key, $format = ':message')
return $results;
}
- public function all($format = ':message')
+ /**
+ * Get all messages
+ *
+ * @param string $format
+ * @return array
+ */
+ public function all(string $format = ':message'): array
{
$messages = $this->messages;
$results = [];
- foreach($messages as $key => $keyMessages) {
- foreach($keyMessages as $message) {
+ foreach ($messages as $key => $keyMessages) {
+ foreach ($keyMessages as $message) {
$results[] = $this->formatMessage($message, $format);
}
}
return $results;
}
- public function firstOfAll($format = ':message')
+ /**
+ * Get the first message from existing keys
+ *
+ * @param string $format
+ * @param boolean $dotNotation
+ * @return array
+ */
+ public function firstOfAll(string $format = ':message', bool $dotNotation = false): array
{
$messages = $this->messages;
$results = [];
- foreach($messages as $key => $keyMessages) {
- $results[] = $this->formatMessage(array_shift($messages[$key]), $format);
+ foreach ($messages as $key => $keyMessages) {
+ if ($dotNotation) {
+ $results[$key] = $this->formatMessage(array_shift($messages[$key]), $format);
+ } else {
+ Helper::arraySet($results, $key, $this->formatMessage(array_shift($messages[$key]), $format));
+ }
}
return $results;
}
- public function toArray()
+ /**
+ * Get plain array messages
+ *
+ * @return array
+ */
+ public function toArray(): array
{
return $this->messages;
}
- protected function parseKey($key)
+ /**
+ * Parse $key to get the array of $key and $ruleName
+ *
+ * @param string $key
+ * @return array
+ */
+ protected function parseKey(string $key): array
{
$expl = explode(':', $key, 2);
$key = $expl[0];
@@ -122,12 +191,25 @@ protected function parseKey($key)
return [$key, $ruleName];
}
- protected function isWildcardKey($key)
+ /**
+ * Check the $key is wildcard
+ *
+ * @param mixed $key
+ * @return bool
+ */
+ protected function isWildcardKey(string $key): bool
{
return false !== strpos($key, '*');
}
- protected function filterMessagesForWildcardKey($key, $ruleName = null)
+ /**
+ * Filter messages with wildcard key
+ *
+ * @param string $key
+ * @param mixed $ruleName
+ * @return array
+ */
+ protected function filterMessagesForWildcardKey(string $key, $ruleName = null): array
{
$messages = $this->messages;
$pattern = preg_quote($key, '#');
@@ -140,8 +222,10 @@ protected function filterMessagesForWildcardKey($key, $ruleName = null)
continue;
}
- foreach($keyMessages as $rule => $message) {
- if ($ruleName AND $rule != $ruleName) continue;
+ foreach ($keyMessages as $rule => $message) {
+ if ($ruleName and $rule != $ruleName) {
+ continue;
+ }
$filteredMessages[$k][$rule] = $message;
}
}
@@ -149,9 +233,15 @@ protected function filterMessagesForWildcardKey($key, $ruleName = null)
return $filteredMessages;
}
- protected function formatMessage($message, $format)
+ /**
+ * Get formatted message
+ *
+ * @param string $message
+ * @param string $format
+ * @return string
+ */
+ protected function formatMessage(string $message, string $format): string
{
return str_replace(':message', $message, $format);
}
-
}
diff --git a/src/Helper.php b/src/Helper.php
index 0596152..816f020 100644
--- a/src/Helper.php
+++ b/src/Helper.php
@@ -9,11 +9,11 @@ class Helper
* Determine if a given string matches a given pattern.
* Adapted from: https://github.com/illuminate/support/blob/v5.3.23/Str.php#L119
*
- * @param string $pattern
- * @param string $value
+ * @param string $pattern
+ * @param string $value
* @return bool
*/
- public static function strIs($pattern, $value)
+ public static function strIs(string $pattern, string $value): bool
{
if ($pattern == $value) {
return true;
@@ -33,11 +33,11 @@ public static function strIs($pattern, $value)
* Check if an item or items exist in an array using "dot" notation.
* Adapted from: https://github.com/illuminate/support/blob/v5.3.23/Arr.php#L81
*
- * @param array $array
- * @param string|array $keys
+ * @param array $array
+ * @param string $key
* @return bool
*/
- public static function arrayHas(array $array, $key)
+ public static function arrayHas(array $array, string $key): bool
{
if (array_key_exists($key, $array)) {
return true;
@@ -59,11 +59,11 @@ public static function arrayHas(array $array, $key)
* Adapted from: https://github.com/illuminate/support/blob/v5.3.23/Arr.php#L246
*
* @param array $array
- * @param string $key
- * @param mixed $default
+ * @param string $key
+ * @param mixed $default
* @return mixed
*/
- public static function arrayGet(array $array, $key, $default = null)
+ public static function arrayGet(array $array, string $key, $default = null)
{
if (is_null($key)) {
return $array;
@@ -88,11 +88,11 @@ public static function arrayGet(array $array, $key, $default = null)
* Flatten a multi-dimensional associative array with dots.
* Adapted from: https://github.com/illuminate/support/blob/v5.3.23/Arr.php#L81
*
- * @param array $array
- * @param string $prepend
+ * @param array $array
+ * @param string $prepend
* @return array
*/
- public static function arrayDot(array $array, $prepend = '')
+ public static function arrayDot(array $array, string $prepend = ''): array
{
$results = [];
@@ -111,13 +111,13 @@ public static function arrayDot(array $array, $prepend = '')
* Set an item on an array or object using dot notation.
* Adapted from: https://github.com/illuminate/support/blob/v5.3.23/helpers.php#L437
*
- * @param mixed $target
- * @param string|array $key
- * @param mixed $value
- * @param bool $overwrite
+ * @param mixed $target
+ * @param string|array $key
+ * @param mixed $value
+ * @param bool $overwrite
* @return mixed
*/
- public static function arraySet(&$target, $key, $value, $overwrite = true)
+ public static function arraySet(&$target, $key, $value, $overwrite = true): array
{
$segments = is_array($key) ? $key : explode('.', $key);
@@ -158,15 +158,14 @@ public static function arraySet(&$target, $key, $value, $overwrite = true)
return $target;
}
-
/**
* Unset an item on an array or object using dot notation.
*
- * @param mixed $target
- * @param string|array $key
+ * @param mixed $target
+ * @param string|array $key
* @return mixed
*/
- public static function arrayUnset(&$target, $key)
+ public static function arrayUnset(&$target, $key): array
{
if (!is_array($target)) {
return $target;
@@ -195,7 +194,7 @@ public static function arrayUnset(&$target, $key)
* @param string $delimiter
* @return string
*/
- public static function snakeCase($value, $delimiter = '_')
+ public static function snakeCase(string $value, string $delimiter = '_'): string
{
if (! ctype_lower($value)) {
$value = preg_replace('/\s+/u', '', ucwords($value));
@@ -205,4 +204,48 @@ public static function snakeCase($value, $delimiter = '_')
return $value;
}
+ /**
+ * Join string[] to string with given $separator and $lastSeparator.
+ *
+ * @param array $pieces
+ * @param string $separator
+ * @param string|null $lastSeparator
+ * @return string
+ */
+ public static function join(array $pieces, string $separator, string $lastSeparator = null): string
+ {
+ if (is_null($lastSeparator)) {
+ $lastSeparator = $separator;
+ }
+
+ $last = array_pop($pieces);
+
+ switch (count($pieces)) {
+ case 0:
+ return $last ?: '';
+ case 1:
+ return $pieces[0] . $lastSeparator . $last;
+ default:
+ return implode($separator, $pieces) . $lastSeparator . $last;
+ }
+ }
+
+ /**
+ * Wrap string[] by given $prefix and $suffix
+ *
+ * @param array $strings
+ * @param string $prefix
+ * @param string|null $suffix
+ * @return array
+ */
+ public static function wraps(array $strings, string $prefix, string $suffix = null): array
+ {
+ if (is_null($suffix)) {
+ $suffix = $prefix;
+ }
+
+ return array_map(function ($str) use ($prefix, $suffix) {
+ return $prefix . $str . $suffix;
+ }, $strings);
+ }
}
diff --git a/src/MimeTypeGuesser.php b/src/MimeTypeGuesser.php
index 17d292a..3efe69e 100644
--- a/src/MimeTypeGuesser.php
+++ b/src/MimeTypeGuesser.php
@@ -5,6 +5,7 @@
class MimeTypeGuesser
{
+ /** @var array */
protected $mimeTypes = [
'application/andrew-inset' => 'ez',
'application/applixware' => 'aw',
@@ -778,15 +779,26 @@ class MimeTypeGuesser
'x-conference/x-cooltalk' => 'ice'
];
- public function getExtension($mimeType)
+ /**
+ * Get extension by mime type
+ *
+ * @param string $mimeType
+ * @return string|null
+ */
+ public function getExtension(string $mimeType)
{
return isset($this->mimeTypes[$mimeType])? $this->mimeTypes[$mimeType] : null;
}
- public function getMimeType($extension)
+ /**
+ * Get mime type by extension
+ *
+ * @param string $extension
+ * @return string|null
+ */
+ public function getMimeType(string $extension)
{
$key = array_search($extension, $this->mimeTypes);
return $key ?: null;
}
-
}
diff --git a/src/Rule.php b/src/Rule.php
index 9025f25..a2674ab 100644
--- a/src/Rule.php
+++ b/src/Rule.php
@@ -6,107 +6,227 @@
abstract class Rule
{
+ /** @var string */
protected $key;
+ /** @var Rakit\Validation\Attribute|null */
protected $attribute;
+ /** @var Rakit\Validation\Validation|null */
protected $validation;
+ /** @var bool */
protected $implicit = false;
+ /** @var array */
protected $params = [];
- protected $fillable_params = [];
+ /** @var array */
+ protected $paramsTexts = [];
+ /** @var array */
+ protected $fillableParams = [];
+
+ /** @var string */
protected $message = "The :attribute is invalid";
- abstract public function check($value);
+ abstract public function check($value): bool;
+ /**
+ * Set Validation class instance
+ *
+ * @param Rakit\Validation\Validation $validation
+ * @return void
+ */
public function setValidation(Validation $validation)
{
$this->validation = $validation;
}
- public function setKey($key)
+ /**
+ * Set key
+ *
+ * @param string $key
+ * @return void
+ */
+ public function setKey(string $key)
{
$this->key = $key;
}
+ /**
+ * Get key
+ *
+ * @return string
+ */
public function getKey()
{
return $this->key ?: get_class($this);
}
- public function setAttribute($attribute)
+ /**
+ * Set attribute
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @return void
+ */
+ public function setAttribute(Attribute $attribute)
{
$this->attribute = $attribute;
}
+ /**
+ * Get attribute
+ *
+ * @return Rakit\Validation\Attribute|null
+ */
public function getAttribute()
{
- return $this->attribute ?: get_class($this);
+ return $this->attribute;
}
- public function getParameters()
+ /**
+ * Get parameters
+ *
+ * @return array
+ */
+ public function getParameters(): array
{
return $this->params;
}
- public function setParameters(array $params)
+ /**
+ * Set params
+ *
+ * @param array $params
+ * @return Rakit\Validation\Rule
+ */
+ public function setParameters(array $params): Rule
{
$this->params = array_merge($this->params, $params);
return $this;
}
- public function setParameter($key, $value)
+ /**
+ * Set parameters
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return Rakit\Validation\Rule
+ */
+ public function setParameter(string $key, $value): Rule
{
$this->params[$key] = $value;
return $this;
}
- public function fillParameters(array $params)
+ /**
+ * Fill $params to $this->params
+ *
+ * @param array $params
+ * @return Rakit\Validation\Rule
+ */
+ public function fillParameters(array $params): Rule
{
- foreach($this->fillable_params as $key) {
- if (empty($params)) break;
+ foreach ($this->fillableParams as $key) {
+ if (empty($params)) {
+ break;
+ }
$this->params[$key] = array_shift($params);
}
return $this;
}
- public function parameter($key)
+ /**
+ * Get parameter from given $key, return null if it not exists
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function parameter(string $key)
{
return isset($this->params[$key])? $this->params[$key] : null;
}
- public function isImplicit()
+ /**
+ * Set parameter text that can be displayed in error message using ':param_key'
+ *
+ * @param string $key
+ * @param string $text
+ * @return void
+ */
+ public function setParameterText(string $key, string $text)
+ {
+ $this->paramsTexts[$key] = $text;
+ }
+
+ /**
+ * Get $paramsTexts
+ *
+ * @return array
+ */
+ public function getParametersTexts(): array
{
- return $this->implicit === true;
+ return $this->paramsTexts;
}
- public function message($message)
+ /**
+ * Check whether this rule is implicit
+ *
+ * @return boolean
+ */
+ public function isImplicit(): bool
+ {
+ return $this->implicit;
+ }
+
+ /**
+ * Just alias of setMessage
+ *
+ * @param string $message
+ * @return Rakit\Validation\Rule
+ */
+ public function message(string $message): Rule
{
return $this->setMessage($message);
}
- public function setMessage($message)
+ /**
+ * Set message
+ *
+ * @param string $message
+ * @return Rakit\Validation\Rule
+ */
+ public function setMessage(string $message): Rule
{
$this->message = $message;
return $this;
- }
+ }
- public function getMessage()
+ /**
+ * Get message
+ *
+ * @return string
+ */
+ public function getMessage(): string
{
return $this->message;
}
+ /**
+ * Check given $params must be exists
+ *
+ * @param array $params
+ * @return void
+ * @throws Rakit\Validation\MissingRequiredParameterException
+ */
protected function requireParameters(array $params)
{
- foreach($params as $param) {
+ foreach ($params as $param) {
if (!isset($this->params[$param])) {
$rule = $this->getKey();
throw new MissingRequiredParameterException("Missing required parameter '{$param}' on rule '{$rule}'");
}
}
}
-
-}
\ No newline at end of file
+}
diff --git a/src/Rules/Accepted.php b/src/Rules/Accepted.php
index fb9f27b..6f4655b 100644
--- a/src/Rules/Accepted.php
+++ b/src/Rules/Accepted.php
@@ -6,14 +6,21 @@
class Accepted extends Rule
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute must be accepted";
- public function check($value)
+ /**
+ * Check the $value is accepted
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$acceptables = ['yes', 'on', '1', 1, true, 'true'];
return in_array($value, $acceptables, true);
}
-
}
diff --git a/src/Rules/After.php b/src/Rules/After.php
index 8fdf8d1..cb49db6 100644
--- a/src/Rules/After.php
+++ b/src/Rules/After.php
@@ -7,18 +7,27 @@
class After extends Rule
{
- use DateUtils;
+ use Traits\DateUtilsTrait;
+ /** @var string */
protected $message = "The :attribute must be a date after :time.";
- protected $fillable_params = ['time'];
-
- public function check($value)
+ /** @var array */
+ protected $fillableParams = ['time'];
+
+ /**
+ * Check the value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ * @throws Exception
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$time = $this->parameter('time');
- if (!$this->isValidDate($value)){
+ if (!$this->isValidDate($value)) {
throw $this->throwException($value);
}
diff --git a/src/Rules/Alpha.php b/src/Rules/Alpha.php
index 225fe5d..376fbb6 100644
--- a/src/Rules/Alpha.php
+++ b/src/Rules/Alpha.php
@@ -7,11 +7,17 @@
class Alpha extends Rule
{
+ /** @var string */
protected $message = "The :attribute only allows alphabet characters";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return is_string($value) && preg_match('/^[\pL\pM]+$/u', $value);
}
-
}
diff --git a/src/Rules/AlphaDash.php b/src/Rules/AlphaDash.php
index 11c34dd..7813f5b 100644
--- a/src/Rules/AlphaDash.php
+++ b/src/Rules/AlphaDash.php
@@ -7,9 +7,16 @@
class AlphaDash extends Rule
{
+ /** @var string */
protected $message = "The :attribute only allows a-z, 0-9, _ and -";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
if (! is_string($value) && ! is_numeric($value)) {
return false;
@@ -17,5 +24,4 @@ public function check($value)
return preg_match('/^[\pL\pM\pN_-]+$/u', $value) > 0;
}
-
}
diff --git a/src/Rules/AlphaNum.php b/src/Rules/AlphaNum.php
index fba0002..7fb2b3b 100644
--- a/src/Rules/AlphaNum.php
+++ b/src/Rules/AlphaNum.php
@@ -7,9 +7,16 @@
class AlphaNum extends Rule
{
+ /** @var string */
protected $message = "The :attribute only allows alphabet and numeric";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
if (! is_string($value) && ! is_numeric($value)) {
return false;
@@ -17,5 +24,4 @@ public function check($value)
return preg_match('/^[\pL\pM\pN]+$/u', $value) > 0;
}
-
}
diff --git a/src/Rules/Before.php b/src/Rules/Before.php
index b35b09e..22cdfa5 100644
--- a/src/Rules/Before.php
+++ b/src/Rules/Before.php
@@ -6,18 +6,27 @@
class Before extends Rule
{
- use DateUtils;
+ use Traits\DateUtilsTrait;
+ /** @var string */
protected $message = "The :attribute must be a date before :time.";
- protected $fillable_params = ['time'];
-
- public function check($value)
+ /** @var array */
+ protected $fillableParams = ['time'];
+
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ * @throws Exception
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$time = $this->parameter('time');
- if (!$this->isValidDate($value)){
+ if (!$this->isValidDate($value)) {
throw $this->throwException($value);
}
diff --git a/src/Rules/Between.php b/src/Rules/Between.php
index fa4df9c..fa7de36 100644
--- a/src/Rules/Between.php
+++ b/src/Rules/Between.php
@@ -6,27 +6,33 @@
class Between extends Rule
{
+ use Traits\SizeTrait;
+ /** @var string */
protected $message = "The :attribute must be between :min and :max";
- protected $fillable_params = ['min', 'max'];
+ /** @var array */
+ protected $fillableParams = ['min', 'max'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
-
- $min = (int) $this->parameter('min');
- $max = (int) $this->parameter('max');
-
- if (is_int($value) || is_float($value)) {
- return $value >= $min AND $value <= $max;
- } elseif(is_string($value)) {
- return mb_strlen($value, 'UTF-8') >= $min AND mb_strlen($value, 'UTF-8') <= $max;
- } elseif(is_array($value)) {
- return count($value) >= $min AND count($value) <= $max;
- } else {
+ $this->requireParameters($this->fillableParams);
+
+ $min = $this->getBytesSize($this->parameter('min'));
+ $max = $this->getBytesSize($this->parameter('max'));
+
+ $valueSize = $this->getValueSize($value);
+
+ if (!is_numeric($valueSize)) {
return false;
}
- }
+ return ($valueSize >= $min && $valueSize <= $max);
+ }
}
diff --git a/src/Rules/Callback.php b/src/Rules/Callback.php
index d8e9991..bb18959 100644
--- a/src/Rules/Callback.php
+++ b/src/Rules/Callback.php
@@ -9,18 +9,33 @@
class Callback extends Rule
{
+ /** @var string */
protected $message = "The :attribute is not valid";
- protected $fillable_params = ['callback'];
+ /** @var array */
+ protected $fillableParams = ['callback'];
- public function setCallback(Closure $callback)
+ /**
+ * Set the Callback closure
+ *
+ * @param Closure $callback
+ * @return self
+ */
+ public function setCallback(Closure $callback): Rule
{
return $this->setParameter('callback', $callback);
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ * @throws Exception
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$callback = $this->parameter('callback');
if (false === $callback instanceof Closure) {
@@ -34,11 +49,10 @@ public function check($value)
if (is_string($invalidMessage)) {
$this->setMessage($invalidMessage);
return false;
- } elseif(false === $invalidMessage) {
+ } elseif (false === $invalidMessage) {
return false;
}
return true;
}
-
}
diff --git a/src/Rules/Date.php b/src/Rules/Date.php
index 73f4be5..37c5b03 100644
--- a/src/Rules/Date.php
+++ b/src/Rules/Date.php
@@ -7,20 +7,28 @@
class Date extends Rule
{
+ /** @var string */
protected $message = "The :attribute is not valid date format";
- protected $fillable_params = ['format'];
+ /** @var array */
+ protected $fillableParams = ['format'];
+ /** @var array */
protected $params = [
'format' => 'Y-m-d'
];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$format = $this->parameter('format');
return date_create_from_format($format, $value) !== false;
}
-
}
diff --git a/src/Rules/DateUtils.php b/src/Rules/DateUtils.php
deleted file mode 100644
index 659fa64..0000000
--- a/src/Rules/DateUtils.php
+++ /dev/null
@@ -1,26 +0,0 @@
-requireParameters($this->fillable_params);
-
+ $this->requireParameters($this->fillableParams);
+
$default = $this->parameter('default');
- return $default;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function modifyValue($value)
+ {
+ return $this->isEmptyValue($value) ? $this->parameter('default') : $value;
}
+ /**
+ * Check $value is empty value
+ *
+ * @param mixed $value
+ * @return boolean
+ */
+ protected function isEmptyValue($value): bool
+ {
+ $requiredValidator = new Required;
+ return false === $requiredValidator->check($value, []);
+ }
}
diff --git a/src/Rules/Different.php b/src/Rules/Different.php
index fdab36c..3577318 100644
--- a/src/Rules/Different.php
+++ b/src/Rules/Different.php
@@ -7,18 +7,25 @@
class Different extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be different with :field";
- protected $fillable_params = ['field'];
+ /** @var array */
+ protected $fillableParams = ['field'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$field = $this->parameter('field');
- $another_value = $this->validation->getValue($field);
+ $anotherValue = $this->validation->getValue($field);
- return $value != $another_value;
+ return $value != $anotherValue;
}
-
}
diff --git a/src/Rules/Digits.php b/src/Rules/Digits.php
index d578021..87a5f65 100644
--- a/src/Rules/Digits.php
+++ b/src/Rules/Digits.php
@@ -7,18 +7,25 @@
class Digits extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be numeric and must have an exact length of :length";
- protected $fillable_params = ['length'];
+ /** @var array */
+ protected $fillableParams = ['length'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$length = (int) $this->parameter('length');
return ! preg_match('/[^0-9]/', $value)
&& strlen((string) $value) == $length;
}
-
}
diff --git a/src/Rules/DigitsBetween.php b/src/Rules/DigitsBetween.php
index 4209fc6..539c09d 100644
--- a/src/Rules/DigitsBetween.php
+++ b/src/Rules/DigitsBetween.php
@@ -7,13 +7,21 @@
class DigitsBetween extends Rule
{
+ /** @var string */
protected $message = "The :attribute must have a length between the given :min and :max";
- protected $fillable_params = ['min', 'max'];
+ /** @var array */
+ protected $fillableParams = ['min', 'max'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$min = (int) $this->parameter('min');
$max = (int) $this->parameter('max');
@@ -23,5 +31,4 @@ public function check($value)
return ! preg_match('/[^0-9]/', $value)
&& $length >= $min && $length <= $max;
}
-
}
diff --git a/src/Rules/Email.php b/src/Rules/Email.php
index 7d83694..a9bd236 100644
--- a/src/Rules/Email.php
+++ b/src/Rules/Email.php
@@ -7,11 +7,17 @@
class Email extends Rule
{
+ /** @var string */
protected $message = "The :attribute is not valid email";
- public function check($value)
+ /**
+ * Check $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
}
-
}
diff --git a/src/Rules/FileTrait.php b/src/Rules/FileTrait.php
deleted file mode 100644
index d9bc3c5..0000000
--- a/src/Rules/FileTrait.php
+++ /dev/null
@@ -1,74 +0,0 @@
-isValueFromUploadedFiles($value) AND is_uploaded_file($value['tmp_name']);
- }
-
- protected function getBytes($size)
- {
- if (is_int($size)) {
- return $size;
- }
-
- if (!is_string($size)) {
- throw new InvalidArgumentException("Size must be string or integer Bytes", 1);
- }
-
- if (!preg_match("/^(?((\d+)?\.)?\d+)(?(B|K|M|G|T|P)B?)?$/i", $size, $match)) {
- throw new InvalidArgumentException("Size is not valid format", 1);
- }
-
- $number = (float)$match['number'];
- $format = isset($match['format']) ? $match['format'] : '';
-
- switch (strtoupper($format)) {
- case "KB":
- case "K":
- return $number * 1024;
-
- case "MB":
- case "M":
- return $number * pow(1024, 2);
-
- case "GB":
- case "G":
- return $number * pow(1024, 3);
-
- case "TB":
- case "T":
- return $number * pow(1024, 4);
-
- case "PB":
- case "P":
- return $number * pow(1024, 5);
-
- default:
- return $number;
- }
- }
-}
diff --git a/src/Rules/In.php b/src/Rules/In.php
index 3845edb..1971ed5 100644
--- a/src/Rules/In.php
+++ b/src/Rules/In.php
@@ -2,35 +2,60 @@
namespace Rakit\Validation\Rules;
+use Rakit\Validation\Helper;
use Rakit\Validation\Rule;
class In extends Rule
{
- protected $message = "The :attribute is not allowing :value";
+ /** @var string */
+ protected $message = "The :attribute only allows :allowed_values";
+ /** @var bool */
protected $strict = false;
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign the $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
- if (count($params) == 1 AND is_array($params[0])) {
+ if (count($params) == 1 && is_array($params[0])) {
$params = $params[0];
}
$this->params['allowed_values'] = $params;
return $this;
}
- public function strict($strict = true)
+ /**
+ * Set strict value
+ *
+ * @param bool $strict
+ * @return void
+ */
+ public function strict(bool $strict = true)
{
$this->strict = $strict;
}
- public function check($value)
+ /**
+ * Check $value is existed
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['allowed_values']);
- $allowed_values = $this->parameter('allowed_values');
- return in_array($value, $allowed_values, $this->strict);
- }
+ $allowedValues = $this->parameter('allowed_values');
+
+ $or = $this->validation ? $this->validation->getTranslation('or') : 'or';
+ $allowedValuesText = Helper::join(Helper::wraps($allowedValues, "'"), ', ', ", {$or} ");
+ $this->setParameterText('allowed_values', $allowedValuesText);
+ return in_array($value, $allowedValues, $this->strict);
+ }
}
diff --git a/src/Rules/Integer.php b/src/Rules/Integer.php
index 04ffd7c..47aa702 100644
--- a/src/Rules/Integer.php
+++ b/src/Rules/Integer.php
@@ -7,11 +7,17 @@
class Integer extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be integer";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return filter_var($value, FILTER_VALIDATE_INT) !== false;
}
-
}
diff --git a/src/Rules/Interfaces/BeforeValidate.php b/src/Rules/Interfaces/BeforeValidate.php
new file mode 100644
index 0000000..e3c058f
--- /dev/null
+++ b/src/Rules/Interfaces/BeforeValidate.php
@@ -0,0 +1,13 @@
+requireParameters($this->fillable_params);
-
- $max = (int) $this->parameter('max');
- if (is_int($value)) {
- return $value <= $max;
- } elseif(is_string($value)) {
- return mb_strlen($value, 'UTF-8') <= $max;
- } elseif(is_array($value)) {
- return count($value) <= $max;
- } else {
+ $this->requireParameters($this->fillableParams);
+
+ $max = $this->getBytesSize($this->parameter('max'));
+ $valueSize = $this->getValueSize($value);
+
+ if (!is_numeric($valueSize)) {
return false;
}
- }
+ return $valueSize <= $max;
+ }
}
diff --git a/src/Rules/Mimes.php b/src/Rules/Mimes.php
new file mode 100644
index 0000000..9abb5a8
--- /dev/null
+++ b/src/Rules/Mimes.php
@@ -0,0 +1,95 @@
+params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
+ {
+ $this->allowTypes($params);
+ return $this;
+ }
+
+ /**
+ * Given $types and assign $this->params
+ *
+ * @param mixed $types
+ * @return self
+ */
+ public function allowTypes($types): Rule
+ {
+ if (is_string($types)) {
+ $types = explode('|', $types);
+ }
+
+ $this->params['allowed_types'] = $types;
+
+ return $this;
+ }
+
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
+ {
+ $allowedTypes = $this->parameter('allowed_types');
+
+ if ($allowedTypes) {
+ $or = $this->validation ? $this->validation->getTranslation('or') : 'or';
+ $this->setParameterText('allowed_types', Helper::join(Helper::wraps($allowedTypes, "'"), ', ', ", {$or} "));
+ }
+
+ // below is Required rule job
+ if (!$this->isValueFromUploadedFiles($value) or $value['error'] == UPLOAD_ERR_NO_FILE) {
+ return true;
+ }
+
+ if (!$this->isUploadedFile($value)) {
+ return false;
+ }
+
+ // just make sure there is no error
+ if ($value['error']) {
+ return false;
+ }
+
+ if (!empty($allowedTypes)) {
+ $guesser = new MimeTypeGuesser;
+ $ext = $guesser->getExtension($value['type']);
+ unset($guesser);
+
+ if (!in_array($ext, $allowedTypes)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/Rules/Min.php b/src/Rules/Min.php
index bee43eb..555f8d9 100644
--- a/src/Rules/Min.php
+++ b/src/Rules/Min.php
@@ -6,25 +6,31 @@
class Min extends Rule
{
+ use Traits\SizeTrait;
+ /** @var string */
protected $message = "The :attribute minimum is :min";
- protected $fillable_params = ['min'];
+ /** @var array */
+ protected $fillableParams = ['min'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
-
- $min = (int) $this->parameter('min');
- if (is_int($value)) {
- return $value >= $min;
- } elseif(is_string($value)) {
- return mb_strlen($value, 'UTF-8') >= $min;
- } elseif(is_array($value)) {
- return count($value) >= $min;
- } else {
+ $this->requireParameters($this->fillableParams);
+
+ $min = $this->getBytesSize($this->parameter('min'));
+ $valueSize = $this->getValueSize($value);
+
+ if (!is_numeric($valueSize)) {
return false;
}
- }
+ return $valueSize >= $min;
+ }
}
diff --git a/src/Rules/NotIn.php b/src/Rules/NotIn.php
index 8abbb24..f70275a 100644
--- a/src/Rules/NotIn.php
+++ b/src/Rules/NotIn.php
@@ -2,34 +2,60 @@
namespace Rakit\Validation\Rules;
+use Rakit\Validation\Helper;
use Rakit\Validation\Rule;
class NotIn extends Rule
{
- protected $message = "The :attribute is not allowing :value";
+ /** @var string */
+ protected $message = "The :attribute is not allowing :disallowed_values";
+ /** @var bool */
protected $strict = false;
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign the $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
- if (count($params) == 1 AND is_array($params[0])) {
+ if (count($params) == 1 and is_array($params[0])) {
$params = $params[0];
}
$this->params['disallowed_values'] = $params;
return $this;
}
+ /**
+ * Set strict value
+ *
+ * @param bool $strict
+ * @return void
+ */
public function strict($strict = true)
{
$this->strict = $strict;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['disallowed_values']);
- $disallowed_values = (array) $this->parameter('disallowed_values');
- return !in_array($value, $disallowed_values, $this->strict);
- }
+ $disallowedValues = (array) $this->parameter('disallowed_values');
+
+ $and = $this->validation ? $this->validation->getTranslation('and') : 'and';
+ $disallowedValuesText = Helper::join(Helper::wraps($disallowedValues, "'"), ', ', ", {$and} ");
+ $this->setParameterText('disallowed_values', $disallowedValuesText);
+
+ return !in_array($value, $disallowedValues, $this->strict);
+ }
}
diff --git a/src/Rules/Numeric.php b/src/Rules/Numeric.php
index f312fb4..ddbf6bd 100644
--- a/src/Rules/Numeric.php
+++ b/src/Rules/Numeric.php
@@ -7,11 +7,17 @@
class Numeric extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be numeric";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return is_numeric($value);
}
-
}
diff --git a/src/Rules/Present.php b/src/Rules/Present.php
index 4bc6d24..9094475 100644
--- a/src/Rules/Present.php
+++ b/src/Rules/Present.php
@@ -6,13 +6,20 @@
class Present extends Rule
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute must be present";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return $this->validation->hasValue($this->attribute->getKey());
}
-
}
diff --git a/src/Rules/Regex.php b/src/Rules/Regex.php
index ab68eeb..470944c 100644
--- a/src/Rules/Regex.php
+++ b/src/Rules/Regex.php
@@ -7,15 +7,22 @@
class Regex extends Rule
{
+ /** @var string */
protected $message = "The :attribute is not valid format";
- protected $fillable_params = ['regex'];
+ /** @var array */
+ protected $fillableParams = ['regex'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$regex = $this->parameter('regex');
return preg_match($regex, $value) > 0;
}
-
}
diff --git a/src/Rules/Required.php b/src/Rules/Required.php
index 48aa1e8..e7c17b2 100644
--- a/src/Rules/Required.php
+++ b/src/Rules/Required.php
@@ -6,30 +6,46 @@
class Required extends Rule
{
- use FileTrait;
+ use Traits\FileTrait;
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->setAttributeAsRequired();
- if ($this->attribute AND $this->attribute->hasRule('uploaded_file')) {
- return $this->isValueFromUploadedFiles($value) AND $value['error'] != UPLOAD_ERR_NO_FILE;
+ if ($this->attribute and $this->attribute->hasRule('uploaded_file')) {
+ return $this->isValueFromUploadedFiles($value) and $value['error'] != UPLOAD_ERR_NO_FILE;
}
- if (is_string($value)) return mb_strlen(trim($value), 'UTF-8') > 0;
- if (is_array($value)) return count($value) > 0;
+ if (is_string($value)) {
+ return mb_strlen(trim($value), 'UTF-8') > 0;
+ }
+ if (is_array($value)) {
+ return count($value) > 0;
+ }
return !is_null($value);
}
+ /**
+ * Set attribute is required if $this->attribute is true
+ *
+ * @return void
+ */
protected function setAttributeAsRequired()
{
if ($this->attribute) {
$this->attribute->setRequired(true);
}
}
-
}
diff --git a/src/Rules/RequiredIf.php b/src/Rules/RequiredIf.php
index 586f9df..fb4eac4 100644
--- a/src/Rules/RequiredIf.php
+++ b/src/Rules/RequiredIf.php
@@ -6,18 +6,32 @@
class RequiredIf extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign the $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['field'] = array_shift($params);
$this->params['values'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['field', 'values']);
@@ -26,14 +40,13 @@ public function check($value)
$anotherValue = $this->getAttribute()->getValue($anotherAttribute);
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
if (in_array($anotherValue, $definedValues)) {
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
return true;
}
-
}
diff --git a/src/Rules/RequiredUnless.php b/src/Rules/RequiredUnless.php
index ef4cbec..dc1e3a1 100644
--- a/src/Rules/RequiredUnless.php
+++ b/src/Rules/RequiredUnless.php
@@ -6,18 +6,32 @@
class RequiredUnless extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign the $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['field'] = array_shift($params);
$this->params['values'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['field', 'values']);
@@ -26,14 +40,13 @@ public function check($value)
$anotherValue = $this->getAttribute()->getValue($anotherAttribute);
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
if (!in_array($anotherValue, $definedValues)) {
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
return true;
}
-
}
diff --git a/src/Rules/RequiredWith.php b/src/Rules/RequiredWith.php
index 78fd5ad..5fd809c 100644
--- a/src/Rules/RequiredWith.php
+++ b/src/Rules/RequiredWith.php
@@ -6,31 +6,44 @@
class RequiredWith extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['fields'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['fields']);
$fields = $this->parameter('fields');
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
- foreach($fields as $field) {
+ foreach ($fields as $field) {
if ($this->validation->hasValue($field)) {
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
}
return true;
}
-
}
diff --git a/src/Rules/RequiredWithAll.php b/src/Rules/RequiredWithAll.php
index c323311..ba7ad59 100644
--- a/src/Rules/RequiredWithAll.php
+++ b/src/Rules/RequiredWithAll.php
@@ -6,31 +6,44 @@
class RequiredWithAll extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['fields'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['fields']);
$fields = $this->parameter('fields');
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
- foreach($fields as $field) {
+ foreach ($fields as $field) {
if (!$this->validation->hasValue($field)) {
return true;
}
}
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
-
}
diff --git a/src/Rules/RequiredWithout.php b/src/Rules/RequiredWithout.php
index 17015c8..074fc0d 100644
--- a/src/Rules/RequiredWithout.php
+++ b/src/Rules/RequiredWithout.php
@@ -6,31 +6,44 @@
class RequiredWithout extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['fields'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['fields']);
$fields = $this->parameter('fields');
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
- foreach($fields as $field) {
+ foreach ($fields as $field) {
if (!$this->validation->hasValue($field)) {
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
}
return true;
}
-
}
diff --git a/src/Rules/RequiredWithoutAll.php b/src/Rules/RequiredWithoutAll.php
index 1154f96..53bac2c 100644
--- a/src/Rules/RequiredWithoutAll.php
+++ b/src/Rules/RequiredWithoutAll.php
@@ -6,31 +6,44 @@
class RequiredWithoutAll extends Required
{
+ /** @var bool */
protected $implicit = true;
+ /** @var string */
protected $message = "The :attribute is required";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->params['fields'] = $params;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$this->requireParameters(['fields']);
$fields = $this->parameter('fields');
$validator = $this->validation->getValidator();
- $required_validator = $validator('required');
+ $requiredValidator = $validator('required');
- foreach($fields as $field) {
+ foreach ($fields as $field) {
if ($this->validation->hasValue($field)) {
return true;
}
}
$this->setAttributeAsRequired();
- return $required_validator->check($value, []);
+ return $requiredValidator->check($value, []);
}
-
}
diff --git a/src/Rules/Same.php b/src/Rules/Same.php
index 508071b..b127b55 100644
--- a/src/Rules/Same.php
+++ b/src/Rules/Same.php
@@ -7,18 +7,25 @@
class Same extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be same with :field";
- protected $fillable_params = ['field'];
+ /** @var array */
+ protected $fillableParams = ['field'];
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- $this->requireParameters($this->fillable_params);
+ $this->requireParameters($this->fillableParams);
$field = $this->parameter('field');
$anotherValue = $this->getAttribute()->getValue($field);
return $value == $anotherValue;
}
-
}
diff --git a/src/Rules/Traits/DateUtilsTrait.php b/src/Rules/Traits/DateUtilsTrait.php
new file mode 100644
index 0000000..af33d71
--- /dev/null
+++ b/src/Rules/Traits/DateUtilsTrait.php
@@ -0,0 +1,43 @@
+isValueFromUploadedFiles($value) && is_uploaded_file($value['tmp_name']);
+ }
+
+ /**
+ * Resolve uploaded file value
+ *
+ * @param mixed $value
+ * @return array|null
+ */
+ public function resolveUploadedFileValue($value)
+ {
+ if (!$this->isValueFromUploadedFiles($value)) {
+ return null;
+ }
+
+ // Here $value should be an array:
+ // [
+ // 'name' => string|array,
+ // 'type' => string|array,
+ // 'size' => int|array,
+ // 'tmp_name' => string|array,
+ // 'error' => string|array,
+ // ]
+
+ // Flatten $value to it's array dot format,
+ // so our array must be something like:
+ // ['name' => string, 'type' => string, 'size' => int, ...]
+ // or for multiple values:
+ // ['name.0' => string, 'name.1' => string, 'type.0' => string, 'type.1' => string, ...]
+ // or for nested array:
+ // ['name.foo.bar' => string, 'name.foo.baz' => string, 'type.foo.bar' => string, 'type.foo.baz' => string, ...]
+ $arrayDots = Helper::arrayDot($value);
+
+ $results = [];
+ foreach ($arrayDots as $key => $val) {
+ // Move first key to last key
+ // name.foo.bar -> foo.bar.name
+ $splits = explode(".", $key);
+ $firstKey = array_shift($splits);
+ $key = count($splits) ? implode(".", $splits) . ".{$firstKey}" : $firstKey;
+
+ Helper::arraySet($results, $key, $val);
+ }
+ return $results;
+ }
+}
diff --git a/src/Rules/Traits/SizeTrait.php b/src/Rules/Traits/SizeTrait.php
new file mode 100644
index 0000000..8d4fab9
--- /dev/null
+++ b/src/Rules/Traits/SizeTrait.php
@@ -0,0 +1,102 @@
+isUploadedFileValue($value)) {
+ return (float) $value['size'];
+ } elseif (is_array($value)) {
+ return (float) count($value);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Given $size and get the bytes
+ *
+ * @param string|int $size
+ * @return float
+ * @throws InvalidArgumentException
+ */
+ protected function getBytesSize($size)
+ {
+ if (is_numeric($size)) {
+ return (float) $size;
+ }
+
+ if (!is_string($size)) {
+ throw new InvalidArgumentException("Size must be string or numeric Bytes", 1);
+ }
+
+ if (!preg_match("/^(?((\d+)?\.)?\d+)(?(B|K|M|G|T|P)B?)?$/i", $size, $match)) {
+ throw new InvalidArgumentException("Size is not valid format", 1);
+ }
+
+ $number = (float) $match['number'];
+ $format = isset($match['format']) ? $match['format'] : '';
+
+ switch (strtoupper($format)) {
+ case "KB":
+ case "K":
+ return $number * 1024;
+
+ case "MB":
+ case "M":
+ return $number * pow(1024, 2);
+
+ case "GB":
+ case "G":
+ return $number * pow(1024, 3);
+
+ case "TB":
+ case "T":
+ return $number * pow(1024, 4);
+
+ case "PB":
+ case "P":
+ return $number * pow(1024, 5);
+
+ default:
+ return $number;
+ }
+ }
+
+ /**
+ * Check whether value is from $_FILES
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function isUploadedFileValue($value): bool
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ $keys = ['name', 'type', 'tmp_name', 'size', 'error'];
+ foreach ($keys as $key) {
+ if (!array_key_exists($key, $value)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/Rules/TypeArray.php b/src/Rules/TypeArray.php
index d706df9..311e5cc 100644
--- a/src/Rules/TypeArray.php
+++ b/src/Rules/TypeArray.php
@@ -7,11 +7,17 @@
class TypeArray extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be array";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
return is_array($value);
}
-
}
diff --git a/src/Rules/UploadedFile.php b/src/Rules/UploadedFile.php
index 7b016f5..ce5830e 100644
--- a/src/Rules/UploadedFile.php
+++ b/src/Rules/UploadedFile.php
@@ -2,20 +2,34 @@
namespace Rakit\Validation\Rules;
-use Rakit\Validation\Rule;
+use Rakit\Validation\Helper;
use Rakit\Validation\MimeTypeGuesser;
+use Rakit\Validation\Rule;
+use Rakit\Validation\Rules\Interfaces\BeforeValidate;
-class UploadedFile extends Rule
+class UploadedFile extends Rule implements BeforeValidate
{
- use FileTrait;
+ use Traits\FileTrait, Traits\SizeTrait;
- protected $message = "The :attribute is not valid";
+ /** @var string */
+ protected $message = "The :attribute is not valid uploaded file";
+ /** @var string|int */
protected $maxSize = null;
+
+ /** @var string|int */
protected $minSize = null;
+
+ /** @var array */
protected $allowedTypes = [];
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
$this->minSize(array_shift($params));
$this->maxSize(array_shift($params));
@@ -24,19 +38,38 @@ public function fillParameters(array $params)
return $this;
}
- public function maxSize($size)
+ /**
+ * Given $size and set the max size
+ *
+ * @param string|int $size
+ * @return self
+ */
+ public function maxSize($size): Rule
{
$this->params['max_size'] = $size;
return $this;
}
- public function minSize($size)
+ /**
+ * Given $size and set the min size
+ *
+ * @param string|int $size
+ * @return self
+ */
+ public function minSize($size): Rule
{
$this->params['min_size'] = $size;
return $this;
}
- public function sizeBetween($min, $max)
+ /**
+ * Given $min and $max then set the range size
+ *
+ * @param string|int $min
+ * @param string|int $max
+ * @return self
+ */
+ public function sizeBetween($min, $max): Rule
{
$this->minSize($min);
$this->maxSize($max);
@@ -44,7 +77,13 @@ public function sizeBetween($min, $max)
return $this;
}
- public function fileTypes($types)
+ /**
+ * Given $types and assign $this->params
+ *
+ * @param mixed $types
+ * @return self
+ */
+ public function fileTypes($types): Rule
{
if (is_string($types)) {
$types = explode('|', $types);
@@ -55,14 +94,52 @@ public function fileTypes($types)
return $this;
}
- public function check($value)
- {
+ /**
+ * {@inheritDoc}
+ */
+ public function beforeValidate()
+ {
+ $attribute = $this->getAttribute();
+
+ // We only resolve uploaded file value
+ // from complex attribute such as 'files.photo', 'images.*', 'images.foo.bar', etc.
+ if (!$attribute->isUsingDotNotation()) {
+ return;
+ }
+
+ $keys = explode(".", $attribute->getKey());
+ $firstKey = array_shift($keys);
+ $firstKeyValue = $this->validation->getValue($firstKey);
+
+ $resolvedValue = $this->resolveUploadedFileValue($firstKeyValue);
+
+ // Return original value if $value can't be resolved as uploaded file value
+ if (!$resolvedValue) {
+ return;
+ }
+
+ $this->validation->setValue($firstKey, $resolvedValue);
+ }
+
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
+ {
$minSize = $this->parameter('min_size');
$maxSize = $this->parameter('max_size');
$allowedTypes = $this->parameter('allowed_types');
+ if ($allowedTypes) {
+ $or = $this->validation ? $this->validation->getTranslation('or') : 'or';
+ $this->setParameterText('allowed_types', Helper::join(Helper::wraps($allowedTypes, "'"), ', ', ", {$or} "));
+ }
+
// below is Required rule job
- if (!$this->isValueFromUploadedFiles($value) OR $value['error'] == UPLOAD_ERR_NO_FILE) {
+ if (!$this->isValueFromUploadedFiles($value) or $value['error'] == UPLOAD_ERR_NO_FILE) {
return true;
}
@@ -71,18 +148,22 @@ public function check($value)
}
// just make sure there is no error
- if ($value['error']) return false;
+ if ($value['error']) {
+ return false;
+ }
if ($minSize) {
- $bytesMinSize = $this->getBytes($minSize);
+ $bytesMinSize = $this->getBytesSize($minSize);
if ($value['size'] < $bytesMinSize) {
+ $this->setMessage('The :attribute file is too small, minimum size is :min_size');
return false;
}
}
if ($maxSize) {
- $bytesMaxSize = $this->getBytes($maxSize);
+ $bytesMaxSize = $this->getBytesSize($maxSize);
if ($value['size'] > $bytesMaxSize) {
+ $this->setMessage('The :attribute file is too large, maximum size is :max_size');
return false;
}
}
@@ -93,6 +174,7 @@ public function check($value)
unset($guesser);
if (!in_array($ext, $allowedTypes)) {
+ $this->setMessage('The :attribute file type must be :allowed_types');
return false;
}
}
diff --git a/src/Rules/Uppercase.php b/src/Rules/Uppercase.php
index 641e681..11300dd 100644
--- a/src/Rules/Uppercase.php
+++ b/src/Rules/Uppercase.php
@@ -7,11 +7,17 @@
class Uppercase extends Rule
{
+ /** @var string */
protected $message = "The :attribute must be uppercase";
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
- return mb_strtoupper($value, mb_detect_encoding($value)) === $value;
+ return mb_strtoupper($value, mb_detect_encoding($value)) === $value;
}
-
}
diff --git a/src/Rules/Url.php b/src/Rules/Url.php
index c1549e8..3ed8583 100644
--- a/src/Rules/Url.php
+++ b/src/Rules/Url.php
@@ -7,23 +7,42 @@
class Url extends Rule
{
+ /** @var string */
protected $message = "The :attribute is not valid url";
- public function fillParameters(array $params)
+ /**
+ * Given $params and assign $this->params
+ *
+ * @param array $params
+ * @return self
+ */
+ public function fillParameters(array $params): Rule
{
- if (count($params) == 1 AND is_array($params[0])) {
+ if (count($params) == 1 and is_array($params[0])) {
$params = $params[0];
}
return $this->forScheme($params);
}
- public function forScheme($schemes)
+ /**
+ * Given $schemes and assign $this->params
+ *
+ * @param array $schemes
+ * @return self
+ */
+ public function forScheme($schemes): Rule
{
$this->params['schemes'] = (array) $schemes;
return $this;
}
- public function check($value)
+ /**
+ * Check the $value is valid
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function check($value): bool
{
$schemes = $this->parameter('schemes');
@@ -36,7 +55,7 @@ public function check($value)
if ($this->{$method}($value)) {
return true;
}
- } elseif($this->validateCommonScheme($value, $scheme)) {
+ } elseif ($this->validateCommonScheme($value, $scheme)) {
return true;
}
}
@@ -45,12 +64,25 @@ public function check($value)
}
}
- public function validateBasic($value)
+ /**
+ * Validate $value is valid URL format
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function validateBasic($value): bool
{
return filter_var($value, FILTER_VALIDATE_URL) !== false;
}
- public function validateCommonScheme($value, $scheme = null)
+ /**
+ * Validate $value is correct $scheme format
+ *
+ * @param mixed $value
+ * @param null $scheme
+ * @return bool
+ */
+ public function validateCommonScheme($value, $scheme = null): bool
{
if (!$scheme) {
return $this->validateBasic($value) && (bool) preg_match("/^\w+:\/\//i", $value);
@@ -59,14 +91,25 @@ public function validateCommonScheme($value, $scheme = null)
}
}
- public function validateMailtoScheme($value)
+ /**
+ * Validate the $value is mailto scheme format
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function validateMailtoScheme($value): bool
{
return $this->validateBasic($value) && preg_match("/^mailto:/", $value);
}
- public function validateJdbcScheme($value)
+ /**
+ * Validate the $value is jdbc scheme format
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function validateJdbcScheme($value): bool
{
return (bool) preg_match("/^jdbc:\w+:\/\//", $value);
}
-
}
diff --git a/src/Traits/MessagesTrait.php b/src/Traits/MessagesTrait.php
new file mode 100644
index 0000000..14ed28e
--- /dev/null
+++ b/src/Traits/MessagesTrait.php
@@ -0,0 +1,54 @@
+messages[$key] = $message;
+ }
+
+ /**
+ * Given $messages and set multiple messages
+ *
+ * @param array $messages
+ * @return void
+ */
+ public function setMessages(array $messages)
+ {
+ $this->messages = array_merge($this->messages, $messages);
+ }
+
+ /**
+ * Given message from given $key
+ *
+ * @param string $key
+ * @return string
+ */
+ public function getMessage(string $key): string
+ {
+ return array_key_exists($key, $this->messages) ? $this->messages[$key] : $key;
+ }
+
+ /**
+ * Get all $messages
+ *
+ * @return array
+ */
+ public function getMessages(): array
+ {
+ return $this->messages;
+ }
+}
diff --git a/src/Traits/TranslationsTrait.php b/src/Traits/TranslationsTrait.php
new file mode 100644
index 0000000..db935e7
--- /dev/null
+++ b/src/Traits/TranslationsTrait.php
@@ -0,0 +1,54 @@
+translations[$key] = $translation;
+ }
+
+ /**
+ * Given $translations and set multiple translations
+ *
+ * @param array $translations
+ * @return void
+ */
+ public function setTranslations(array $translations)
+ {
+ $this->translations = array_merge($this->translations, $translations);
+ }
+
+ /**
+ * Given translation from given $key
+ *
+ * @param string $key
+ * @return string
+ */
+ public function getTranslation(string $key): string
+ {
+ return array_key_exists($key, $this->translations) ? $this->translations[$key] : $key;
+ }
+
+ /**
+ * Get all $translations
+ *
+ * @return array
+ */
+ public function getTranslations(): array
+ {
+ return $this->translations;
+ }
+}
diff --git a/src/Validation.php b/src/Validation.php
index 51cb4f5..601ec69 100644
--- a/src/Validation.php
+++ b/src/Validation.php
@@ -2,70 +2,131 @@
namespace Rakit\Validation;
-use Rakit\Validation\Rules\Required;
use Closure;
-use Rakit\Validation\Rules\Defaults;
+use Rakit\Validation\Rules\Interfaces\BeforeValidate;
+use Rakit\Validation\Rules\Interfaces\ModifyValue;
+use Rakit\Validation\Rules\Required;
class Validation
{
+ use Traits\TranslationsTrait, Traits\MessagesTrait;
+ /** @var mixed */
protected $validator;
+ /** @var array */
protected $inputs = [];
+ /** @var array */
protected $attributes = [];
- protected $messages = [];
-
+ /** @var array */
protected $aliases = [];
+ /** @var string */
protected $messageSeparator = ':';
+ /** @var array */
protected $validData = [];
+
+ /** @var array */
protected $invalidData = [];
- public function __construct(Validator $validator, array $inputs, array $rules, array $messages = array())
- {
+ /**
+ * Constructor
+ *
+ * @param Rakit\Validation\Validator $validator
+ * @param array $inputs
+ * @param array $rules
+ * @param array $messages
+ * @return void
+ */
+ public function __construct(
+ Validator $validator,
+ array $inputs,
+ array $rules,
+ array $messages = []
+ ) {
$this->validator = $validator;
$this->inputs = $this->resolveInputAttributes($inputs);
$this->messages = $messages;
$this->errors = new ErrorBag;
- foreach($rules as $attributeKey => $rules) {
+ foreach ($rules as $attributeKey => $rules) {
$this->addAttribute($attributeKey, $rules);
}
}
- public function addAttribute($attributeKey, $rules)
+ /**
+ * Add attribute rules
+ *
+ * @param string $attributeKey
+ * @param string|array $rules
+ * @return void
+ */
+ public function addAttribute(string $attributeKey, $rules)
{
- $resolved_rules = $this->resolveRules($rules);
- $attribute = new Attribute($this, $attributeKey, $this->getAlias($attributeKey), $resolved_rules);
+ $resolvedRules = $this->resolveRules($rules);
+ $attribute = new Attribute($this, $attributeKey, $this->getAlias($attributeKey), $resolvedRules);
$this->attributes[$attributeKey] = $attribute;
}
- public function getAttribute($attributeKey)
+ /**
+ * Get attribute by key
+ *
+ * @param string $attributeKey
+ * @return null|Rakit\Validation\Attribute
+ */
+ public function getAttribute(string $attributeKey)
{
return isset($this->attributes[$attributeKey])? $this->attributes[$attributeKey] : null;
}
- public function validate(array $inputs = array())
+ /**
+ * Run validation
+ *
+ * @param array $inputs
+ * @return void
+ */
+ public function validate(array $inputs = [])
{
$this->errors = new ErrorBag; // reset error bag
$this->inputs = array_merge($this->inputs, $this->resolveInputAttributes($inputs));
- foreach($this->attributes as $attributeKey => $attribute) {
+
+ // Before validation hooks
+ foreach ($this->attributes as $attributeKey => $attribute) {
+ foreach ($attribute->getRules() as $rule) {
+ if ($rule instanceof BeforeValidate) {
+ $rule->beforeValidate();
+ }
+ }
+ }
+
+ foreach ($this->attributes as $attributeKey => $attribute) {
$this->validateAttribute($attribute);
}
}
- public function errors()
+ /**
+ * Get ErrorBag instance
+ *
+ * @return Rakit\Validation\ErrorBag
+ */
+ public function errors(): ErrorBag
{
return $this->errors;
}
+ /**
+ * Validate attribute
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @return void
+ */
protected function validateAttribute(Attribute $attribute)
{
if ($this->isArrayAttribute($attribute)) {
$attributes = $this->parseArrayAttribute($attribute);
- foreach($attributes as $i => $attr) {
+ foreach ($attributes as $i => $attr) {
$this->validateAttribute($attr);
}
return;
@@ -78,18 +139,17 @@ protected function validateAttribute(Attribute $attribute)
$isEmptyValue = $this->isEmptyValue($value);
$isValid = true;
- foreach($rules as $ruleValidator) {
+ foreach ($rules as $ruleValidator) {
$ruleValidator->setAttribute($attribute);
- if ($isEmptyValue && $ruleValidator instanceof Defaults) {
- $value = $ruleValidator->check(null);
+ if ($ruleValidator instanceof ModifyValue) {
+ $value = $ruleValidator->modifyValue($value);
$isEmptyValue = $this->isEmptyValue($value);
- continue;
}
$valid = $ruleValidator->check($value);
- if ($isEmptyValue AND $this->ruleIsOptional($attribute, $ruleValidator)) {
+ if ($isEmptyValue and $this->ruleIsOptional($attribute, $ruleValidator)) {
continue;
}
@@ -109,13 +169,25 @@ protected function validateAttribute(Attribute $attribute)
}
}
- protected function isArrayAttribute(Attribute $attribute)
+ /**
+ * Check whether given $attribute is array attribute
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @return bool
+ */
+ protected function isArrayAttribute(Attribute $attribute): bool
{
$key = $attribute->getKey();
return strpos($key, '*') !== false;
}
- protected function parseArrayAttribute(Attribute $attribute)
+ /**
+ * Parse array attribute into it's child attributes
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @return array
+ */
+ protected function parseArrayAttribute(Attribute $attribute): array
{
$attributeKey = $attribute->getKey();
$data = Helper::arrayDot($this->initializeAttributeOnData($attributeKey));
@@ -123,7 +195,8 @@ protected function parseArrayAttribute(Attribute $attribute)
$pattern = str_replace('\*', '([^\.]+)', preg_quote($attributeKey));
$data = array_merge($data, $this->extractValuesForWildcards(
- $data, $attributeKey
+ $data,
+ $attributeKey
));
$attributes = [];
@@ -154,7 +227,7 @@ protected function parseArrayAttribute(Attribute $attribute)
* @param string $attribute
* @return array
*/
- protected function initializeAttributeOnData($attributeKey)
+ protected function initializeAttributeOnData(string $attributeKey): array
{
$explicitPath = $this->getLeadingExplicitAttributePath($attributeKey);
@@ -177,7 +250,7 @@ protected function initializeAttributeOnData($attributeKey)
* @param string $attributeKey
* @return array
*/
- public function extractValuesForWildcards($data, $attributeKey)
+ public function extractValuesForWildcards(array $data, string $attributeKey): array
{
$keys = [];
@@ -211,7 +284,7 @@ public function extractValuesForWildcards($data, $attributeKey)
* @param string $attributeKey
* @return string
*/
- protected function getLeadingExplicitAttributePath($attributeKey)
+ protected function getLeadingExplicitAttributePath(string $attributeKey): string
{
return rtrim(explode('*', $attributeKey)[0], '.') ?: null;
}
@@ -225,7 +298,7 @@ protected function getLeadingExplicitAttributePath($attributeKey)
* @param string $attributeKey
* @return array
*/
- protected function extractDataFromPath($attributeKey)
+ protected function extractDataFromPath(string $attributeKey): array
{
$results = [];
@@ -238,6 +311,14 @@ protected function extractDataFromPath($attributeKey)
return $results;
}
+ /**
+ * Add error to the $this->errors
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @param mixed $value
+ * @param Rakit\Validation\Rule $ruleValidator
+ * @return void
+ */
protected function addError(Attribute $attribute, $value, Rule $ruleValidator)
{
$ruleName = $ruleValidator->getKey();
@@ -246,42 +327,69 @@ protected function addError(Attribute $attribute, $value, Rule $ruleValidator)
$this->errors->add($attribute->getKey(), $ruleName, $message);
}
- protected function isEmptyValue($value)
+ /**
+ * Check $value is empty value
+ *
+ * @param mixed $value
+ * @return boolean
+ */
+ protected function isEmptyValue($value): bool
{
$requiredValidator = new Required;
return false === $requiredValidator->check($value, []);
}
- protected function ruleIsOptional(Attribute $attribute, Rule $rule)
+ /**
+ * Check the rule is optional
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @param Rakit\Validation\Rule $rule
+ * @return bool
+ */
+ protected function ruleIsOptional(Attribute $attribute, Rule $rule): bool
{
- return false === $attribute->isRequired() AND
- false === $rule->isImplicit() AND
+ return false === $attribute->isRequired() and
+ false === $rule->isImplicit() and
false === $rule instanceof Required;
}
- protected function resolveAttributeName(Attribute $attribute)
+ /**
+ * Resolve attribute name
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @return string
+ */
+ protected function resolveAttributeName(Attribute $attribute): string
{
$primaryAttribute = $attribute->getPrimaryAttribute();
if (isset($this->aliases[$attribute->getKey()])) {
return $this->aliases[$attribute->getKey()];
- } elseif($primaryAttribute AND isset($this->aliases[$primaryAttribute->getKey()])) {
+ } elseif ($primaryAttribute and isset($this->aliases[$primaryAttribute->getKey()])) {
return $this->aliases[$primaryAttribute->getKey()];
- } elseif ($this->validator->getUseHumanizedKeys()) {
+ } elseif ($this->validator->isUsingHumanizedKey()) {
return $attribute->getHumanizedKey();
} else {
return $attribute->getKey();
}
}
- protected function resolveMessage(Attribute $attribute, $value, Rule $validator)
+ /**
+ * Resolve message
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @param mixed $value
+ * @param Rakit\Validation\Rule $validator
+ * @return mixed
+ */
+ protected function resolveMessage(Attribute $attribute, $value, Rule $validator): string
{
$primaryAttribute = $attribute->getPrimaryAttribute();
- $params = $validator->getParameters();
+ $params = array_merge($validator->getParameters(), $validator->getParametersTexts());
$attributeKey = $attribute->getKey();
$ruleKey = $validator->getKey();
$alias = $attribute->getAlias() ?: $this->resolveAttributeName($attribute);
$message = $validator->getMessage(); // default rule message
- $message_keys = [
+ $messageKeys = [
$attributeKey.$this->messageSeparator.$ruleKey,
$attributeKey,
$ruleKey
@@ -289,7 +397,7 @@ protected function resolveMessage(Attribute $attribute, $value, Rule $validator)
if ($primaryAttribute) {
// insert primaryAttribute keys
- // $message_keys = [
+ // $messageKeys = [
// $attributeKey.$this->messageSeparator.$ruleKey,
// >> here [1] <<
// $attributeKey,
@@ -297,11 +405,11 @@ protected function resolveMessage(Attribute $attribute, $value, Rule $validator)
// $ruleKey
// ];
$primaryAttributeKey = $primaryAttribute->getKey();
- array_splice($message_keys, 1, 0, $primaryAttributeKey.$this->messageSeparator.$ruleKey);
- array_splice($message_keys, 3, 0, $primaryAttributeKey);
+ array_splice($messageKeys, 1, 0, $primaryAttributeKey.$this->messageSeparator.$ruleKey);
+ array_splice($messageKeys, 3, 0, $primaryAttributeKey);
}
- foreach($message_keys as $key) {
+ foreach ($messageKeys as $key) {
if (isset($this->messages[$key])) {
$message = $this->messages[$key];
break;
@@ -314,7 +422,7 @@ protected function resolveMessage(Attribute $attribute, $value, Rule $validator)
'value' => $value,
]);
- foreach($vars as $key => $value) {
+ foreach ($vars as $key => $value) {
$value = $this->stringify($value);
$message = str_replace(':'.$key, $value, $message);
}
@@ -336,49 +444,70 @@ protected function resolveMessage(Attribute $attribute, $value, Rule $validator)
return $message;
}
- protected function stringify($value)
+ /**
+ * Stringify $value
+ *
+ * @param mixed $value
+ * @return string
+ */
+ protected function stringify($value): string
{
if (is_string($value) || is_numeric($value)) {
return $value;
- } elseif(is_array($value) || is_object($value)) {
+ } elseif (is_array($value) || is_object($value)) {
return json_encode($value);
} else {
return '';
}
}
- protected function resolveRules($rules)
+ /**
+ * Resolve $rules
+ *
+ * @param mixed $rules
+ * @return array
+ */
+ protected function resolveRules($rules): array
{
if (is_string($rules)) {
$rules = explode('|', $rules);
}
- $resolved_rules = [];
+ $resolvedRules = [];
$validatorFactory = $this->getValidator();
- foreach($rules as $i => $rule) {
- if (empty($rule)) continue;
+ foreach ($rules as $i => $rule) {
+ if (empty($rule)) {
+ continue;
+ }
$params = [];
if (is_string($rule)) {
list($rulename, $params) = $this->parseRule($rule);
$validator = call_user_func_array($validatorFactory, array_merge([$rulename], $params));
- } elseif($rule instanceof Rule) {
+ } elseif ($rule instanceof Rule) {
$validator = $rule;
- } elseif($rule instanceof Closure) {
+ } elseif ($rule instanceof Closure) {
$validator = call_user_func_array($validatorFactory, ['callback', $rule]);
} else {
$ruleName = is_object($rule) ? get_class($rule) : gettype($rule);
- throw new \Exception("Rule must be a string, closure or Rakit\Validation\Rule instance. ".$ruleName." given");
+ $message = "Rule must be a string, Closure or '".Rule::class."' instance. ".$ruleName." given";
+ throw new \Exception();
}
- $resolved_rules[] = $validator;
+ $resolvedRules[] = $validator;
}
- return $resolved_rules;
+ return $resolvedRules;
}
- protected function parseRule($rule)
+ /**
+ * Parse $rule
+ *
+ * @param string $rule
+ * @return array
+ */
+ protected function parseRule(string $rule): array
{
$exp = explode(':', $rule, 2);
$rulename = $exp[0];
@@ -391,60 +520,114 @@ protected function parseRule($rule)
return [$rulename, $params];
}
- public function setMessage($key, $message)
- {
- $this->messages[$key] = $message;
- }
-
- public function setMessages(array $messages)
- {
- $this->messages = array_merge($this->messages, $messages);
- }
-
- public function setAlias($attributeKey, $alias)
+ /**
+ * Given $attributeKey and $alias then assign alias
+ *
+ * @param mixed $attributeKey
+ * @param mixed $alias
+ * @return void
+ */
+ public function setAlias(string $attributeKey, string $alias)
{
$this->aliases[$attributeKey] = $alias;
}
- public function getAlias($attributeKey)
+ /**
+ * Get attribute alias from given key
+ *
+ * @param mixed $attributeKey
+ * @return string|null
+ */
+ public function getAlias(string $attributeKey)
{
return isset($this->aliases[$attributeKey])? $this->aliases[$attributeKey] : null;
}
- public function setAliases($aliases)
+ /**
+ * Set attributes aliases
+ *
+ * @param array $aliases
+ * @return void
+ */
+ public function setAliases(array $aliases)
{
$this->aliases = array_merge($this->aliases, $aliases);
}
- public function passes()
+ /**
+ * Check validations are passed
+ *
+ * @return bool
+ */
+ public function passes(): bool
{
return $this->errors->count() == 0;
}
- public function fails()
+ /**
+ * Check validations are failed
+ *
+ * @return bool
+ */
+ public function fails(): bool
{
return !$this->passes();
}
- public function getValue($key)
+ /**
+ * Given $key and get value
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function getValue(string $key)
{
return Helper::arrayGet($this->inputs, $key);
}
- public function hasValue($key)
+ /**
+ * Set input value
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function setValue(string $key, $value)
+ {
+ Helper::arraySet($this->inputs, $key, $value);
+ }
+
+ /**
+ * Given $key and check value is exsited
+ *
+ * @param string $key
+ * @return boolean
+ */
+ public function hasValue(string $key): bool
{
return Helper::arrayHas($this->inputs, $key);
}
- public function getValidator()
+ /**
+ * Get Validator class instance
+ *
+ * @return Rakit\Validation\Validator
+ */
+ public function getValidator(): Validator
{
return $this->validator;
}
- protected function resolveInputAttributes(array $inputs)
+ /**
+ * Given $inputs and resolve input attributes
+ *
+ * @param array $inputs
+ * @return array
+ */
+ protected function resolveInputAttributes(array $inputs): array
{
$resolvedInputs = [];
- foreach($inputs as $key => $rules) {
+ foreach ($inputs as $key => $rules) {
$exp = explode(':', $key);
if (count($exp) > 1) {
@@ -458,10 +641,23 @@ protected function resolveInputAttributes(array $inputs)
return $resolvedInputs;
}
- public function getValidatedData() {
+ /**
+ * Get validated data
+ *
+ * @return array
+ */
+ public function getValidatedData(): array
+ {
return array_merge($this->validData, $this->invalidData);
}
+ /**
+ * Set valid data
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @param mixed $value
+ * @return void
+ */
protected function setValidData(Attribute $attribute, $value)
{
$key = $attribute->getKey();
@@ -473,11 +669,23 @@ protected function setValidData(Attribute $attribute, $value)
}
}
- public function getValidData()
+ /**
+ * Get valid data
+ *
+ * @return array
+ */
+ public function getValidData(): array
{
return $this->validData;
}
+ /**
+ * Set invalid data
+ *
+ * @param Rakit\Validation\Attribute $attribute
+ * @param mixed $value
+ * @return void
+ */
protected function setInvalidData(Attribute $attribute, $value)
{
$key = $attribute->getKey();
@@ -489,9 +697,13 @@ protected function setInvalidData(Attribute $attribute, $value)
}
}
- public function getInvalidData()
+ /**
+ * Get invalid data
+ *
+ * @return void
+ */
+ public function getInvalidData(): array
{
return $this->invalidData;
}
-
}
diff --git a/src/Validator.php b/src/Validator.php
index cbd9a19..943952b 100644
--- a/src/Validator.php
+++ b/src/Validator.php
@@ -4,56 +4,96 @@
class Validator
{
+ use Traits\TranslationsTrait, Traits\MessagesTrait;
- protected $messages = [];
+ /** @var translations */
+ protected $translations = [];
+ /** @var array */
protected $validators = [];
+ /** @var bool */
protected $allowRuleOverride = false;
+ /** @var bool */
protected $useHumanizedKeys = true;
+ /**
+ * Constructor
+ *
+ * @param array $messages
+ * @return void
+ */
public function __construct(array $messages = [])
{
$this->messages = $messages;
$this->registerBaseValidators();
}
- public function setMessage($key, $message)
- {
- return $this->messages[$key] = $message;
- }
-
- public function setMessages($messages)
- {
- $this->messages = array_merge($this->messages, $messages);
- }
-
- public function setValidator($key, Rule $rule)
+ /**
+ * Register or override existing validator
+ *
+ * @param mixed $key
+ * @param Rakit\Validation\Rule $rule
+ * @return void
+ */
+ public function setValidator(string $key, Rule $rule)
{
$this->validators[$key] = $rule;
$rule->setKey($key);
}
+ /**
+ * Get validator object from given $key
+ *
+ * @param mixed $key
+ * @return mixed
+ */
public function getValidator($key)
{
return isset($this->validators[$key])? $this->validators[$key] : null;
}
- public function validate(array $inputs, array $rules, array $messages = array())
+ /**
+ * Validate $inputs
+ *
+ * @param array $inputs
+ * @param array $rules
+ * @param array $messages
+ * @return Validation
+ */
+ public function validate(array $inputs, array $rules, array $messages = []): Validation
{
$validation = $this->make($inputs, $rules, $messages);
$validation->validate();
return $validation;
}
- public function make(array $inputs, array $rules, array $messages = array())
+ /**
+ * Given $inputs, $rules and $messages to make the Validation class instance
+ *
+ * @param array $inputs
+ * @param array $rules
+ * @param array $messages
+ * @return Validation
+ */
+ public function make(array $inputs, array $rules, array $messages = []): Validation
{
$messages = array_merge($this->messages, $messages);
- return new Validation($this, $inputs, $rules, $messages);
+ $validation = new Validation($this, $inputs, $rules, $messages);
+ $validation->setTranslations($this->getTranslations());
+
+ return $validation;
}
- public function __invoke($rule)
+ /**
+ * Magic invoke method to make Rule instance
+ *
+ * @param string $rule
+ * @return Rule
+ * @throws RuleNotFoundException
+ */
+ public function __invoke(string $rule): Rule
{
$args = func_get_args();
$rule = array_shift($args);
@@ -69,6 +109,11 @@ public function __invoke($rule)
return $clonedValidator;
}
+ /**
+ * Initialize base validators array
+ *
+ * @return void
+ */
protected function registerBaseValidators()
{
$baseValidator = [
@@ -102,6 +147,7 @@ protected function registerBaseValidators()
'present' => new Rules\Present,
'different' => new Rules\Different,
'uploaded_file' => new Rules\UploadedFile,
+ 'mimes' => new Rules\Mimes,
'callback' => new Rules\Callback,
'before' => new Rules\Before,
'after' => new Rules\After,
@@ -114,12 +160,19 @@ protected function registerBaseValidators()
'default' => new Rules\Defaults, // alias of defaults
];
- foreach($baseValidator as $key => $validator) {
+ foreach ($baseValidator as $key => $validator) {
$this->setValidator($key, $validator);
}
}
- public function addValidator($ruleName, Rule $rule)
+ /**
+ * Given $ruleName and $rule to add new validator
+ *
+ * @param string $ruleName
+ * @param Rakit\Validation\Rule $rule
+ * @return void
+ */
+ public function addValidator(string $ruleName, Rule $rule)
{
if (!$this->allowRuleOverride && array_key_exists($ruleName, $this->validators)) {
throw new RuleQuashException(
@@ -130,17 +183,34 @@ public function addValidator($ruleName, Rule $rule)
$this->setValidator($ruleName, $rule);
}
- public function allowRuleOverride($status = false)
+ /**
+ * Set rule can allow to be overrided
+ *
+ * @param boolean $status
+ * @return void
+ */
+ public function allowRuleOverride(bool $status = false)
{
$this->allowRuleOverride = $status;
}
- public function setUseHumanizedKeys($useHumanizedKeys = true)
+ /**
+ * Set this can use humanize keys
+ *
+ * @param boolean $useHumanizedKeys
+ * @return void
+ */
+ public function setUseHumanizedKeys(bool $useHumanizedKeys = true)
{
$this->useHumanizedKeys = $useHumanizedKeys;
}
- public function getUseHumanizedKeys()
+ /**
+ * Get $this->useHumanizedKeys value
+ *
+ * @return void
+ */
+ public function isUsingHumanizedKey(): bool
{
return $this->useHumanizedKeys;
}
diff --git a/tests/ErrorBagTest.php b/tests/ErrorBagTest.php
index 6cb80c6..9f78c61 100644
--- a/tests/ErrorBagTest.php
+++ b/tests/ErrorBagTest.php
@@ -1,8 +1,11 @@
'1',
'unique' => '2',
],
-
+
'items.0.id_product' => [
'numeric' => '3',
'etc' => 'x'
@@ -125,7 +128,7 @@ public function testGet()
'items.0.qty' => [
'numeric' => 'a'
],
-
+
'items.1.id_product' => [
'numeric' => '4',
'etc' => 'y'
@@ -227,7 +230,7 @@ public function testAll()
$this->assertEquals($errors->all('prefix :message suffix'), [
'prefix 1 suffix',
'prefix 2 suffix',
-
+
'prefix 3 suffix',
'prefix x suffix',
'prefix a suffix',
@@ -262,14 +265,49 @@ public function testFirstOfAll()
]);
$this->assertEquals($errors->firstOfAll('prefix :message suffix'), [
- 'prefix 1 suffix',
-
- 'prefix 3 suffix',
- 'prefix a suffix',
-
- 'prefix 4 suffix',
- 'prefix b suffix',
+ 'email' => 'prefix 1 suffix',
+ 'items' => [
+ [
+ 'id_product' => 'prefix 3 suffix',
+ 'qty' => 'prefix a suffix'
+ ],
+ [
+ 'id_product' => 'prefix 4 suffix',
+ 'qty' => 'prefix b suffix'
+ ],
+ ]
]);
}
+ public function testFirstOfAllDotNotation()
+ {
+ $errors = new ErrorBag([
+ 'email' => [
+ 'email' => '1',
+ 'unique' => '2',
+ ],
+ 'items.0.id_product' => [
+ 'numeric' => '3',
+ 'etc' => 'x'
+ ],
+ 'items.0.qty' => [
+ 'numeric' => 'a'
+ ],
+ 'items.1.id_product' => [
+ 'numeric' => '4',
+ 'etc' => 'y'
+ ],
+ 'items.1.qty' => [
+ 'numeric' => 'b'
+ ]
+ ]);
+
+ $this->assertEquals($errors->firstOfAll('prefix :message suffix', true), [
+ 'email' => 'prefix 1 suffix',
+ 'items.0.id_product' => 'prefix 3 suffix',
+ 'items.0.qty' => 'prefix a suffix',
+ 'items.1.id_product' => 'prefix 4 suffix',
+ 'items.1.qty' => 'prefix b suffix',
+ ]);
+ }
}
diff --git a/tests/Fixtures/Even.php b/tests/Fixtures/Even.php
index cc0ea6d..b556695 100644
--- a/tests/Fixtures/Even.php
+++ b/tests/Fixtures/Even.php
@@ -1,18 +1,20 @@
assertEquals(Helper::join($pieces0, $separator, $lastSeparator), '');
+ $this->assertEquals(Helper::join($pieces1, $separator, $lastSeparator), '1');
+ $this->assertEquals(Helper::join($pieces2, $separator, $lastSeparator), '1, and 2');
+ $this->assertEquals(Helper::join($pieces3, $separator, $lastSeparator), '1, 2, and 3');
+ }
+
+ public function testWraps()
+ {
+ $inputs = [1, 2, 3];
+
+ $this->assertEquals(Helper::wraps($inputs, '-'), ['-1-', '-2-', '-3-']);
+ $this->assertEquals(Helper::wraps($inputs, '-', '+'), ['-1+', '-2+', '-3+']);
+ }
}
diff --git a/tests/Rules/AcceptedTest.php b/tests/Rules/AcceptedTest.php
index 3e3eb70..dbad471 100644
--- a/tests/Rules/AcceptedTest.php
+++ b/tests/Rules/AcceptedTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check(' 1'));
$this->assertFalse($this->rule->check(10));
}
-
}
diff --git a/tests/Rules/AfterTest.php b/tests/Rules/AfterTest.php
index a6dd1ed..79a06aa 100644
--- a/tests/Rules/AfterTest.php
+++ b/tests/Rules/AfterTest.php
@@ -1,7 +1,12 @@
validator = new \Rakit\Validation\Rules\After();
+ $this->validator = new After();
}
/**
diff --git a/tests/Rules/AlphaDashTest.php b/tests/Rules/AlphaDashTest.php
index c80f118..269d383 100644
--- a/tests/Rules/AlphaDashTest.php
+++ b/tests/Rules/AlphaDashTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('foo bar'));
$this->assertFalse($this->rule->check('123 bar '));
}
-
}
diff --git a/tests/Rules/AlphaNumTest.php b/tests/Rules/AlphaNumTest.php
index 91ed4dc..dbbff98 100644
--- a/tests/Rules/AlphaNumTest.php
+++ b/tests/Rules/AlphaNumTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('123 foo'));
$this->assertFalse($this->rule->check(' foo123 '));
}
-
}
diff --git a/tests/Rules/AlphaTest.php b/tests/Rules/AlphaTest.php
index cc2c8b5..11e6b4b 100644
--- a/tests/Rules/AlphaTest.php
+++ b/tests/Rules/AlphaTest.php
@@ -1,8 +1,12 @@
assertFalse($this->rule->check('foo123bar'));
$this->assertFalse($this->rule->check('foo bar'));
}
-
}
diff --git a/tests/Rules/BeforeTest.php b/tests/Rules/BeforeTest.php
index b7ddb43..3a44c3c 100644
--- a/tests/Rules/BeforeTest.php
+++ b/tests/Rules/BeforeTest.php
@@ -1,7 +1,12 @@
validator = new \Rakit\Validation\Rules\Before();
+ $this->validator = new Before();
}
/**
diff --git a/tests/Rules/BetweenTest.php b/tests/Rules/BetweenTest.php
index d50199e..7bcf5f0 100644
--- a/tests/Rules/BetweenTest.php
+++ b/tests/Rules/BetweenTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters([50, 100])->check(123.4));
}
+ public function testUploadedFileValue()
+ {
+ $mb = function ($n) {
+ return $n * 1024 * 1024;
+ };
+
+ $sampleFile = [
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => $mb(2),
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ];
+
+ $this->assertTrue($this->rule->fillParameters([$mb(2), $mb(5)])->check($sampleFile));
+ $this->assertTrue($this->rule->fillParameters(['2M', '5M'])->check($sampleFile));
+ $this->assertTrue($this->rule->fillParameters([$mb(1), $mb(2)])->check($sampleFile));
+ $this->assertTrue($this->rule->fillParameters(['1M', '2M'])->check($sampleFile));
+
+ $this->assertFalse($this->rule->fillParameters([$mb(2.1), $mb(5)])->check($sampleFile));
+ $this->assertFalse($this->rule->fillParameters(['2.1M', '5M'])->check($sampleFile));
+ $this->assertFalse($this->rule->fillParameters([$mb(1), $mb(1.9)])->check($sampleFile));
+ $this->assertFalse($this->rule->fillParameters(['1M', '1.9M'])->check($sampleFile));
+ }
}
diff --git a/tests/Rules/CallbackTest.php b/tests/Rules/CallbackTest.php
index a71f133..de36ce8 100644
--- a/tests/Rules/CallbackTest.php
+++ b/tests/Rules/CallbackTest.php
@@ -1,15 +1,18 @@
rule = new Callback;
- $this->rule->setCallback(function($value) {
- return (is_numeric($value) AND $value % 2 === 0);
+ $this->rule->setCallback(function ($value) {
+ return (is_numeric($value) and $value % 2 === 0);
});
}
@@ -26,5 +29,4 @@ public function testInvalids()
$this->assertFalse($this->rule->check('abc12'));
$this->assertFalse($this->rule->check("12abc"));
}
-
}
diff --git a/tests/Rules/DateTest.php b/tests/Rules/DateTest.php
index ca2aa73..1619e28 100644
--- a/tests/Rules/DateTest.php
+++ b/tests/Rules/DateTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check("10-10-2010"));
$this->assertFalse($this->rule->fillParameters(['Y-m-d'])->check("2010-10-10 10:10"));
}
-
}
diff --git a/tests/Rules/DefaultsTest.php b/tests/Rules/DefaultsTest.php
index 0bbde29..e3b637c 100644
--- a/tests/Rules/DefaultsTest.php
+++ b/tests/Rules/DefaultsTest.php
@@ -1,10 +1,12 @@
rule = new Defaults;
@@ -12,9 +14,9 @@ public function setUp()
public function testDefaults()
{
- $this->assertEquals($this->rule->fillParameters([10])->check(null), 10);
- $this->assertEquals($this->rule->fillParameters(['something'])->check(null), 'something');
- $this->assertEquals($this->rule->fillParameters([[1,2,3]])->check('anything'), [1,2,3]);
+ $this->assertTrue($this->rule->fillParameters([10])->check(0));
+ $this->assertTrue($this->rule->fillParameters(['something'])->check(null));
+ $this->assertTrue($this->rule->fillParameters([[1,2,3]])->check(false));
+ $this->assertTrue($this->rule->fillParameters([[1,2,3]])->check([]));
}
-
}
diff --git a/tests/Rules/DigitsBetweenTest.php b/tests/Rules/DigitsBetweenTest.php
index f84e694..0602663 100644
--- a/tests/Rules/DigitsBetweenTest.php
+++ b/tests/Rules/DigitsBetweenTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters([1, 3])->check(12345));
$this->assertFalse($this->rule->fillParameters([3, 6])->check('foobar'));
}
-
}
diff --git a/tests/Rules/DigitsTest.php b/tests/Rules/DigitsTest.php
index 2523144..7d9db2e 100644
--- a/tests/Rules/DigitsTest.php
+++ b/tests/Rules/DigitsTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters([7])->check(12345678));
- $this->assertFalse($this->rule->fillParameters([4])->check(12));
- $this->assertFalse($this->rule->fillParameters([3])->check('foo'));
+ $this->assertFalse($this->rule->fillParameters([4])->check(12));
+ $this->assertFalse($this->rule->fillParameters([3])->check('foo'));
}
-
}
diff --git a/tests/Rules/EmailTest.php b/tests/Rules/EmailTest.php
index 255155b..66ba2fc 100644
--- a/tests/Rules/EmailTest.php
+++ b/tests/Rules/EmailTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('johndoe.gmail.com'));
$this->assertFalse($this->rule->check('johndoe.gmail.com'));
}
-
}
diff --git a/tests/Rules/InTest.php b/tests/Rules/InTest.php
index f0d1169..29e86be 100644
--- a/tests/Rules/InTest.php
+++ b/tests/Rules/InTest.php
@@ -1,8 +1,11 @@
assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
$this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(true));
- // Strict
+ // Strict
$this->rule->strict();
- $this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
- $this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
}
-
}
diff --git a/tests/Rules/IntegerTest.php b/tests/Rules/IntegerTest.php
index 7e0304f..101a4d4 100644
--- a/tests/Rules/IntegerTest.php
+++ b/tests/Rules/IntegerTest.php
@@ -1,8 +1,11 @@
assertTrue($this->rule->check('-123'));
$this->assertTrue($this->rule->check(123));
$this->assertTrue($this->rule->check(-123));
-
}
public function testInvalids()
@@ -29,5 +31,4 @@ public function testInvalids()
$this->assertFalse($this->rule->check('123.456'));
$this->assertFalse($this->rule->check('-123.456'));
}
-
}
diff --git a/tests/Rules/IpTest.php b/tests/Rules/IpTest.php
index 5f68c32..0eac7eb 100644
--- a/tests/Rules/IpTest.php
+++ b/tests/Rules/IpTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('hf02::2'));
$this->assertFalse($this->rule->check('12345:0000:3238:DFE1:0063:0000:0000:FEFB'));
}
-
}
diff --git a/tests/Rules/Ipv4Test.php b/tests/Rules/Ipv4Test.php
index d0b9a1b..41bd6fe 100644
--- a/tests/Rules/Ipv4Test.php
+++ b/tests/Rules/Ipv4Test.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('hf02::2'));
$this->assertFalse($this->rule->check('12345:0000:3238:DFE1:0063:0000:0000:FEFB'));
}
-
}
diff --git a/tests/Rules/Ipv6Test.php b/tests/Rules/Ipv6Test.php
index ea4218a..f3ab8d3 100644
--- a/tests/Rules/Ipv6Test.php
+++ b/tests/Rules/Ipv6Test.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('hf02::2'));
$this->assertFalse($this->rule->check('12345:0000:3238:DFE1:0063:0000:0000:FEFB'));
}
-
}
diff --git a/tests/Rules/JsonTest.php b/tests/Rules/JsonTest.php
index aa5377f..9daa860 100644
--- a/tests/Rules/JsonTest.php
+++ b/tests/Rules/JsonTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('{"username": John Doe}'));
$this->assertFalse($this->rule->check('{number: 12345678}'));
}
-
}
-
diff --git a/tests/Rules/LowercaseTest.php b/tests/Rules/LowercaseTest.php
index 5441140..dcc17b4 100644
--- a/tests/Rules/LowercaseTest.php
+++ b/tests/Rules/LowercaseTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('Username'));
$this->assertFalse($this->rule->check('userName'));
}
-
}
diff --git a/tests/Rules/MaxTest.php b/tests/Rules/MaxTest.php
index 304edb0..8c9087b 100644
--- a/tests/Rules/MaxTest.php
+++ b/tests/Rules/MaxTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters([100])->check(123));
}
+ public function testUploadedFileValue()
+ {
+ $twoMega = 1024 * 1024 * 2;
+ $sampleFile = [
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => $twoMega,
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ];
+
+ $this->assertTrue($this->rule->fillParameters([$twoMega])->check($sampleFile));
+ $this->assertTrue($this->rule->fillParameters(['2M'])->check($sampleFile));
+
+ $this->assertFalse($this->rule->fillParameters([$twoMega - 1])->check($sampleFile));
+ $this->assertFalse($this->rule->fillParameters(['1.9M'])->check($sampleFile));
+ }
}
diff --git a/tests/Rules/MimesTest.php b/tests/Rules/MimesTest.php
new file mode 100644
index 0000000..5056f96
--- /dev/null
+++ b/tests/Rules/MimesTest.php
@@ -0,0 +1,151 @@
+rule = new Mimes();
+ }
+
+ public function testValidMimes()
+ {
+ $file = [
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => filesize(__FILE__),
+ 'tmp_name' => __FILE__,
+ 'error' => UPLOAD_ERR_OK
+ ];
+
+ $uploadedFileRule = $this->getMockBuilder(Mimes::class)
+ ->setMethods(['isUploadedFile'])
+ ->getMock();
+
+ $uploadedFileRule->expects($this->once())
+ ->method('isUploadedFile')
+ ->willReturn(true);
+
+ $this->assertTrue($uploadedFileRule->check($file));
+ }
+
+ /**
+ * Make sure we can't just passing array like valid $_FILES['key']
+ */
+ public function testValidateWithoutMockShouldBeInvalid()
+ {
+ $this->assertFalse($this->rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => filesize(__FILE__),
+ 'tmp_name' => __FILE__,
+ 'error' => UPLOAD_ERR_OK
+ ]));
+ }
+
+ /**
+ * Missing UPLOAD_ERR_NO_FILE should be valid because it is job for required rule
+ */
+ public function testEmptyMimesShouldBeValid()
+ {
+ $this->assertTrue($this->rule->check([
+ 'name' => '',
+ 'type' => '',
+ 'size' => '',
+ 'tmp_name' => '',
+ 'error' => UPLOAD_ERR_NO_FILE
+ ]));
+ }
+
+ public function testUploadError()
+ {
+ $this->assertFalse($this->rule->check([
+ 'name' => '',
+ 'type' => '',
+ 'size' => '',
+ 'tmp_name' => '',
+ 'error' => 5
+ ]));
+ }
+
+ public function testFileTypes()
+ {
+
+ $rule = $this->getMockBuilder(Mimes::class)
+ ->setMethods(['isUploadedFile'])
+ ->getMock();
+
+ $rule->expects($this->exactly(3))
+ ->method('isUploadedFile')
+ ->willReturn(true);
+
+ $rule->allowTypes('png|jpeg');
+
+ $this->assertFalse($rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => 1024, // 1K
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+
+ $this->assertTrue($rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'image/png',
+ 'size' => 10 * 1024,
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+
+ $this->assertTrue($rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'image/jpeg',
+ 'size' => 10 * 1024,
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+ }
+
+ /**
+ * Missing array key(s) should be valid because it is job for required rule
+ */
+ public function testMissingAKeyShouldBeValid()
+ {
+ // missing name
+ $this->assertTrue($this->rule->check([
+ 'type' => 'text/plain',
+ 'size' => filesize(__FILE__),
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+
+ // missing type
+ $this->assertTrue($this->rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'size' => filesize(__FILE__),
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+
+ // missing size
+ $this->assertTrue($this->rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ]));
+
+ // missing tmp_name
+ $this->assertTrue($this->rule->check([
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => filesize(__FILE__),
+ 'error' => 0
+ ]));
+ }
+}
diff --git a/tests/Rules/MinTest.php b/tests/Rules/MinTest.php
index 5f51ef3..98b8b99 100644
--- a/tests/Rules/MinTest.php
+++ b/tests/Rules/MinTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters([7])->check('foobar'));
$this->assertFalse($this->rule->fillParameters([4])->check([1,2,3]));
- $this->assertFalse($this->rule->fillParameters([200])->check(123));
+ $this->assertFalse($this->rule->fillParameters([200])->check(123));
$this->assertFalse($this->rule->fillParameters([4])->check('мин'));
$this->assertFalse($this->rule->fillParameters([5])->check('كلمة'));
$this->assertFalse($this->rule->fillParameters([4])->check('ワード'));
- $this->assertFalse($this->rule->fillParameters([2])->check('字'));
+ $this->assertFalse($this->rule->fillParameters([2])->check('字'));
}
+ public function testUploadedFileValue()
+ {
+ $twoMega = 1024 * 1024 * 2;
+ $sampleFile = [
+ 'name' => pathinfo(__FILE__, PATHINFO_BASENAME),
+ 'type' => 'text/plain',
+ 'size' => $twoMega,
+ 'tmp_name' => __FILE__,
+ 'error' => 0
+ ];
+
+ $this->assertTrue($this->rule->fillParameters([$twoMega])->check($sampleFile));
+ $this->assertTrue($this->rule->fillParameters(['2M'])->check($sampleFile));
+
+ $this->assertFalse($this->rule->fillParameters([$twoMega + 1])->check($sampleFile));
+ $this->assertFalse($this->rule->fillParameters(['2.1M'])->check($sampleFile));
+ }
}
diff --git a/tests/Rules/NotInTest.php b/tests/Rules/NotInTest.php
index 403c860..34f0523 100644
--- a/tests/Rules/NotInTest.php
+++ b/tests/Rules/NotInTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(1));
$this->assertFalse($this->rule->fillParameters(['1', '2', '3'])->check(true));
- // Strict
+ // Strict
$this->rule->strict();
- $this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
- $this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
+ $this->assertTrue($this->rule->fillParameters(['1', '2', '3'])->check(1));
}
-
}
diff --git a/tests/Rules/NumericTest.php b/tests/Rules/NumericTest.php
index 92de70b..cc309df 100644
--- a/tests/Rules/NumericTest.php
+++ b/tests/Rules/NumericTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('123foo'));
$this->assertFalse($this->rule->check([123]));
}
-
}
diff --git a/tests/Rules/RegexTest.php b/tests/Rules/RegexTest.php
index 9360115..d5d5f35 100644
--- a/tests/Rules/RegexTest.php
+++ b/tests/Rules/RegexTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->fillParameters(["/^F/i"])->check("bar"));
}
-
}
diff --git a/tests/Rules/RequiredTest.php b/tests/Rules/RequiredTest.php
index 349f650..3f3535f 100644
--- a/tests/Rules/RequiredTest.php
+++ b/tests/Rules/RequiredTest.php
@@ -1,8 +1,12 @@
assertTrue($this->rule->check(true));
$this->assertTrue($this->rule->check('0'));
$this->assertTrue($this->rule->check(0));
- $this->assertTrue($this->rule->check(new \stdClass));
+ $this->assertTrue($this->rule->check(new stdClass));
}
public function testInvalids()
@@ -27,5 +31,4 @@ public function testInvalids()
$this->assertFalse($this->rule->check(''));
$this->assertFalse($this->rule->check([]));
}
-
}
diff --git a/tests/Rules/TypeArrayTest.php b/tests/Rules/TypeArrayTest.php
index 2da1ee5..56e8e60 100644
--- a/tests/Rules/TypeArrayTest.php
+++ b/tests/Rules/TypeArrayTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('[]'));
$this->assertFalse($this->rule->check('[1,2,3]'));
}
-
}
diff --git a/tests/Rules/UploadedFileTest.php b/tests/Rules/UploadedFileTest.php
index 542c4f3..3f0f6f5 100644
--- a/tests/Rules/UploadedFileTest.php
+++ b/tests/Rules/UploadedFileTest.php
@@ -1,8 +1,11 @@
getMockBuilder(UploadedFile::class)
->setMethods(['isUploadedFile'])
->getMock();
diff --git a/tests/Rules/UppercaseTest.php b/tests/Rules/UppercaseTest.php
index 7c69600..cf7bdc8 100644
--- a/tests/Rules/UppercaseTest.php
+++ b/tests/Rules/UppercaseTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->check('Username'));
$this->assertFalse($this->rule->check('userName'));
}
-
}
diff --git a/tests/Rules/UrlTest.php b/tests/Rules/UrlTest.php
index 00a520e..d91fe3d 100644
--- a/tests/Rules/UrlTest.php
+++ b/tests/Rules/UrlTest.php
@@ -1,8 +1,11 @@
assertFalse($this->rule->forScheme('jdbc')->check('http://www.foobar.com'));
$this->assertFalse($this->rule->forScheme(['http', 'https'])->check('any://www.foobar.com'));
}
-
}
diff --git a/tests/ValidatonTest.php b/tests/ValidatonTest.php
index 9f82e70..4f8f69d 100644
--- a/tests/ValidatonTest.php
+++ b/tests/ValidatonTest.php
@@ -1,9 +1,13 @@
'',
'type' => '',
'size' => '',
@@ -95,7 +97,7 @@ public function testOptionalUploadedFile()
];
$validation = $this->validator->validate([
- 'file' => $empty_file
+ 'file' => $emptyFile
], [
'file' => 'uploaded_file'
]);
@@ -105,10 +107,10 @@ public function testOptionalUploadedFile()
/**
* @dataProvider getSamplesMissingKeyFromUploadedFileValue
*/
- public function testMissingKeyUploadedFile($uploaded_file)
+ public function testMissingKeyUploadedFile($uploadedFile)
{
$validation = $this->validator->validate([
- 'file' => $uploaded_file
+ 'file' => $uploadedFile
], [
'file' => 'required|uploaded_file'
]);
@@ -120,7 +122,7 @@ public function testMissingKeyUploadedFile($uploaded_file)
public function getSamplesMissingKeyFromUploadedFileValue()
{
- $valid_uploaded_file = [
+ $validUploadedFile = [
'name' => 'foo',
'type' => 'text/plain',
'size' => 1000,
@@ -129,14 +131,279 @@ public function getSamplesMissingKeyFromUploadedFileValue()
];
$samples = [];
- foreach($valid_uploaded_file as $key => $value) {
- $uploaded_file = $valid_uploaded_file;
- unset($uploaded_file[$key]);
- $samples[] = $uploaded_file;
+ foreach ($validUploadedFile as $key => $value) {
+ $uploadedFile = $validUploadedFile;
+ unset($uploadedFile[$key]);
+ $samples[] = $uploadedFile;
}
return $samples;
}
+ public function testValidationShouldCorrectlyResolveMultipleFileUploads()
+ {
+ // Test from input files:
+ //
+ //
+ $sampleInputFiles = [
+ 'photos' => [
+ 'name' => [
+ 'a.png',
+ 'b.jpeg',
+ ],
+ 'type' => [
+ 'image/png',
+ 'image/jpeg',
+ ],
+ 'size' => [
+ 1000,
+ 2000,
+ ],
+ 'tmp_name' => [
+ __DIR__.'/a.png',
+ __DIR__.'/b.jpeg',
+ ],
+ 'error' => [
+ UPLOAD_ERR_OK,
+ UPLOAD_ERR_OK,
+ ]
+ ]
+ ];
+
+ $uploadedFileRule = $this->getMockedUploadedFileRule()->fileTypes('jpeg');
+
+ $validation = $this->validator->validate($sampleInputFiles, [
+ 'photos.*' => ['required', $uploadedFileRule]
+ ]);
+
+ $this->assertFalse($validation->passes());
+ $this->assertEquals($validation->getValidData(), [
+ 'photos' => [
+ 1 => [
+ 'name' => 'b.jpeg',
+ 'type' => 'image/jpeg',
+ 'size' => 2000,
+ 'tmp_name' => __DIR__.'/b.jpeg',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ]);
+ $this->assertEquals($validation->getInvalidData(), [
+ 'photos' => [
+ 0 => [
+ 'name' => 'a.png',
+ 'type' => 'image/png',
+ 'size' => 1000,
+ 'tmp_name' => __DIR__.'/a.png',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ]);
+ }
+
+ public function testValidationShouldCorrectlyResolveAssocFileUploads()
+ {
+ // Test from input files:
+ //
+ //
+ $sampleInputFiles = [
+ 'photos' => [
+ 'name' => [
+ 'foo' => 'a.png',
+ 'bar' => 'b.jpeg',
+ ],
+ 'type' => [
+ 'foo' => 'image/png',
+ 'bar' => 'image/jpeg',
+ ],
+ 'size' => [
+ 'foo' => 1000,
+ 'bar' => 2000,
+ ],
+ 'tmp_name' => [
+ 'foo' => __DIR__.'/a.png',
+ 'bar' => __DIR__.'/b.jpeg',
+ ],
+ 'error' => [
+ 'foo' => UPLOAD_ERR_OK,
+ 'bar' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ];
+
+ $uploadedFileRule = $this->getMockedUploadedFileRule()->fileTypes('jpeg');
+
+ $validation = $this->validator->validate($sampleInputFiles, [
+ 'photos.foo' => ['required', clone $uploadedFileRule],
+ 'photos.bar' => ['required', clone $uploadedFileRule],
+ ]);
+
+ $this->assertFalse($validation->passes());
+ $this->assertEquals($validation->getValidData(), [
+ 'photos' => [
+ 'bar' => [
+ 'name' => 'b.jpeg',
+ 'type' => 'image/jpeg',
+ 'size' => 2000,
+ 'tmp_name' => __DIR__.'/b.jpeg',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ]);
+ $this->assertEquals($validation->getInvalidData(), [
+ 'photos' => [
+ 'foo' => [
+ 'name' => 'a.png',
+ 'type' => 'image/png',
+ 'size' => 1000,
+ 'tmp_name' => __DIR__.'/a.png',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ]);
+ }
+
+ public function testValidationShouldCorrectlyResolveComplexFileUploads()
+ {
+ // Test from input files:
+ //
+ //
+ //
+ //
+ $sampleInputFiles = [
+ 'files' => [
+ 'name' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => 'foo-bar-baz.jpeg',
+ 'qux' => 'foo-bar-qux.png',
+ ]
+ ],
+ 'photos' => [
+ 'photos-0.png',
+ 'photos-1.jpeg',
+ ]
+ ],
+ 'type' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => 'image/jpeg',
+ 'qux' => 'image/png',
+ ]
+ ],
+ 'photos' => [
+ 'image/png',
+ 'image/jpeg',
+ ]
+ ],
+ 'size' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => 500,
+ 'qux' => 750,
+ ]
+ ],
+ 'photos' => [
+ 1000,
+ 2000,
+ ]
+ ],
+ 'tmp_name' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => __DIR__.'/foo-bar-baz.jpeg',
+ 'qux' => __DIR__.'/foo-bar-qux.png',
+ ]
+ ],
+ 'photos' => [
+ __DIR__.'/photos-0.png',
+ __DIR__.'/photos-1.jpeg',
+ ]
+ ],
+ 'error' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => UPLOAD_ERR_OK,
+ 'qux' => UPLOAD_ERR_OK,
+ ]
+ ],
+ 'photos' => [
+ UPLOAD_ERR_OK,
+ UPLOAD_ERR_OK,
+ ]
+ ]
+ ]
+ ];
+
+ $uploadedFileRule = $this->getMockedUploadedFileRule()->fileTypes('jpeg');
+
+ $validation = $this->validator->validate($sampleInputFiles, [
+ 'files.foo.bar.baz' => ['required', clone $uploadedFileRule],
+ 'files.foo.bar.qux' => ['required', clone $uploadedFileRule],
+ 'files.photos.*' => ['required', clone $uploadedFileRule],
+ ]);
+
+ $this->assertFalse($validation->passes());
+ $this->assertEquals($validation->getValidData(), [
+ 'files' => [
+ 'foo' => [
+ 'bar' => [
+ 'baz' => [
+ 'name' => 'foo-bar-baz.jpeg',
+ 'type' => 'image/jpeg',
+ 'size' => 500,
+ 'tmp_name' => __DIR__.'/foo-bar-baz.jpeg',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ],
+ 'photos' => [
+ 1 => [
+ 'name' => 'photos-1.jpeg',
+ 'type' => 'image/jpeg',
+ 'size' => 2000,
+ 'tmp_name' => __DIR__.'/photos-1.jpeg',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ]
+ ]);
+ $this->assertEquals($validation->getInvalidData(), [
+ 'files' => [
+ 'foo' => [
+ 'bar' => [
+ 'qux' => [
+ 'name' => 'foo-bar-qux.png',
+ 'type' => 'image/png',
+ 'size' => 750,
+ 'tmp_name' => __DIR__.'/foo-bar-qux.png',
+ 'error' => UPLOAD_ERR_OK,
+ ]
+ ]
+ ],
+ 'photos' => [
+ 0 => [
+ 'name' => 'photos-0.png',
+ 'type' => 'image/png',
+ 'size' => 1000,
+ 'tmp_name' => __DIR__.'/photos-0.png',
+ 'error' => UPLOAD_ERR_OK,
+ ],
+ ]
+ ]
+ ]);
+ }
+
+ public function getMockedUploadedFileRule()
+ {
+ $rule = $this->getMockBuilder(UploadedFile::class)
+ ->setMethods(['isUploadedFile'])
+ ->getMock();
+
+ $rule->method('isUploadedFile')->willReturn(true);
+
+ return $rule;
+ }
+
public function testRequiredIfRule()
{
$v1 = $this->validator->validate([
@@ -286,7 +553,7 @@ public function testNonExistentValidationRule()
'name' => "some name"
], [
'name' => 'required|xxx'
- ],[
+ ], [
'name.required' => "Fill in your name",
'xxx' => "Oops"
]);
@@ -308,7 +575,7 @@ public function testBeforeRule()
$validator2 = $this->validator->make($data, [
'date' => "required|before:last week"
- ],[]);
+ ], []);
$validator2->validate();
@@ -329,7 +596,7 @@ public function testAfterRule()
$validator2 = $this->validator->make($data, [
'date' => "required|after:next year"
- ],[]);
+ ], []);
$validator2->validate();
@@ -369,7 +636,8 @@ public function testInternalValidationRuleCanBeOverridden()
{
$this->validator->allowRuleOverride(true);
- $this->validator->addValidator('required', new Required()); //This is a custom rule defined in the fixtures directory
+ //This is a custom rule defined in the fixtures directory
+ $this->validator->addValidator('required', new Required());
$data = ['s' => json_encode(['name' => 'space x', 'human' => false])];
@@ -629,7 +897,7 @@ public function testSetCustomMessagesInValidation()
public function testCustomMessageInCallbackRule()
{
$evenNumberValidator = function ($value) {
- if (!is_numeric($value) OR $value % 2 !== 0) {
+ if (!is_numeric($value) or $value % 2 !== 0) {
return ":attribute must be even number";
}
return true;
@@ -1010,4 +1278,143 @@ public function testGetInvalidData()
$this->assertFalse(isset($stuffs['two']));
}
+ public function testRuleInInvalidMessages()
+ {
+ $validation = $this->validator->validate([
+ 'number' => 1
+ ], [
+ 'number' => 'in:7,8,9',
+ ]);
+
+ $this->assertEquals($validation->errors()->first('number'), "The Number only allows '7', '8', or '9'");
+
+ // Using translation
+ $this->validator->setTranslation('or', 'atau');
+
+ $validation = $this->validator->validate([
+ 'number' => 1
+ ], [
+ 'number' => 'in:7,8,9',
+ ]);
+
+ $this->assertEquals($validation->errors()->first('number'), "The Number only allows '7', '8', atau '9'");
+ }
+
+ public function testRuleNotInInvalidMessages()
+ {
+ $validation = $this->validator->validate([
+ 'number' => 1
+ ], [
+ 'number' => 'not_in:1,2,3',
+ ]);
+
+ $this->assertEquals($validation->errors()->first('number'), "The Number is not allowing '1', '2', and '3'");
+
+ // Using translation
+ $this->validator->setTranslation('and', 'dan');
+
+ $validation = $this->validator->validate([
+ 'number' => 1
+ ], [
+ 'number' => 'not_in:1,2,3',
+ ]);
+
+ $this->assertEquals($validation->errors()->first('number'), "The Number is not allowing '1', '2', dan '3'");
+ }
+
+ public function testRuleMimesInvalidMessages()
+ {
+ $file = [
+ 'name' => 'sample.txt',
+ 'type' => 'plain/text',
+ 'tmp_name' => __FILE__,
+ 'size' => 1000,
+ 'error' => UPLOAD_ERR_OK,
+ ];
+
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => 'mimes:jpeg,png,bmp',
+ ]);
+
+ $expectedMessage = "The Sample file type must be 'jpeg', 'png', or 'bmp'";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+
+ // Using translation
+ $this->validator->setTranslation('or', 'atau');
+
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => 'mimes:jpeg,png,bmp',
+ ]);
+
+ $expectedMessage = "The Sample file type must be 'jpeg', 'png', atau 'bmp'";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+ }
+
+ public function testRuleUploadedFileInvalidMessages()
+ {
+ $file = [
+ 'name' => 'sample.txt',
+ 'type' => 'plain/text',
+ 'tmp_name' => __FILE__,
+ 'size' => 1024 * 1024 * 2, // 2M
+ 'error' => UPLOAD_ERR_OK,
+ ];
+
+ $rule = $this->getMockedUploadedFileRule();
+
+ // Invalid uploaded file (!is_uploaded_file($file['tmp_name']))
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => 'uploaded_file',
+ ]);
+
+ $expectedMessage = "The Sample is not valid uploaded file";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+
+ // Invalid min size
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => [(clone $rule)->minSize('3M')],
+ ]);
+
+ $expectedMessage = "The Sample file is too small, minimum size is 3M";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+
+ // Invalid max size
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => [(clone $rule)->maxSize('1M')],
+ ]);
+
+ $expectedMessage = "The Sample file is too large, maximum size is 1M";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+
+ // Invalid file types
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => [(clone $rule)->fileTypes(['jpeg', 'png', 'bmp'])],
+ ]);
+
+ $expectedMessage = "The Sample file type must be 'jpeg', 'png', or 'bmp'";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+
+ // Invalid file types with translation
+ $this->validator->setTranslation('or', 'atau');
+ $validation = $this->validator->validate([
+ 'sample' => $file,
+ ], [
+ 'sample' => [(clone $rule)->fileTypes(['jpeg', 'png', 'bmp'])],
+ ]);
+
+ $expectedMessage = "The Sample file type must be 'jpeg', 'png', atau 'bmp'";
+ $this->assertEquals($validation->errors()->first('sample'), $expectedMessage);
+ }
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..6c8c4f5
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,3 @@
+