0

I'm working with Laravel nested resources to serve a many-to-many relationship. I'm working on a Football app and I want to link Competitions with Seasons, e.g. Premier League with 2021/22 season.

What I want to achieve is to have a dedicated route to manage this relationship with Seasons being sub-resources of Competitions.

My entities have an auto-generated integer ID at database level, but I'm using getRouteKeyName() to define the slug as the field to be used by Laravel for implicit model binding.

Now I'm struggling to make the validation work when posting a new Season under a Competition. The request looks like this:

POST /api/competitions/premier-league/seasons/

{
    "season": "21-22",
    ...
}

The value "21-22" is the actual slug for the Season object, but I can't manage to use it for validation in the association table, as foreign keys in it use auto-generated ones rather than the column I use for implicit model-binding.

To clarify, the tables look like this:

seasons                  competition_editions               competitions
id      slug             id      comp    season             id      slug
X       21-22            Z       Y       X                  Y       premier-league

Is there a way to make the unique rule of FormRequest work with model-binding key so that I don't have to manually convert the slug to the actual id of the resource inside the controller?

Thank you!

2
  • Are you validating input into seasons or competition_editions? If it's the latter then you can look at unique validation under the part that says Adding Additional Where Clauses Commented Jan 22, 2022 at 6:00
  • The problem is within the value I'm passing to the API.. I could use unique constraints but these aren't really on the slug, they should be applied to its matching id.. Maybe have a look at the answer I posted just to give a feedback/propose improvements? Commented Jan 22, 2022 at 21:06

1 Answer 1

0

So, I came up with something but I'm not sure it's the nicest way to handle it.

Basically I used the prepareForValidation() on FormRequest to transform the slug into the actual database id of the Season resource.

Here is the code, just to make it clear:

/**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation() {
        $season = Season::where('slug', $this->season)->first();

        $this->merge([
            'season' => $season != null ? $season->id : 0,
        ]);
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules() {
        return [
            'season' => [
                'required',
                'exists:seasons,id',
                Rule::unique('competition_editions', 'season_id')
                    ->where('competition_id', $this->route('competition')->id),
            ],
        ];
    }

The thing I like the least is defaulting the id to 0 if the slug doesn't match any Season, but leaving it null would cause a Database Exception within the exists rule..

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.