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
Related
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;
ErrorException:
stripos() expects parameter 1 to be string, object given
For the groupBy() call in the with() method
$user = User::with([
'pricelists' => function($query) {
$query->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
}
])->where('id', $id)->get();
I already saw a few posts talking about how to manage this problem and that it shall not be possible to use groupBy() in eloquent but I do not really understand why...
To be clear:
User and Pricelist model got a many-to-many relationship with the default timestamps() method. I am trying to get the downloaded pricelists grouped by their months they were downloaded from the current user.
After a few attempts I just deleted the above shown => function($query... statement from the with() method and just left the with(['pricelist']) to fetch all datasets and tried this:
$user->pricelists = $user->pricelists->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
return $user->pricelists;
And it works fine and returns an array with multiple arrays for each month... But returning it like this:
return $user;
returns just 1 array with all entries... I do not really get the sense behind it right now...
The two groupBy() method that you are using in the two code you provide are totally different methods.
The first groupBy() where you use it in the callback is actually being called by $query which is a query builder object. The groupBy() here is used to add SQL GROUP BY Statement into the query. And as per the documentation, it only take string variables as parameter.
The groupBy() in your second code is being called by $user->pricelists which is a laravel eloquent collection. The groupBy() method here is actually from the base collection class and is used to group the items inside the collection into multiple collections under the different key defined by the parameter passed to the function. Please read the documentation here.
For your case, the second groupBy() is the one you should be using since you plan to use a callback and will allow you to use more complicated logic.
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
I see you can call my MyModel::all() and then call "where" "groupBy" .. etc
I cant seem to find orderBy as this Q & A suggest..
Has this been removed in Laravel 5?
I've tried looking through the docs for a reference in Collection and Model but I'm assuming these are actually just modifiers for the collection returned and not actually modifying the query statement..
The only way I know of using order by is
\DB::table($table)->where($column)->orderBy($column);
Is that the only way to order your database select when executing a query?
You can actually just use it like where and groupBy:
$result = MyModel::orderBy('name', 'desc')->get();
Note that by calling MyModel::all() you're already executing the query.
In general you can pretty much use every method from the query builder documented here with Eloquent models. The reason for this is that the model proxies method calls (that it doesn't know) to a query builder instance:
public function __call($method, $parameters)
{
// irrelevant code omitted
$query = $this->newQuery();
return call_user_func_array(array($query, $method), $parameters);
}
$this->newQuery() creates an instance of the query builder which then is used to actually run the query. Then when the result is retrieved the model/collection is hydrated with the values from the database.
More info
Eloquent - Laravel 5 Docs
Illuminate\Database\Eloquent\Builder - API docs
And also the regular query builder (since quite a few calls get passed from the eloquent builder)
Illuminate\Database\Query\Builder - API docs
You can achieve this with the following solution:
$result = ModelName::orderBy('id', 'desc')->get();
You can do it by using sort keys
Model::all()->sortKeys()
(or)
Model::all()->sortKeysDesc()
I'm on Laravel and Eloquent, and trying to populate a view's dropdown box with results of a select query.
In my controller:
public function uploadDocs($userid)
{
$doc_options = DB::select('select document.document_description from document where user_id = ?', array($userid));
return View::make('uploaddocs')->with('doc_options', $doc_options);
}
In my view:
<body>
{{ Form::select('doc_options_id', $doc_options) }}
</body>
I'm getting the following stack trace:
htmlentities() expects parameter 1 to be string, object given (View: /home/vagrant/code/eduview/app/views/uploaddocs.blade.php)
Any ideas? Thanks.
Try
$doc_options = DB::statement(DB::raw('select document.document_description from document where user_id = ?', array($userid)))->get();
Edit: I should probably explain first.
DB::select() is primarily used for the database builder in order to chain onto other chain-able functions, and not for doing your whole query.
You could use DB::statement to provide a new custom SQL query in it, but you also have to specify that the contents of the statement()'s parameter will be a raw query. Hence the DB::raw
Alternatively you could take advantage of Eloquent or Laravel's query builder by creating an Eloquent model called Document in app/models with contents as:
class Document extends Eloquent {}
and swap out your query above with:
$doc_options = Document::select('document_description')->where('user_id','=',$userid)->get()
You are passing an object into the Form::select() helper, and it is expecting an array.
Instead, Laravel has tools built in to do just this. See the lists() method in the Laravel docs under Selects:
public function uploadDocs($userid)
{
$doc_options = DB::table('document')->where('user_id', $userid)->lists('document_description');
return View::make('uploaddocs')->with('doc_options', $doc_options);
}
That should be it.