Issue with using `required_with` for nested objects
misa-neopix opened this issue · comments
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.
@klimov-paul I understand your point, however what I failed to mention in the issue is the usage of \Illuminate\Contracts\Validation\ImplicitRule
. This interface can be used for making custom rule classes be validated in the same way as implicit rules (see this and this).
However, even when using the interface the validation still fails due to the issue I explained above.
What I was suggesting is refactoring the package to work with the ImplicitRule
, that way the rules mentioned in the readme would be able to be used in composite rules as long as it implements the said interface.
Sorry for forgetting to mention this in the original post.
@klimov-paul Any thoughts on my comment?