I've currently got a few models that have many to many relationships via laravel. here's the structure:
users
id
username
...
games
id
title
...
game_user
game_id
user_id
system
Now, my models look a little like this:
<?php
class Game extends Eloquent
{
/**
* A game is owned by many users
*
* @return mixed
*/
public function user()
{
return $this->belongsToMany('User')->withPivot('system');
}
<?php
class User extends Eloquent
{
/**
* A user has many games.
*
* @return mixed
*/
public function games()
{
return $this->belongsToMany('Game')->withPivot('system');
}
Now, this all works fine. However, I wish to use a mutator upon the system field from the pivot table. I can't find any documentation on this and the following (in both the User and Game models) does not work:
public function getSystemAttribute($val)
{
return $val.' Testing';
}
I haven't tested but this should work.
public function getSystemAttribute($value)
{
return $this->pivot->system . ' Testing';
}
...
foreach ($user->games as $game)
{
echo $game->system;
}
The value getting passed in is being pulled from the models attributes. There is no system attribute so you should get NULL. We can just ignore that and pull the value from the pivot table directly.
You need to define an accessor for the pivot's system
property and add the attribute name to the appends property on the model. The whole procedure follows
1) Define an accessor in the parent Model from where we want to access the attribute:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Game extends Model
{
/**
* The accessors to append to the model's array form.
*
* @var array
*/
public function getSystemAttribute() // the name can be anything e.g getFooAttribute
{
return $this->pivot->system;
}
}
2) (to avoid getting NULL!) Add the attribute name to the appends property on the model (see here).
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['system'];
}
3) Now you can access that new created system
attribute from the parent Model:
$user = App\User::find($id);
foreach ($user->games as $game)
{
echo $game->system;
}
Of course, like with every accessor, you might also "alter" the value of the pivot table before accessing it, for instance:
public function getSystemAttribute()
{
return $this->pivot->foo .'Hello word!'; //append the ""Hello word!" string to the end of the `foo` attribute value
}
Finally notice that the name of the accessor can be anything like getFooAttribute
, getBarAttribute
, getBarBazAttribute
. In that case the append would be protected $appends = ['foo'];
and you could again access the pivot's foo
property via the parent Model like $game->foo
I found this question interesting, so I started playing around with the code.
If you need to access a specific entry, here's my solution:
public function getSystemAttribute($game){
foreach($this->games as $value){
if($value->id==$game->id){
$value->pivot->system = 'foo';
$value->pivot->save();
}
}
}
which you can simply call with:
$user->getSystemAttribute($game)
Regarding the accessor, I couldn't find any other way without itarating the collection. There are prettier ways of iterating the collection, but this was not the scope of this question. From the documentation, you can see how any attribute of the pivot table can be accessed.
Hope this helps
If you would like to be able to insert your mutated system
attribute on your Response's (JSON, etc.), then you should add the following to both Models (game + user).
protected $appends = array('system');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With