Open jonathan-bird opened 1 day ago
It should be run regardless of whether there is a value.
I don't think that's accurate. The field is only validated if it's included, or if you mark it as required
.
Validator::make([
// foo missing
], [
'foo' => 'min:5',
])->validate(); // passes
Validator::make([
'foo' => 'h',
], [
'foo' => 'min:5',
])->validate(); // fails: the foo field must be at least 5 characters
Validator::make([
'foo' => 'hello',
], [
'foo' => 'min:5',
])->validate(); // passes
Validator::make([
// foo missing
], [
'foo' => 'required|min:5',
])->validate(); // fails: the foo field is required
@jasonvarga this is kind of the point though, based on that logic you can't write your own required-type validation because the class can't even run a validate method. Why can't it pass through the field as null like what Laravel would do in a form?
Or do I have to set "always save" for that logic to apply?
Because of the fact the data isn't always saved, I'm stuck in a circumstance where it's hard to validate logic with the template field too where it's empty by default so it makes it difficult to validate if not set or someone has set it to default template.
Or I get the field to show sometimes and set "sometimes" validation and it's still not required despite the label saying it will be required when it shows.
Interested to hear your thoughts on the Statamic way, this is just how I approach things developing in Laravel.
If the field is hidden, it won't be submitted, and won't be validated.
That's consistent to traditional forms with Laravel. If a form is missing an input, it doesn't get submitted, and wouldn't be validated.
What visibility condition are you applying to it?
In order to force the field to be submitted/validated:
always_save: true
to it@jasonvarga just to clarify, in my original post the field was set, it was just an empty value (was visible).
I'll take a look at your suggestions too
I'll eat my words now. You're absolutely right.
We add nullable
to non-required fields behind the scenes.
https://github.com/statamic/cms/commit/f0ff892970880fefae2bb51bd7c71e9942775820
It's been like that for a while though. We'll have to think about how to resolve this in a non-breaking way.
Haha all good! If I can help at all please let me know.
I thought I wasn't going crazy cause the screenshots from Marty a while back show it as working - https://www.martyfriedel.com/blog/how-to-use-custom-laravel-validationrule-rules-in-statamic
Those class based rules definitely work, but as you've pointed out, they need to have a value.
Actually thinking about it a little more, I think it's probably working fine.
Can you elaborate on what you actually wanted to do in your custom validation rule?
You've named it TemplateDefaultOrNotSet
which sounds like maybe you're planning to allow the value to be null anyway, in which case it shouldn't matter if the rule doesn't run.
I think @freshface is running into a similar issue with frontend forms (precognition). Since you can't use required|sometimes
currently due to #9172, he made a custom validation rule called RequiredIfArrayContains
. This validation rule should make a field required if an array (coming from a checkbox field) contains a certain value. However this validation logic doesn't seem to trigger if the field doesn't have a value. And that's exactly when you'd want it to trigger. It only triggers on blur when there's already data in the field.
You need to add public $implicit = true;
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Contracts\Validation\DataAwareRule ;
class RequiredIfArrayContains implements DataAwareRule, ValidationRule
{
protected $data = [];
public $implicit = true;
public function __construct(
private $key = null,
private $containsValue = null,
) {
//
}
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
ray($this->key);
if(isset($this->data[$this->key]) && in_array($this->containsValue, $this->data[$this->key])) {
if(empty($value)) {
$fail('The :attribute field is required.')->translate();
}
}
}
public function setData(array $data): static
{
$this->data = $data;
return $this;
}
}
Oh, there you go. Nice.
Neat!
It works, but would be nice to make the 'sometimes' option work again. Due to this limitation its not possible anymore for clients to build a form with "show if when condition x is met" anymore.
Bug description
If you create a new custom validation rule and set it in a blueprint. Eg.
Then it won't run the
validate()
method unless there's a value set in the field.It should be run regardless of whether there is a value.
How to reproduce
Create a new custom rule:
Then go to blueprint yaml file and set this (or just set
new App\Rules\TemplateDefaultOrNotSet()
in the Blueprint view):And then once saved, create a new page and don't set any value in that field, and you will notice that it won't hit that
validate()
method (although it will hit a__construct()
if set in the custom rule)Logs
No response
Environment
Installation
Fresh statamic/statamic site via CLI
Additional details
No response