ETAN
ETAN

Reputation: 3182

checking another table for a field status eloquent

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

Answers (2)

benjosantony
benjosantony

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

Marcin Nabiałek
Marcin Nabiałek

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

Related Questions