illuminatech / validation-composite Goto Github PK
View Code? Open in Web Editor NEWAllows uniting of several validation rules into single one for easy re-usage
License: Other
Allows uniting of several validation rules into single one for easy re-usage
License: Other
Hi, I have an issue using composite rules.
Namely, I'm accepting an object with two properties in my form request, and I want to have composite rules for each of the properties.
In order to ensure the structure of the object, I want to use required_with
in both composite rules, and that's proven to be highly problematic.
Here's what I need:
Form request:
<?php
namespace App\Http\Requests\Api;
use App\Http\Requests\FormRequest;
use App\Rules\CurrencyPriceAmountRule;
use App\Rules\CurrencyPriceCurrencyRule;
class ExpenseRequest extends FormRequest
{
public function rules()
{
return [
'total_price' => ['nullable', 'array'],
'total_price.amount' => CurrencyPriceAmountRule::forPrice('total_price'),
'total_price.currency' => CurrencyPriceCurrencyRule::forPrice('total_price'),
];
}
}
Composite rule for amount:
<?php
namespace App\Rules;
use Illuminatech\Validation\Composite\CompositeRule;
class CurrencyPriceAmountRule extends CompositeRule
{
private string $priceObject;
public static function forPrice(string $priceObjectName): self
{
$rule = new self();
$rule->priceObject = $priceObjectName;
return $rule;
}
protected function rules(): array
{
return [
"required_with:{$this->priceObject}",
'numeric',
];
}
}
Composite rule for currency:
<?php
namespace App\Rules;
use Illuminatech\Validation\Composite\CompositeRule;
class CurrencyPriceCurrencyRule extends CompositeRule
{
private string $priceObject;
public static function forPrice(string $priceObjectName): self
{
$rule = new self();
$rule->priceObject = $priceObjectName;
return $rule;
}
protected function rules(): array
{
return [
"required_with:{$this->priceObject}",
"string",
"size:3",
];
}
}
And everything's working well when there is valid input, however when there is no total_price
field in the input validation fails. If total_price.amount
were present without total_price.currency
, or vice versa, validation should fail. However, if total_price
is completely missing validation should not fail.
I've tracked the issue down to this line:
What happens is the CompositeRule::passes()
method receives total_price.amount
as the $attribute
argument, and null
as the $value
argument, and then the Arr::set()
invocation creates the following structure for the $data
variable:
[
'total_price' => [
'amount' => null,
],
]
And then validation fails because it detects total_price
is present, however total_price.amount
is null.
I'd be happy to think about a possible solution and submit a PR, I just want to know that what I'm describing is indeed undesired behaviour and a proper PR would get merged.
Thanks for the nice-looking package.
I'm just wondering if this package is intended to be used with custom validation rules and form requests. For instance, are you aware if there would be any problem with trying to do this:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Uppercase implements Rule
{
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'The :attribute must be uppercase.';
}
}
class PasswordCompositeRule extends CompositeRule
{
protected function rules(): array
{
return ['string', 'min:8', 'max:200', new Uppercase];
}
}
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => ['required', 'min:5', new PasswordCompositeRule],
];
}
}
Q | A |
---|---|
This Package Version | 1.1 |
Laravel Framework Version | 6.0 |
Great package! I just ran into this when trying to validate request data containing array fields.
If you have a set of rules that contain dot notation fields representing array validation the CompositeRule doesn't run, see example:
public function rules() {
return [
'enabled' => 'required|boolean',
'attributes.url' => ['required', new SecureUrl], // Composite seems to get skipped
'attributes.tags.*' => ['required', new TagsAllowed], // Composite seems to get skipped
// Wildcards can be anywhere in the key 'person.*.email'
];
}
CompositeRule
validation is executed.
Validation rules seem to be skipped.
In the below code from the passes
method the [$attribute => $value]
part I think is the issue as the attribute/data structure may need to be converted to the correct array structure.
/** CompositeRule::passes... */
$validator = $this->getValidatorFactory()->make([$attribute => $value], [
$attribute => $this->rules(),
]);
Laravel must handle this translation from dot notation to array somewhere in their validation code. So I assume the solution is out there.
You can transform the dot notation field to an array using something like the below:
/** CompositeRule::passes... */
$fields = [];
// Transform attribute to matching array with value
\Arr::set($fields, $attribute, $value);
$validator = $this->getValidatorFactory()->make($fields, [
$attribute => $this->rules(),
]);
The Arr::set
transforms the dot notation to an array.
Q | A |
---|---|
This Package Version | 1.0.0 |
Laravel Framework Version | 5.8.* |
PHP version | 7.1 |
Operating system | Ubuntu |
The name of Yii Software LLC is in the LICENSE.md file and I think it's the same for some other repos.
why cant we create custom RULES a feature laravel already provides - we can then use these anywhere we want just like urs.
Is there any plans for this package to support Laravel 6?
validation-composite/composer.json
Line 18 in 86e9e78
Should be possible to specify the error message for each of the rules.
Something like:
<?php
namespace App\Rules;
use Illuminatech\Validation\Composite\CompositeRule;
class PasswordRule extends CompositeRule
{
protected function rules(): array
{
return ['string', 'min:8', 'max:200'];
}
protected function messages(): array
{
return [
'string' => 'My custom string message',
'min' => 'My custom min message',
'max' => 'My custom max message',
];
}
}
Is there some way to achieve this implemented already? Looking at the code I see no way of passing the custom messages to the validator instance that is used to perform the checks.
Q | A |
---|---|
This Package Version | 1.1.0 |
Laravel Framework Version | 6.11.0 |
PHP version | 7.4 |
Operating system | Ubuntu 19.10 |
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.