0

I'm starting with Laravel. I have LinksController that handle my links table (CRUD). I want to use this table to store all the links from my app.

I have two tables:

  • tutorials
  • posts

LinksController.php

public function store(Request $request, Tutorial $tutorial) {

    $link = new Link;
    $link->user_id = auth()->user()->id;
    $link->source_id = $tutorial->id;
    $link->link = $request->link;
    $link->save();
}

This works fine. Now I was trying to save posts links and I noticed my route model binding can use only one Model.

Routes:

tutorials/{tutorial}/links
posts/{post}/links

If I change Tutorial $tutorial for Post $post it will work for posts but not for tutorials.

I read about Polymorphic Relationships but I'm not sure how to pass different models to my LinksController.

Should I use something like this in my LinksController.php:

private $model;

public function __construct(Request $request) {
    // if route a
    //     $this->model = Tutorial::class;
    // else
    //     $this->model = Post::class;
}

I know that I can use hidden input to pass model, but I don't really want to do that.

Edit: Other solutions that come to my mind would be Explicit Binding:

RouteServiceProvider.php

Route::model('tutorial', \App\Tutorial::class);
Route::model('post', \App\Post::class);

And then in my LinksController store method:

public function store(Request $request, Model $model) {

Do you think this would be a good approach? In this case, the first parameter from the route should always be a variable that is present in my RouteServiceProvider.

Is there any better and more elegant approach to my problem?

2
  • So just so I understand, the source_id field in the link model relates to the ID of the post or tutorial? Commented May 17, 2019 at 18:42
  • @Mike Yes, it will work like Polymorphic fields, for example like commentable_id. I think I will have to change tables to use Polymorphic Relationships. But currently, I'm not sure how to pass a different model to LinksController. Commented May 17, 2019 at 18:58

1 Answer 1

1

You should add a source_type field to your link model for the polymorphic relationship.

$link->source_type = "tutorial" or "post"

The route may be something like:

Route::post('/{sourceType}/{sourceTypeId}/links', 'LinksController@store')->where(['sourceType' => 'posts|tutorials', 'sourceTypeId' => '[0-9]+']);

Then in your controller

public function store(Request $request, string $sourceType, int $sourceTypeId) {
    if ($sourceType == 'posts') {
        $source = Post::findOrFail($sourceTypeId);
    } elseif ($sourceType == 'tutorials') {
       $source = Tutorial:findOrFail($sourceTypeId);
    }

    $link = new Link;
    $link->user_id = auth()->user()->id;
    $link->source_id = $source->id;
    $link->source_type = substr($sourceType, 0, -1);
    $link->link = $request->link;
    $link->save();
}

I never used polymorphic relationships but this is something I may do.

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

3 Comments

Hi @Mike, thank you for your answer. This is the idea I had in my mind (Polymorphic Relationships) but I want to avoid to share my models with users, by that I mean, avoid using hidden inputs in request and model pass by URI. I'm looking for a way to distinct models in my controller without sending models names in the request. I think I can check URI route to see where it points and set model based on that, but it seems not elegant to me.
Ok yeah I think you can also just create two separate routes with two separate store functions and do regular route model binding. Not sure what the best solution is here either
Yea, but that will duplicate my code. I updated my post with other solution that might work, Explicit Binding.

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.