0

I am setting up a custom validation rule for a BelongsToMany field in Laravel Nova to look up in the pivot table and compare with the entered value. It uses a function which is 'shared' with other fields of the same resource.

I am using the following code in the resource Delegation:

BelongsToMany::make('Authorities')
                ->fields(function ()
                {
                    return [

                        Help::make('Your Limit', "Your own limit for this authority is {$this->displayYourLimit()}. You can only delegate to the limit of your authority."),

                        Number::make('Delegated Limit ($M)', 'delegated_limit')

                            ->rules('required', function ($attribute, $value, $fail)
                            {
                                if ($value > $this->displayYourLimit())
                                {
                                    return $fail('Your value is too high');
                                }
                                …

The function in question is:

public function displayYourLimit()
        {
            $id1 = DB::table('delegations')->where('user_id', auth()->user()->id)->value('id');
            $id2 = $this->pivot['authority_id']; //This returns null inside the validation rule but not the Help field
            $result = DB::table('authority_delegation')->where('delegation_id', '=', $id1)->where('authority_id', '=', $id2)->value('delegated_limit');

            return $result;
        }

The function spans two tables in the database - delegations, which has a model Delegation and a pivot from BelongsToMany relationship with another model Authority. The pivot table is called authority_delegation.

$id1 returns the value of the id column of the delegations table for the currently logged in user. This works fine.

$id2 should return the value of the delegation_id column of the authority_delegation pivot table for the currently viewed Authorityresource attached to Delegation resource. It is basically 26 in the following url http://localhost:8000/nova/resources/delegations/2/edit-attached/authorities/26?viaRelationship=authorities that I am trying to get.

Finally, $result returns the value of the delegated_limit column of the authority_delegation where two first columns' values match. This also works fine provided $id2 sends correct value.

I expect the function to return a float which can be used both for display in the Help field and validation in the Number field. However, while working in the Help field perfectly, it does not work in validation (expected validation has no effect after required. Through testing, I see that it returns null when getting the $id2 from the pivot within the validation rule function. I am attaching a picture to illustrate. In the image, green circle shows that the necessary value is displayed correctly in one field, red circle show that it does not pass validation correctly.

Illustration of pivot returning null inside a Laravel Nova custom rule function but not outside it

But why does it work in one field and not another?

I have spent afternoon trying to figure it out. I tried converting to array, to object etc with no effect. If I can get the id of the currently viewed resource - that elusive 26 - in any other way, I would love to know!

I have relevant relationships set up in respective Authority and Delegation models:

public function authorities()
    {
        return $this->belongsToMany(Authority::class, 'authority_delegation')->withPivot('delegated_limit', 'further_delegatable', 'master_delegated_limit', 'authority_id', 'delegation_id')->withTimestamps();
    }

and 

public function delegations()
    {
        return $this->belongsToMany(Delegation::class, 'authority_delegation')->withPivot('delegated_limit', 'further_delegatable', 'master_delegated_limit', 'authority_id', 'delegation_id')->withTimestamps();
    }

All suggestions are very welcome!

2
  • Elaborate a bit on $id2 = $this->pivot['authority_id']; Where does it come from? Commented Sep 27, 2019 at 22:42
  • Thanks a lot for your willingness to help! I have added more explanation of the offending function and image of the problem. Commented Sep 28, 2019 at 8:02

1 Answer 1

0

Just in case someone has the same problem this is how I solved it:

One cannot use $this in a closure, PHP documentation is very specific about this. See here for more details https://www.php.net/manual/en/functions.anonymous.php

However, it is possible to use $request in the closure. So I just replaced the pivot table with a dedicated model and used use ($request) in the validation rule like so:

Number::make('Delegated Limit')
                ->updateRules('required', function ($attribute, $value, $fail) use ($request) {
                        $id1 = DB::table('delegations')->where('user_id', auth()->user()->id)->value('id');
                        $id2 = $request->authority;
                        $result = DB::table('issuances')->where('delegation_id', '=', $id1)->where('authority_id', '=', $id2)->value('delegated_limit');

                        if ($value > $result)
                        {
                            return $fail('Your value is too high.');
                        }
                    }

And it worked just fine.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.