I have made in laravel v.8. a database query (eloquent) that returns several columns.
$wgName = Auth::user()
->join('wg_groups', 'users.wg_group_id', '=', 'wg_groups.id')
->get();
Now I want in my html view that the wg_name is displayed if it is set.
I have tried the following four things:
#if(isset($wgName->wg_name))
<h1>{{$wgName->wg_name}}</h1>
#endif
Here simply nothing is displayed
#if(isset($wgName))
<h1>{{$wgName->wg_name}}</h1>
#endif
Exception: Property [wg_name] does not exist on this collection instance.
#isset($wgName)
<h1>{{$wgName->wg_name}}</h1>
#endisset
Exception: Property [wg_name] does not exist on this collection instance.
#isset($wgName->wg_name)
<h1>{{ $wgName->wg_name }}</h1>
#endisset
Here simply nothing is displayed
I have no idea why it doesn't work and I didn't find anything in the documentation.
https://laravel.com/docs/8.x/eloquent
Calling ->get() on Query builder will give you a Collection instance containing multiple users. And there is definitely no wg_name on Collection instance so the result is always false.
Try using first():
$wgName = Auth::user()
->join('wg_groups', 'users.wg_group_id', '=', 'wg_groups.id')
->first();
Currently you are selecting all users from the database. This happens due to Eloquent redirecting non existing methods to a new query builder instance.
By changing the query to use the first() method instead of the get() method you'll receive only one record, but this would probably not be the correct record as it does not take the current user into account.
There are multiple ways to solve this issue
1: Just use a simple query to receive the wg_name.
$wgName = DB::table('wg_groups')->find(Auth::user()->wg_group_id);
2: Add a global scope to your User model to always join the wg_group data when looking up a user.
You could add the following method to your User model to always join this table when querying the users table.
protected static function booted()
{
self::addGlobalScope('include_wg_group', function (\Illuminate\Database\Eloquent\Builder $query) {
$query->join('wg_groups', 'users.wg_group_id', '=', 'wg_groups.id');
});
}
Now everytime you receive an instance of a User it will have all the info of wg_groups joined into it. This allows you to just grab the name like this:
$wgName = Auth::user()->wg_name;
Related
In my user model (App\User.php), I declare following relationship:
public function actionables() {
return $this->hasMany(Actionable::class, 'owner_id', 'id');
}
In my migration scheme for the actionables table, I specify following foreign key:
$table->foreign('owner_id')->references('id')->on('users')->onDelete('cascade');
When I call
{{ auth()->user()->actionables->where('act_type', 'order')->latest()->content }}
In a blade view, I get following error message:
Method Illuminate\Database\Eloquent\Collection::latest does not exist.
I´ve tried using ->get() and using other way´s of accessing the user model (Auth::user), but nothing has solved the problem so far.
The distinction that the other answers are glossing over is using the query builder vs using a collection. When you call the relationship using a property Eloquent will fetch all the results then return a collection (which is basically just a beefed up array). So when you do
auth()->user()->actionables
Laravel executes the SQL Query then returns all the results as a collection.
SELECT * FROM actionables WHERE owner_id = ?
The collection class has a where method that functions similarly to the query builder method, but it's important to realize that it's performing the search in PHP not SQL because the query has already been executed and can't be changed anymore. latest() exists on the query builder, but not the collection which is where your error is coming from.
To leverage the relationship in the query builder you need to call the relationship as a function. user()->actionables()
auth()->user()->actionables()->where('act_type', 'order')->latest()->first()
The above will execute the SQL query then return just the record you're looking for.
SELECT * FROM actionables WHERE act_type = order AND WHERE owner_id = ? ORDER BY created_at DESC LIMIT 1
latest not exist not within Collection methods.
to get the last element of your database query you should apply this query:
*Note that you should have created_at within the Actionable table.
auth()->user()->actionables()->where('act_type', 'order')->orderBy('created_at', 'desc')->first()->content
You should use the query builder actionables() not the collection actionables, i.e:
{{ auth()->user()->actionables()->where('act_type', 'order')->latest()->first()->content }}
It must be ->last() not ->latest()
{{ auth()->user()->actionables->where('act_type', 'order')->last()->content ?? ""}}
Collection does not have the latest method, it's the query builder that has that method.
Try last instead.
Ref: https://laravel.com/docs/5.8/collections#available-methods
I'm having problems fetching data using Model::find() with two conditions. I want to return one record that has the given member_id AND its role is guest:
$member = CalendarMembers::find(["member_id" => $r->member_id, "role" => "guest"]);
But this isn't working. I have one user that when created, a new register is added to calendar_members table specifying this user as parent, yet, when attempting to fetch this user automatically created by just giving the member_id, it will be fetched, which SHOULD NOT.
I cannot use other ways such as:
$member = \DB::table("calendar_members")->where([ ["member_id", "=", $r->member_id], ["role", "=", "guest"] ])->first();
Because then $member->delete() or $member->destroy() will throw an error saying either delete or destroy do not exist.
The find() method uses ID to get a record. You need to use the where() and first() methods:
CalendarMembers::where(['member_id' => $r->member_id, 'role' => 'guest'])->first();
you should use where for multiple conditions and get the first row with first() method, find is basically an alias for wehre('id', $id)
To make it clear, find() method will perform database query and returns single model object as result. so find is equal to,
Model::where('id', 1)->first().
find() returns Model object and where() returns QueryBuilder. But you can directly perform on query Builder without fetching model, like,
Model::where('id', 1)->delete().
REF : https://laravel.com/docs/5.6/eloquent
Building a chat application with a dashboard and am trying to get a notification of the last message the that other user sent.
Here is my Model relationships:
public function messages() {
return $this->hasMany('App\Message', 'author_id');
}
public function lastMessage() {
return $this->hasMany('App\Message', 'recipient_id')->orderBy('created_at', 'DESC')->groupBy('author_id');
}
On thing I cant figure out is instead of returning the last message as it should be sorted by using orderBY, it returns the first record of that group that exists in the database.
Looked around online but cant seem to find any info on this. The only thing I found is a post by someone who said that orderBy and groupBy in laravel don't play well together.
Any help is appreciated!
Instead of redefining the relationship in lastMessage, you might try calling messages from it and then running your query from that.
Without seeing more of your model schema (ie: where are these relationships defined??), this might not be perfect, but it's a start:
public function lastMessage()
{
return $this->messages() // <-- Notice the ()...this creates a query instead of immediately returning the relationship
->where('recipient_id', $this->id) // Not sure if this is correct, might need to adjust according to how you have defined the tables
->orderBy('created_at', 'desc')
->first();
}
It will query the messages relationship with the chained constraints that are listed. And by returning first() it returns only one record as opposed to a collection.
I'm trying to get a single column value from the first result of a Model's belongsToMany relationship query, as i'm returning the ->first() result of the relationship I was hoping $code->reward->title would work but it doesn't.
I get an Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation error
What I'm trying to do is the get the title of the current reward that is linked to a specific code - the code_reward pivot table has a valid_from and expires_at date as the reward linked to a code will change as time goes by, hence the need to get the currently active reward for that code.
Here's my code:
Model: Code
public function rewards()
{
return $this->belongsToMany('App\Reward')->withPivot('valid_from', 'expires_at')->withTimestamps();
}
public function reward()
{
$now = Carbon::now();
return $this->rewards()
->wherePivot('valid_from', '<', $now)
->wherePivot('expires_at', '>', $now)
->first();
}
Controller: CodeController
public function index()
{
$codes = Code::all();
return view('codes/index')->with('codes', $codes);
}
View: Codes/index
#foreach ($codes as $code)
{{$code->id}}
{{$code->reward->title}}
#endforeach
Any help is really appreciated!
Update
Unfortunately both suggestions below ($code->reward()->title and getRewardAttribute() return an Trying to get property of non-object error.
If I remove ->first() from the Code->reward() method and replace $code->reward->title with $code->reward->first() in the view it echoes out the whole reward model as json, however $code->reward->first()->title still returns the Trying to get property of non-object error
Update 2
If I do {{dd($code->reward->title)}} in the view I get the reward title but if I just do {{$code->reward->title}}, I don't!
AND the $code->reward->title works as expected in a #Show view, so could it be that the collection of codes supplied by the controller's #index method isn't passing the necessary data or not passing it in a necessary format??
SOLVED
The issue was caused by one of the $code->rewards in the foreach loop in the index view returning null! The first one didn't, hence the dd() working but as soon as the loop hit a null it crashed.
Once I wiped and refreshed the db (and made sure my seeds where adding only valid data!) it worked. Doing {{$code->reward ? $code->reward->title : ''}} fixed the issue. Grrr.
Your statement is failing because $code->reward->title tells Laravel that you have defined a relationship on your Code model in a method called reward(). However, your relationship is actually defined in the method rewards(). Instead, reward() is a custom method on the model that you have made up. Calling it as a method and not a relation is the quickest way to get what you want.
{{$code->reward()->title}}
As #andrewtweber points out below, you could also make your custom reward() method into an attribute accessor. To do that, just rename the function to getRewardAttribute() and then you can call it in your view like you originally did.
Alternatively, you could get rid of that reward() method entirely and move all of that logic to the controller, where it probably makes more sense. You'd have to use constrained eager loading to pull that off. So in your controller you'd have something like this:
$codes = App\Code::with(['rewards' => function ($query) {
$query->wherePivot('valid_from', '<', $now)
->wherePivot('expires_at', '>', $now);
])->get();
Of course, this would return all of your filtered codes. This is because you cannot apply a sql limit inside a nested eager relationship as outlined here. So in your view, you would then have to do something like this:
{{$code->rewards->first()->title}}
However, it will be simpler to go with my first solution, so that's entirely up to you.
Try to set this method in Code Model, because query builder treats valid_from and expired_at as string, not date?
public function getDates()
{
return ['valid_from','expired_at'];
}
I'm learning Laravel and it uses OOPS concepts. Now I'm finding it hard to understand the real difference between array and objects. I actually know what an array and object is.
Array can hold more than one variable where as an object is an independent entity which has its own arguments and methods. We usually use foreach loop to loop through them.
In laravel, data is returned in the form of model instance as object. When the query response has multiple results, then data is returned in the form of an array which contains objects. I was trying to understand Collection Class used in laravel.
Codebright reference says
The Collection class itself, is merely a wrapper for an array of objects, but has a bunch of other interesting methods to help you pluck items out of the array.
Now coming back to my confusion. I was using different methods like all() and first() methods to fetch the result. But sometimes when i used arrow (->) to fetch the data using a foreach loop, from an object (contained in an array), it showed an error that says something like it is a non object. Then I used square brackets and the data was displayed.
I know we use [] to fetch data from arrays and we use -> to fetch data from objects. But I'm still confused about Laravel. Can someone clearly state the difference between them in reference to Collection class used in Laravel?
Edit:: The confusion began while using this code:
foreach($self_conversations as $self_conversations_fetch){
//fetching each conversation id
$conversation_id = Conversation::find($self_conversations_fetch->conversation_id);
$user_id = array();
//fetching each conversation member's id
foreach($conversation_id->conversationsMember as $conversationmembers)
$user_id[] = $conversationmembers->user_id;
$self_id = User::where('email', Session::get('email'))->first()->id;
$self_id_array = array($self_id);
$friend_id_array = array_diff($user_id, $self_id_array);
foreach($friend_id_array as $friend_id) array_push($friend_ids, $friend_id);
$conversations_reply_obj = ConversationReply::where('conversation_id', $self_conversations_fetch->conversation_id)->orderBy('updated_at', 'desc')->first();
$conversations_reply[] = $conversations_reply_obj['reply'];
}
As you can see, i have used square brackets to fetch the data(in the last line).
$conversations_reply[] = $conversations_reply_obj['reply'];
i was expecting arrow to work here
Actually the Collection class is a wrapper object which returns a collection of objects. For example, if you have a Model for example, User then you may use it in various ways, to get all records you may use User::all() and to get a single record you may use User::find(1) and there are other ways as well.
If you use all(), get() methods then you'll get a collection object, it means a collection of User models when you use these methods on User model and remember all() and get() always returns a collection of models even if there is only one model in it, so check this examaple:
$users = User::all(); // returns a collection
You may use first() method of Collection object like this:
$users = User::all();
$users->first();
Or directly just:
$user = User::first();
You may also use last to get the last item/model from the collection. You may also use get() like this:
$users = User::all();
$users = User::get(0) // to get first item/model
$users = User::get(1) // to get second item/model
You may also use a loop like this:
$users = User::get(); // same as all
// pass the collection to the view
return View::make('users.index')->with('users', $users);
Now in your views/users/index.blade.php view you may use a loop like this:
#foreach($users as $user)
{{ $user->username }}<br />
{{ $user->email }}<br />
#endforeach
It's important to knoe that, all() and get() methods returns a collection and first() and find(id) returns a single model object, so if you have a single model then you may directly use it like this:
$user = user::find(1); // 1 is id for example
return View::make('users.index')->with('user', $user);
In your view you may use:
{{ $user->email }}
You may use an object using -> for example $user->name and an array using $user['name'] but in this case you may use both syntax because Laravel's Eloquent/Model implements ArrayAccess (along with others) interface so every model that extends Eloquent could be used using both array and object syntax to access properties. So, following is possible:
$user = User::where('username', 'me')->get();
return View::make('users.index')->with('user', $user);
In the view you may use:
{{ $user->name }}
{{ $user['name'] }}
For better understanding of the Collection class and it's methods check the source code, you may find it at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php of your local installation and it extends Illuminate/Support/Collection.php class. Check both classes. You may also read this article, it'll help you more.
I think I know the source of your problem, as I've been having to work around it. If you are using the arrow notation on a model object and there is no record in the relationship, then you'll get the "non-object" error. For example, if you have the line
$student->school->school_name
and a given $student doesn't have a school object, you'll get the non-object error. I typically add checks for empty($student->school) or empty($student->school_id) or the like to avoid this when I run into it (or heaven forbid forsee the problem when doing my initial coding pass).
EDIT: So, to clarify, Laravel doesn't say "oh, there's a relationship there, so school is an object which happens to be empty, so I'll return null for school_name", it says "there's no school, so ->school_name is an invalid call to an object property"