Home > Enterprise >  Route model binding select specific columns with relation
Route model binding select specific columns with relation

Time:11-02

Route:

Route::get('/posts/{post}', [PostController::class, 'show']);

Controller:

public function show(Post $post){
    $postData = $post->load(['author' => function($query){
        $query->select('post_id', 'name');
    }])
    ->get(['title', 'desc', 'created_date'])
    ->toArray();
}

This returns all the posts in the database, While I only want to get the selected post passed to the show function.

So if I visit /posts/3, It should show data related to the post with id = 3, not all posts.

The result should be an array with only the selected post.

CodePudding user response:

Please don't use get() function on the model.

public function show(Post $post) 
{
    $post->load(['author:post_id,name']);
    dd($post->toArray());
}

Btw, the author shouldn't have a post_id, because author can have multiple posts. you should update the database structure or you are doing wrong in the controller.

CodePudding user response:

Since your goal is to load the author of the post, your code should look something like this:

public function show(Post $post){
   $post->load('author');
   $postData = $post->toArray();
}

If you really only want the columns post_id and name, you can do it like this:

public function show(Post $post){
   $post->load(['author' => function($query) {
       $query->select('post_id', 'name');
   }]);
   $postData = $post->toArray();
}

In case you need author more often on the Post model, than you NOT need it, you can load the relationship by default by adding $with to your Post model like described here:

class Post ... {
    protected $with = ['author'];
    ...
}

CodePudding user response:

When you are inside the Controller you already have the Post you want. If you call get you are getting all posts with a new query.

To select specific columns from a relationship, you can do it like this:

public function show(Post $post)
{
   $post->load('author:id,name,age'); // load columns id, name, age from author
}

Notice that including the id is required.

To specify columns for the Post, there's no way to do it per route, the only way is to override how Laravel resolves the implicit binding. For that, you can add this in your Post model class:

public function resolveRouteBinding($value, $field = null)
{
    return $this->whereKey($value)->select(['id', 'body', 'author_id'])->firstOrFail();
}

Notice that including the author_id is required to load the Author afterwards inside the Controller method. Also keep in mind this will affect all routes where you implicitly load a Post.

  • Related