sweijdt's avatar
Level 25

makeHidden for relationship columns?

I got the following:

$item = Item::with('products')->whereHas('products', function ($query) use ($slug) {
   $query->where('slug', '=', $slug);
})->firstOrFail();

   return view('site.item.show')->withItem($item->makeHidden(['created_at', 'updated_at']));

I'm trying to hide some columns. I do it on the fly because I want to use those columns in a different view. So sometimes they need to be included and sometimes not. This works. However, not for the relations. Products still shows created_at and updated_at. How do you hide/visible them on the fly?

0 likes
12 replies
InaniELHoussain's avatar
return view('site.item.show')->withItem($item->except(['created_at', 'updated_at']));
sweijdt's avatar
Level 25

that doesn't do anything.. I've tried it.

It's not a collection.. it's an eloquent model ;-).. except() only works on a collection as far as I know.

InaniELHoussain's avatar

@sweijdt here is how it can be done

In your Model

protected $columns = ['id','pseudo','email']; // add all columns from you table

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

how to use it

$users = User::where('id', $id)->exclude(['pseudo', 'email', 'age', 'created_at'])->toArray();  
sweijdt's avatar
Level 25
Item {#196 ▼
  #fillable: array:1 [▶]
  #connection: null
  #table: null
  #primaryKey: "id"
  #keyType: "int"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:4 [▶]
  #original: array:4 [▶]
  #relations: array:1 [▼
    "products" => Collection {#202 ▼
      #items: array:2 [▼
        0 => Product {#205 ▼
          #fillable: array:4 [▶]
          #connection: null
          #table: null
          #primaryKey: "id"
          #keyType: "int"
          #perPage: 15
          +incrementing: true
          +timestamps: true
          #attributes: array:9 [▶]
          #original: array:9 [▶]
          #relations: []
          #hidden: []
          #visible: []
          #appends: []
          #guarded: array:1 [▶]
          #dates: []
          #dateFormat: null
          #casts: []
          #touches: []
          #observables: []
          #with: []
          +exists: true
          +wasRecentlyCreated: false
        }
        1 => Product {#206 ▶}
      ]
    }
  ]
  #hidden: []
  #visible: []
  #appends: []
  #guarded: array:1 [▶]
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  +exists: true
  +wasRecentlyCreated: false
}
sweijdt's avatar
Level 25

Thanks, but this one also doesn't work. For the query in the closure.. I tried making another scope for Product, but it doesn't work in the closure I guess.

       $item = Item::with('products')
            ->whereHas('products', function($query) use ($slug) {
                $query->exclude(['created_at', 'updated_at'])->whereSlug($slug);
            })
            ->exclude(['created_at', 'updated_at'])
            ->firstOrFail();

I just get the result with the two columns on products. It did remove them from Item though.

InaniELHoussain's avatar
$item = Item::with('products', function($query) {
    $query->exclude(['created_at', 'updated_at']);
    })
        ->whereHas('products', function($query) use ($slug) {
            $query->whereSlug($slug);
        })
        ->exclude(['created_at', 'updated_at'])
         ->firstOrFail();
sweijdt's avatar
Level 25

That causes

ErrorException in Builder.php line 1150:
explode() expects parameter 2 to be string, object given
InaniELHoussain's avatar
$item = Item::with('products', function($query) {
        $query->select(['column1', 'column2', ...]); // in the queryBuilder you have to select them manulally
 })
      ->whereHas('products', function($query) use ($slug) {
            $query->whereSlug($slug);
        })
        ->exclude(['created_at', 'updated_at'])
        ->firstOrFail();
1 like
sweijdt's avatar
sweijdt
OP
Best Answer
Level 25

this part didn't work:

Item::with('products', function($query) {
        $query->select(['column1', 'column2', ...]); // in the queryBuilder you have to select them manulally
 })

it will raise this exception:

ErrorException in Builder.php line 1150:
explode() expects parameter 2 to be string, object given

I finally got it:

        $item = Item::with(['products' => function($query) {
            $query->select(['name', 'id', 'item_id', 'slug']);
        }])
            ->whereHas('products', function($query) use ($slug) {
                $query->whereSlug($slug);
            })
            ->exclude(['created_at', 'updated_at'])
            ->firstOrFail();

thanks for the help. I was ready to give it up. But with @InaniELHoussain directions I got it.

2 likes
LytraX's avatar

If we want to hide fields that are required to load the related model, like foreign keys, then we can't use exclude or other query altering methods.

For example we have profiles table that it has a user_id foreign key, and now we want to load users with profile and make the useless user_id hidden for profile.

We can do this using:

auth()->user()
    ->load('profile:id,user_id,balance,currency')
    ->makeHidden('user_id');

Then auth()->user()->profile will have user_id field hidden.

And that's because if we do ->load('profile:id,balance,currency') (or with('profile') even), then the foreign key user_id won't be loaded, thus we'll get nothing in return.

Please or to participate in this conversation.