Reputation: 3182
Okay I have a custom field name is_friend
I have 3 tables
1. Users
2. Workers
3. Friends
As you guess a worker belongs to a user, a friend belongs to a worker.
My query, I want to check whether if a worker is a friend of the current signed in user
Friends schema:
Schema::create('tweets', function(Blueprint $table)
{
$table->increments('id');
$table->integer('targetID');
$table->integer('ownerID');
$table->timestamps();
}
As you can see from the schema, the targetID is the friend id of the worker, ownerID is the signed in user.
My query:
$worker = Worker::get('name');
Inside my worker's model
class Worker extends Eloquent{
protected $appends = array('is_friend');
public function user(){
return $this->belongsTo('user');
}
public function getIsFriendAttribute(){
if(Friend::where('targetID', $this->attributes['id'])
->where('ownerID', Auth::user()->id)->first()){
return true;
} else {
return false;
}
}
}
I am using a custom accessor to get this custom field. It works but it is pretty ugly, If i query 20 workers, there will be 20 queries just to check this status.
On view, i can access like
@if($worker->is_friend)
Your friend
@endif
Upvotes: 2
Views: 741
Reputation: 537
OK I think this issue(the n+1 problem) can be solved using eager loading with constraints.
First define a friends relation in the Worker Model . as such
class Worker extends Eloquent{
...
// This will get all the friends
public function friends(){
return $this->hasMany('Friend','targetID');
}
...
}
We use eager loading to deal with the n +1 problem. Click here and scroll down to Eager Load Constraints for documentation
// We use Eager loading constraints so that only two db queries are executed instead of n+1
$workers = Worker::with(array('friends' => function($query)
{
// So we constraint the ownerId to be current user id
$query->where('ownerID', Auth::user()->id);
}))->get();
Now on the view
@foreach ($workers as $worker)
@if(count($worker->friends) >0)
Your friend
@endif
@endforeach
Upvotes: 1
Reputation: 111839
You can add the following relation to your Worker
model:
public function friendsNumber()
{
return $this->hasMany('Friend','targetID')
->selectRaw('targetID, count(targetID) as count')
->where('ownerID', Auth::user()->id)
->groupBy('targetID');
}
and now add the following accessor to the Worker
model:
public function getIsFriendAttribute()
{
if (!array_key_exists('friendsNumber', $this->relations)) {
$this->load('friendsNumber');
}
$related = $this->getRelation('friendsNumber')->first();
return ($related && $related->count) ? true : false;
}
now you should be able to use:
$workers = Worker::with('friendNumber')->get();
foreach ($workers as $worker) {
echo $worker->name;
if ($worker->is_friend) {
echo " is your friend";
}
echo "<br />";
}
Upvotes: 1