nova-flexible-content icon indicating copy to clipboard operation
nova-flexible-content copied to clipboard

How to use before and after rules on date fields?

Open vmihaly2020 opened this issue 5 years ago • 5 comments

How to use before and after rules on date fields? none of this won't work ->rules('required', 'date', 'before:b_enddate')) ->rules('required', 'date', 'before:blackout.b_enddate')) ->rules('required', 'date', 'before:blackout.attributes.b_enddate)) The layout's unique identifier is blackout and I have two fields b_startdate and b_enddate both is casted to date

vmihaly2020 avatar Jul 31 '20 11:07 vmihaly2020

Hi @vmihaly2020,

Layouts have their own (random) identifiers since one layout can have multiple instances. We'll have to check why before:b_enddate doesn't work, because it should.

toonvandenbos avatar Jul 31 '20 12:07 toonvandenbos

Same issue with required_if, required_unless... all rules referencing another field.

Also, rules seems not applied if the value is null, example: ->rules(['nullable', new CustomRules]), the CustomRules::passes() method is not called.

Broutard avatar Jun 11 '21 13:06 Broutard

Here is how I fixed this for a required_with and a required_unless rule. Create a new Layout class and use that one instead of Whitecube\NovaFlexibleContent\Layouts\Layout, then overwrite the getScopedFieldRules method.

use Whitecube\NovaFlexibleContent\Http\ScopedRequest;
use Whitecube\NovaFlexibleContent\Layouts\Layout as BaseLayout;

class Layout extends BaseLayout
{
    /**
     * Get validation rules for fields concerned by given request
     *
     * @param  \Laravel\Nova\Fields\Field $field
     * @param  ScopedRequest $request
     * @param  null|string $specificty
     * @param  string $key
     * @return array
     */
    protected function getScopedFieldRules($field, ScopedRequest $request, $specificty, $key)
    {
        $method = 'get' . ucfirst($specificty) . 'Rules';

        $rules = call_user_func([$field, $method], $request);

        return collect($rules)->mapWithKeys(function ($validatorRules, $attribute) use ($key, $field) {
            $rules = $this->wrapScopedFieldRules($field, $validatorRules);

            // Scope the fields used in the rules
            if ($rules !== null) {
                foreach ($rules['rules'] as &$rule) {
                    if (substr($rule, 0, 16) === 'required_unless:') {
                        $rule = preg_replace('/^(required_unless:)(.+?)($|,.*$)/', '${1}' . $key . '.attributes.' . '${2}${3}', $rule);
                    } elseif (substr($rule, 0, 14) === 'required_with:') {
                        $rule = preg_replace('/^(required_with:)(.+)$/', '${1}' . $key . '.attributes.' . '${2}', $rule);
                    }
                }
            }

            return [$key . '.attributes.' . $attribute => $rules];
        })
        ->filter()
        ->all();
    }
}

chosten avatar Aug 06 '21 21:08 chosten

This works great. Would you accept this feature into the codebase? It should be expanded with support for other rules like required_if, and account for Rule objects and such, but with a bit of polishing this would be a great addition to the core.

harmenjanssen avatar Apr 06 '22 12:04 harmenjanssen

this is my solution for other rules in chosten's solution, the only problem is that the error message contains "content.0.attributes." in the string, dont know how to solve that yet, apart from that the logic works as it should:

protected function getScopedFieldRules($field, ScopedRequest $request, $specificty, $key)
    {
        $method = 'get' . ucfirst($specificty) . 'Rules';

        $rules = call_user_func([$field, $method], $request);

        return collect($rules)->mapWithKeys(function ($validatorRules, $attribute) use ($key, $field, $request) {
            $rules = $this->wrapScopedFieldRules($field, $validatorRules);

            if ($rules !== null) {
                foreach ($rules['rules'] as &$rule) {
                    $ruleType = explode(':', $rule)[0];
                    $rule = preg_replace('/^(' . preg_quote($ruleType, '/') . ':)(.+)$/', '${1}' . $key . '.attributes.' . '${2}', $rule);
                }
            }

            return [$key . '.attributes.' . $attribute => $rules];
        })
        ->filter()
        ->all();
    }

Mare02 avatar Sep 30 '24 09:09 Mare02