Adam
Adam

Reputation: 1309

Return a Boolean instead of the whole collection

The Stack model can have "user progress", users can "clear" stacks. And that progress is stored in the Progress model.

Progress model:

public function stack(){
    return $this->belongsTo(Stack::class);
}

It would be neat if it was possible to fetch all stacks, and if the user has "cleared" it or not, with a boolean true or false. I don't won't to fetch all data corresponding to the progress. So I have tried setting up a "finished" relation on the Stack model

public function finished(){
    return $this->hasOne(Progress::class) ? true : false;
}

But this setup gives me the following error Call to a member function addEagerConstraints() on boolean.

This is how I call the relationship at the moment

    $user = \App\Stack::with(['finished' => function($q){
        return $q->where('user_id', auth()->user()->id);
    }])->get();

But that returns the whole collection, and that is not necessary. The expected result should be like:

{
"id": 5,
"user_id": 2,
"subject_id": 2,
"name": "tstar igen",
"slug": "tstar-igen",
"description": "asdasd",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": true/false
},

So lets say that here is an relation entry in in the progress table for the stack above.

+----+---------+----------+
| id | user_id | stack_id |
+----+---------+----------+
|  1 |       1 |        5 |
+----+---------+----------+

So when fetching the stacks, with relation finish. The finished column should be true or false. So the return from Stack, with relation finished should be like the following. Notice the finished column changed to false on the last stack, because the relation is not present in the progress table.

{
"id": 5,
"user_id": 2,
"subject_id": 2,
"name": "tstar igen",
"slug": "tstar-igen",
"description": "asdasd",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": true
},
{
"id": 6,
"user_id": 2,
"subject_id": 2,
"name": "another stack",
"slug": "another-stack",
"description": "This is a test stack for all the stacks out there",
"image": null,
"created_at": "2017-10-06 08:27:36",
"updated_at": "2017-10-06 08:27:36",
"finished": false
},

Upvotes: 1

Views: 1845

Answers (3)

Your model

public function progress(){
    return $this->hasOne(Progress::class);
}

Your controller

...
$stacks->load('progress');

resource

'finished' => $this->whenLoaded('progress')->isNotEmpty()

Upvotes: 0

Andriy Lozynskiy
Andriy Lozynskiy

Reputation: 2604

You can try withCount that counts your related models. But it will return number of related models not boolean. Here is an example:

Stack.php

public function progress(){
    return $this->hasOne(Progress::class);
}

then:

 \App\Stack::withCount('progress')->get();

Now results have count_progress attribute with number of related 'Progress' models. Because your relation is hasOne it should be 0 or 1.

Upvotes: 2

omitobi
omitobi

Reputation: 7334

You are almost done, You have your relationship setup well except for the boolean stuffs, remove it:

public function finished(){
    return $this->hasOne(Progress::class);
}

Then when you need to check you can use has or whereHas relationship method:

$stack = \App\Stack::whereHas('finished', function($q){
    return $q->where('user_id', auth()->user()->id);
})->get();

Based on your need thats the best I could conceive. I think this should be sufficient.

It would do well to learn how has and whereHas works. But just to summarize: has simply is like whereHas except that it checks if there is at least one model related to the first model, and the other helps you to make more advanced constraints as shown in the example I gave.

Upvotes: 1

Related Questions