Laravel - Property does not exist on this collection instance - php

On my Users model I have a query that gives me "Property [manager_id] does not exist on this collection instance" error. I suppose this is because the collection of expiringUsers does not have a single property manager_id, but I'm not sure how to loop through expiringUsers in the query.
What I'm trying to return is a collection of managers where their ID matches the expiring manager_id.
public function scopeManagers()
{
$expiringUsers = $this->ExpiringContractors(); // This returns a collection of users
return $mangers = $this->where(function($query) use ($expiringUsers){
$query->where('id', $expiringUsers->manager_id);
})->get();
}

You already said it yourself... If $expiringUsers is a Collection, you can't access manager_id without looping, but you actually don't have to in this case. If you want to query id for those that match any manager_id, you can do that via a whereIn() clause, combined with the pluck() method:
$query->whereIn('id', $expiringUsers->pluck('manager_id'));
And, your code can be simplified to:
public function scopeManagers(){
return $this->where(function($query){
$query->whereIn('id', $this->ExpiringContractors()->pluck('manager_id'));
})->get();
}
Note: ExpiringContractors should really be expiringContractors; function names are generally camelCase.

Related

whereIn function within a sub query within eloquent doesnt filter any records

I have a Prize, Ticket and User model. A prize can have many tickets, and a ticket can only be associated to one User.
Each Prize will have one Winning Ticket, what I am trying to do is list all my Users that have a winning Ticket like so:
$winning_tickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$users = User::with(['tickets' => function($query) use ($winning_tickets) {
$query->whereIn('id', $winning_tickets);
}])->get();
$winning_tickets returns an array of winning ticket ids, but the $users collection returns ALL my users, even users that have no ticket records.
Can anyone explain what I am doing wrong?
with() doesn't actually filter the User Collection being returned. To do that, you need to use whereHas():
$winningTickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$users = User::whereHas('tickets', function($query) use ($winningTickets) {
$query->whereIn('id', $winningTickets);
})->get();
Now, the $users Collection will only contain User records that have one or more Ticket records matching the given ticket_winner_id in $winning_tickets.
If you need to, you can use both with() and whereHas() to filter and eager load the associated Ticket records:
$winningTickets = Prize::WinnerSelected()->get('ticket_winner_id')->pluck('ticket_winner_id');
$filterClause = function ($query) use ($winningTickets) {
return $query->whereIn('id', $winningTickets);
};
$users = User::with(['tickets' => $filterClause])
->whereHas('tickets', $filterClause)
->get();
Define the the function ($query) as a reusable clause to avoid repetition, and voila!
Sidenote, you don't need to chain ->get() into ->pluck(); both Builder and Collection classes have a ->pluck() method, so this is valid:
$winningTickets = Prize::WinnerSelected()->pluck('ticket_winner_id');

Dynamic Property call giving error (Property [game] does not exist on the Eloquent builder instance.)

I have two models: Game and Game_Assignment. Game_Assignment tells whose job it is to play a game.
I am trying to count the number of Game_Assignment's that a user has their id on that also have a specific value on the Game model that it relates to. I'll just get into the Models/the code
Game Model Relationship:
public function assignments() {
return $this->hasMany('App\Models\Game_Assignment', 'game_id');
}
Game_Assignment Relationship:
public function game() {
return $this->belongsTo('App\Models\Game', 'game_id');
}
Where things are going wrong (in a queue job, if that makes a difference)
$gamesDue = Game_Assignment::where('statistician_id', $statistician->id)->game->where('stats_done', '!=', 'yes')->count();
I have also tried the following two things, neither worked:
$gamesDue = Game_Assignment::where('statistician_id', $statistician->id)->game()->where('stats_done', '!=', 'yes')->count();
and...
$gamesDue = Game_Assignment::where('statistician_id', $defaultStatistician->id)->with(['games' => function($query) {
$query->where('stats_done', '!=', 'yes');
}])->count();
None of these work, and the first one I showed threw an error:
Property [game] does not exist on the Eloquent builder instance.
Anyone have an idea of where I am going wrong? I am using this link as my reference https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
When using the query builder of your Game_Assignment model, you cannot simply switch context to the query builder of Game. You can only call ->game() or ->game after you retrieved one or many model instances of Game_Assignment with first() or get().
So, in your particular case, you were looking for whereHas('game', $callback) (where $callback is a function that applies constraints on the foreign table) in order to add a constraint on the foreign table:
use Illuminate\Database\Eloquent\Builder;
$gamesDue = Game_Assignment::query()
->where('statistician_id', $statistician->id)
->whereHas('game', function (Builder $query) {
$query->where('stats_done', '!=', 'yes');
})
->count();
Side note: a column (stats_done) that seems to hold a boolean value (yes/no) should be of boolean type and not string/varchar.

Laravel fetch data from model where the condtions is from another model

I have a table called List which i planned to be displayed into view with this command : $lists= List::with('user', 'product.photodb', 'tagCloud.tagDetail')->get();. But, i want the data displayed is only those that has TagID equal to the one user inputted. Those data can be retrieved from TagCloud table.
What i am currently doing is :
$clouds = TagCloud::select('contentID')
->where('tagDetailID', '=', $tagID)
->get();
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->where('id', '=', $clouds->contentID)
->get();
But when i tried to run it, it only return a null value, even though when i am doing return $clouds, it does returned the desired ID.
Where did i do wrong ? Any help is appreciated !
A couple of gotchas with your current solution.
Using get() returns an Illuminate\Database\Eloquent\Collection object. Hence you can't use $clouds->contentID directly since $clouds is a collection (or array if you prefer). See Collection Documentation.
where(...) expects the third parameter to be a string or integer, aka single value. Instead, you are passing a collection, which won't work.
The correct way is to use whereHas() which allows you to filter through an eager loaded relationship.
Final Code:
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->whereHas('tagCloud',function($query) use ($tagID) {
return $query->where('contentID','=',$tagID);
})
->get();
See WhereHas Documentation.
What you want is whereHas()
$list = List::with(...)
->whereHas('relation', function($q) use($id) {
return $q->where('id', $id);
})->get();
Apply Where condition in you tagCloud model method tagDetail
public function tagDetail(){
return $q->where('id', $id);
}

Laravel query builder returns object or array?

I'm building a very simple web app with Laravel.
I've built two separate Controllers, which each return two separate views, as follows:
ProfileController:
class ProfileController extends BaseController {
public function user($name)
{
$user = User::where('name', '=', $name);
if ($user->count())
{
$user = $user->first();
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
Return View::make('profile')
->with('user', $user)
->with('workout', $workout);
}
return App::abort(404);
}
}
WorkoutController:
class WorkoutController extends BaseController {
public function workout($name)
{
$workout = DB::table('workouts')->where('name', '=', $name)->first();
if ($workout)
{
Return View::make('add-exercise')
->with('workout', $workout);
}
return App::abort(404);
}
}
What is confusing me is what I had to do in order to pass a single workout object to each view. As you might have noticed the query builders for workout are different:
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
and
$workout = DB::table('workouts')->where('name', '=', $name)->first();
On the profile view, I get an object using the ->get(); method, but on the add-exercise view, I must use ->first(); or I will otherwise get an array with only one index, where I can then access the object, i.e. $workout[0]->name instead of $workout->name.
Why is this? Shouldn't I be able to use either get and/or first in both controllers and expect the same type of result from both since I want the same thing from the same table?
get() returns a collection of objects every time. That collection may have 0 or more objects in it, depending on the results of the query.
first() calls get() under the hood, but instead of returning the collection of results, it returns the first entry in the collection (if there is one).
Which method you use depends on what you need. Do you need the collection of all the results (use get()), or do you just want the first result in the collection (use first())?
Model::find(numeric); returns a object
Model::whereId(numeric)->first(); returns a object
Model::whereId(numeric)->get(); - returns a collection
Model::whereId(numeric); - returns a builder

Laravel 4: Why can I access a model accessor when using first() but not take()?

I'm trying to return a number of recent posts from my database, ordered by date, and I then want to select and return the month the post was made in via my model's getMonthAttribute() accessor method. To accomplish this, I'm using scoped queries. This all works fine when I use first() to return just a single result, but when I use take(1) or take() with any valid numerical input, I receive the following error:
Undefined property: Illuminate\Database\Eloquent\Collection::$month
In my model, I have this month attribute accessor:
public function getMonthAttribute() {
return Carbon::createFromFormat('Y-m-d',$this->date)->format('F');
}
and my scoped query to return a variable number of recent posts (the portion of my code that is not working):
public function scopeRecent($query, $take = 1) {
// Replace take with first and I no longer receive the above error.
return $query->where('status', '=', '1')->orderBy('date', 'DESC')->get()->take($take);
}
Here is how I'm accessing my data in the view:
{{ $post->recent()->month }}
Any suggestions?
This is because ->first() returns an eloquent model. Using the get() method returns an eloquent collection (an array of eloquent models) instead. So you must run a foreach over the collection like so:
#foreach($post->recent() as $recent)
{{$recent->month }}
#endforeach

Categories