10

I have a statement like this:

App\User::with('client')->find(2)->makeHidden('client.phone_no');

I want to hide certain columns from a relation, but I can't do that with makeHidden(), because it only takes the arguments for the Model not the relation.

How can I hide some columns from the relation?

Tanmay
  • 3,009
  • 9
  • 53
  • 83

4 Answers4

20

If you don't want to hide the phone_no for all the requests by adding it to the hidden property, you could do something like this:

$user = App\User::with('client')->find(2);
$user->client->makeHidden('phone_no');
return $user;

As I stated in my comment to the original question: I found this method as well. I believe this should be the method you should use when you want to exclude columns more often. If you only want to exclude a column once, my solution should be sufficient.

Douwe de Haan
  • 6,247
  • 1
  • 30
  • 45
  • I think this is the cleanest approach since it has no extra hassle of subquerying and a dedicated scope. However as @JonasStaudenmeir pointed out, the`with()` call is redundant here. – Tanmay Aug 15 '18 at 05:22
  • @Eisenheim Not completely. If you're going to load the client, might as well eager load it. The second call to client will use the already loaded client. – Douwe de Haan Aug 15 '18 at 07:03
13

You can either hide the column in the query result (eager loading is unnecessary):

$user = User::find(2);
$user->client->makeHidden('phone_no');

Or you don't even get it from the database:

$user = User::with('client:id,user_id,...' /* other columns except phone_no */)->find(2);
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109
6

With accepts a callback to modify the query.

$users = User::with(['client' => function($query) {
        $query->select(['id', 'name']);
    }])->find(2);

You could also define default hidden attributes on your Client model

protected $hidden = ['phone_no'];
  • Returns null for client: `client: null` – Tanmay Aug 14 '18 at 13:39
  • 2
    depending on how this relationship is setup you may not be selecting the 'key' that links these models ... if client belongs to user you would need to be selecting that foreign key – lagbox Aug 14 '18 at 13:55
  • @lagbox You're right. If I don't specify a foreign key, I get null. But if I do specify the FK, it does work: `\App\User::with(['client' => function($query){$query->select(['user_id','name']);}])->find(2);` But I don't want to reveal the `user_id` either... – Tanmay Aug 15 '18 at 05:04
4

You can create a scope in your model and apply it in builder

Define these functions in your model

protected function columns(){
    return Schema::getColumnListing('clients');
}

public function scopeExclude($query, $value = array()) 
{
  return $query->select( array_diff( $this->columns(), $value) );
}

Now use it in query builder

App\User::with(['client' => function($query){
    $query->exclude(['phone_no']);
}])->find(2)
rkj
  • 8,067
  • 2
  • 27
  • 33
  • This should be the accepted answer because this filters the column while querying the database. And other methods are querying for all columns and filtering afterward which is not a good idea I guess. – Shoaib Khan Apr 16 '22 at 08:20