This is so confusing to me. I don't see any difference between these two methods. If I var_dump() the object returned by these methods, they are exactly the same but the book by Dayle Rees says that pluck() returns a single value from the given column (the first one) while the lists() method returns all the values from the given column. I can't even figure out why two different methods exist to do the same thing.
Example
Route::get('getalbum', function() {
$data = \App\Album::pluck('artist');
var_dump($data); // a lot of text, let's call it 'object'
$data = \App\Album::lists('artist');
var_dump($data); // exact , exact, exact same 'object'
});
From the docs, Deprecations section
The following features are deprecated in 5.2 and will be removed in the 5.3 release in June 2016
The lists method on the Collection, query builder and Eloquent query builder objects has been renamed to pluck. The method signature remains the same.
So yes they are same. It's just there for backward compatibility.
Source code
Related
I have a variable $courses that in my debugger is shown as type App/Courses
In the model, there is a one to many relation and I retrieve these related items in the model and then access as $courses->relateditems
In the debugger, $courses->relateditems is shown as type Illuminate/Database/Eloquent/Collection
Ok, all makes sense.
I want to get last item in the $courses->relateditems collection. So I try
$courses->relateditems->last()->startdate
But this is not returning the value that I know exists. And when I evaluate the expression $courses->relateditems->last() in the debugger I get this in my laravel.log:
Symfony\Component\Debug\Exception\FatalErrorException: Cannot access self:: when no class scope is active in /app/Courses.php:68
I am just not sure what is going on. I know I can use DB queries to just get the data I need, but I have a model event triggering a function and that function receives the $courses object/model (or however we name it) and I am just trying to get this working as above.
Ideas on what I am doing wrong?
thanks,
Brian
The issue here based on the error you have at the bottom of your post is a mistake in your code.
However, I think you've misunderstood how Laravel relationships work. They essentially come in two forms on a model, that of a property and that of a method.
relateditems Is a magic property that will return the result of a simple select on the relationship if one has already been performed. If one hasn't been performed it will perform one and then return it, known as eager loading.
relateditems() Is a method that returns a query builder instance for that relationship.
By calling relateditems->last() you're loading ALL related items from the database and then getting the last, which is less than optimal.
The best thing for you to do is this:
$course->relateditems()->orderBy('id', 'desc')->first();
This will get the first item return, however, since we've ordered it by id in descending order, it'll be reversed from what could be considered its default ordering. Feel free to change the id to whatever you want.
Does anyone have any suggestions for how to use makeHidden() when eager-loading? here is my code:
$work=Work::with([
'work_category'=>function($query){
$query->with(['companies'=>function($query){
$query->select('companies.id','companies.name');
}]);
},
'prices',
])
->findOrFail($id);
Work has a belongsTo('App\WorkCategory') relationship, and WorkCategory has a belongsToMany('App\Company') relationship through a pivot.
If I try to chain ->makeHidden('pivot') on to $query->select('companies.id','companies.name'); - I get a BadMethodCall exception: Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsToMany::makeHidden()
Is there something I'm missing here?
This is the code with the offending makeHidden() call
$work=Work::with([
'work_category'=>function($query){
$query->with(['companies'=>function($query){
$query->select('companies.id','companies.name')->makeHidden('pivot');
}]);
},
'prices',
])
->findOrFail($id);
My temporary fix has been to add protected $hidden=['pivot']; to my Company model, however it would be nice to be able to access the pivot when I do need it, and use $model->relation->makeHidden('attribute') in my controllers to trim away extra data before sending.
Unfortunately, makeHidden() doesn't work on relationships in Laravel. Not directly nor using dot notation on the related field.
You've touched upon one solution that I've used in the past, which is to use select() to limit to only the relationship's fields that you want within the subquery as a somewhat rough way to exclude your pivot:
$query->with(['companies'=>function($query){
$query->select('id','name', 'something', 'something');
}]);
This works when the fields are limited. But its a pain when you have a lot or are making many queries.
Another alternative is to do what you've done, and mark it protected on the model: protected $hidden=['pivot'];. You then have some flexibility in various methods to use ->makeVisible('pivot'); on the fly to regain access to this pivot.
I'm trying to get data from an Eloquent query as follows:
$submission->find($id)->first()->with('user', 'clientform')->get();
I'm sending the submission to the view and attempting to access properties from the user model like so:
{{ $submission->clientform->name }}
However, Laravel is throwing the following error:
Undefined property: Illuminate\Database\Eloquent\Collection::$clientform
What am I doing wrong with the way my query is formatted?
You're overdoing it!
Let's break it down:
$submission->find($id);
Will return an instance of the model which corresponds to the entry having the primary key of $id.
$submission->find($id)->first();
This is an unncessary repetition; the find method already gives you a single entry, no need to call first on it.
$submission->find($id)->first()->with('user', 'clientform');
This is where you start going the wrong way; when calling with on a model, Laravel will transform that model into a query builder again, even though it was already resolved by calling find.
$submission->find($id)->first()->with('user', 'clientform')->get();
Finally, the get method resolves the builder into a Illuminate\Support\Collection, regardless of the number of entries found (i.e. it could be a Collection of only one item). It's worth noting, though, that your query will most likely have been fully reset by calling with. It would be the same as instantiating a fresh Submission model and building your query with it. That means you're probably using a collection of all your submission entries, not just the one with $id.
Long story short, this is what you want:
$submission->with('user', 'clientform')->find($id);
It will fetch the matching $id, with the user and clientform relations eager-loaded.
(integer) cast must be done in Homestead for Controller parameter
I am having a hard time searching for the cause of a discrepancy between my local dev environment (Homestead) and the hosted one.
I define a route like this:
Route::get('group/{id}/data', 'GroupDataController#index');
And the code in the Controller looks like this:
public function index($id)
{
return Grouping::all()->where('group_id', $id);
}
Which works fine in production (hosted env), BUT when I execute it locally it throws and empty array [] unless I modify my Controller function to look like this:
public function index($id)
{
return Grouping::all()->where('group_id', (integer)$id);
}
I have no idea of what is going on in here, and I am tired of making changes all over my Controller to make it work on both environments.
I have searched in several place, but maybe I am using incorrect tokens for my search as I have found nothing.
Any help will be really appreciated.
The problem here is that you're not using the correct set of functions.
When you call Grouping::all(), this is actually returning an Eloquent Collection object with every record in your groupings table. You are then calling the where() method on this Collection. This causes two problems: one, it is horribly inefficient; two, the where() method on the Collection works differently than the where() method on the query builder.
The where() method on the Collection takes three parameters: the name of the field, the value in that field on which to filter, and finally a boolean value to tell it whether or not to do a strict comparison (===) or a loose comparison (==). The third parameter defaults to strict. This strict comparison is why you're having the issue you are having, but I cannot explain why one environment sees $id as an integer and the other doesn't.
The where() method on a query builder object will actually add a where clause to the SQL statement being executed, which is a much more efficient way of filtering the data. It also has more flexibility as it is not limited to just equals comparisons (the second parameter is the comparison operator for the where clause, but will default to "=" if it is left out).
You have two options to fix your issue. You can either pass in false as the third parameter to your where() method in the current code (bad), or you can update the code to actually filter using the query instead of filtering on the entire Collection (good).
I would suggest updating your code to this:
public function index($id) {
return Grouping::where('group_id', '=', $id)->get();
}
In the above code, Grouping::where('group_id', '=', $id) will generate a query builder object that has the given where clause, and then get() will execute the query and return the Collection of results.
I marked #patricus (thanks you, so much!) as the correct answer, for he really pointed me in the right direction to understand that there are some keywords that work differently under different contexts (like get()), but I will also point out, how my 2 confusing points were solved in my case:
The difference in my code between production and Homestead development environments was solved by pointing my Homestead to the production database. I am not sure what was the difference (maybe collation or table format), but it gave me a quick out.
I was trying to filter a list of elements in the database but I was constructing it with the wrong logic for Laravel.
To clear what I refer to in the second point, I was using this code:
Grouping::all(['id', 'name_id', 'product_id', 'ship_id'])->where('name_id', '=', $id);
I thought this could work, because it would be selecting all items, with the selected columns, and then filter those with a where clause. But I was wrong, since, as I found out later, the correct way of writing this is:
Grouping::where('name_id', $id)->select('id', 'name_id', 'product_id', 'ship_id')->get();
This is because I forgot completely that I was assembling the query, not writing the actions I expected the program to do.
This second syntax has more logic, since I specify the filter, then put the columns over what was filtered, and finally execute the query with the get() clause.
Of course, it can also be written the other side around for clearer fluent reading:
Grouping::select('id', 'name_id', 'product_id', 'ship_id')->where('name_id', $id)->get();
I'm trying to query in MongoDB using PHP/CodeIgniter but I can't find a solution...
I have a first query in "function1" where there is
$this->mongo_db->where("category" => getCatID("games");
And in my second function "getCatID" I have
return $this->mongo_db->select('_id')->where("name" => $name)->get('Category');
But it seems that the second function continue on the first query of function1.
I'm using this library...
I assume your first code snippet was intended to be:
$this->mongo_db->where("category", getCatID("games"));
// or…
$this->mongo_db->where(array("category" => getCatID("games")));
I've not used this library, but from perusing the source code, it looks like all query criteria set by where() is accumulated in an internal $wheres property on the Mongo_db class. This only gets cleared by the private _clear() method, which is called from the following public methods:
get()
count()
update()
update_all()
delete()
delete_all()
add_index()
remove_index()
remove_all_indexes()
Any time either of those terminating methods are called, $wheres will be reset. Likewise, if those methods aren't called, older criteria may bleed into your next criteria. In your case getCatID() may be clearing out earlier criteria. PHP is going to execute getCatID() before invoking the where() method in which it's an argument, so I'd expect that outer where() call to see an empty $wheres array.
One solution would be to call getCatID() on its own before building your second query. Alternatively, you could clone the Mongo_db instance to ensure that each query is built independently.