i have the next structure:
model call content
public function credits(){
return $this->belongsToMany('App\models\Credit');
}
model call Credit
public function content()
{
return $this->belongsToMany('App\models\Content');
}
What i am triying to do is extract all the credits of one content, but selecting only the columns that i want, with the below code:
$credits2=$this->content::with(array('credits'=>function($query){
$query->select('id','department','job');
}))->where('id',$id_content)->get();
The problem that i have is that when i execute all the code the result is:
[]
but if i do a normal query in mysql i can figure out that for the movie exists credits.
I have extracted this code, from other forums, and stackoverflow post.
There is another easy way to specify columns without using closure:
$credits2 = $this->content::with('credits:credits.id,department,job')
->find($id_content->id);
The problem was that $id_content was a result from a previous query, so if i put $id_content didn't work, for that i have to access to the column.
And the solution is:
$credits2=$this->content::with(array('credits'=>function($query){
$query->select('id','department','job');
}))->where('id',$id_content)->get();
Related
im new in laravel programming and im trying to do something with laravel Eloquent.
So i have 3 tables, dev, dev_project(many to many) and project.
i need to see in which projects the dev is part of, using the dev_project table, and get the corresponding id from projects.
after that i need to go to the table project, and use the id that I got from the many-to-many table to get the corresponding name of the projects in which that same dev is part of.
First im fetching data from my DB into a variable
$devproject = DB::table('dev_project')->where('id_dev', '=', Auth::user()->id)->get();
And then Im trying to get the data from the project table where the id is the same from the one that i fetched before
return Project::where('id', $dev_project->id_project);
The problem here is that the variable dev_project is an object, and i cant use a foreach and store the data that i want to return inside an array.
So how can I get all the data that i want in the same object.
I appreciate any help, Thank you.
Here, $devproject is a Collection, not a single row. $dev_project->id_project is not a valid property.
If you want the first result's id_project, then the syntax is $devproject->first()->id_project.
If you want a Collection of each of $devproject 's id_project, then the syntax should be $devproject->pluck('id_project').
With that in mind, your query should either be
return Project::where('id', $dev_project->first()->id_project);
or
return Project::whereIn('id', $dev_project->pluck('id_project'));
As harish durga suggests, a relationship would save you the trouble of writin these queries.
# Dev Model
public function projects()
{
return $this->belongsToMany(Project::class, 'dev_project', 'id_project', 'id_dev');
}
# Project Model
public function devs()
{
return $this->belongsToMany(Dev::class, 'dev_project', 'id_dev', 'id_project');
}
# Get all devs with associated projects:
$devs = Dev::with('projects')->get();
foreach ($devs as $dev) {
echo $dev->...
foreach ($dev->projects as $project) {
echo $project->...
}
}
I got 2 main tables users and pictures. Each user can have same picture(and vice versa) so it have got "hasMany"(and pivot table in between of them) relationship in Elaquent and it works well. Also, I do have as separate table pictures_details. I wonder, is it possible to get the details of pictures_details when accessing from user to picture model?
public function getImages($id, Images $images)
{
return $users->with('images')->find($id);
}
So when I have call like that, can I also get data of pictures_details table? I have following method in my Image model
public function imageDetails(): BelongsTo
{
return $this->belongsTo(ImageDetails::class, 'image_details_id', 'id');
}
So I thought something like
return $users->with('images')->find($id)->with('imagedetails');
Will work but its not. Can you tell me how to achieve this? Or it is wrong approach?
I want to edit ArSeN's answer. May be it would be more correct if
$users->with(['images.imagedetails'])->find($id);
find($id) returns a single model, not the eloquent query, you cant do joins there.
Switch them around:
$users->with('images')->with('imagedetails')->find($id);
I was wondering about the best way to get the count of all the rows created before the selected one. Right now I have defined an accessor that looks like this:
// In the model
public function getPositionAttribute() {
return self::where([
// Some other condition
['created_at', '<', $this->created_at->toDateTimeString()]
])->count();
}
// In the code
$model->position
It works correctly, but I'm worried about 2 things:
Is it a bad practice to call self on the model? Looks somehow off to me.
When called in a foreach this obviously generates a query for each element which is far from optimal. Is there any way to refactor this so that it can be eager loaded in a single query?
Bonus: I have totally discarded the idea of keeping a column with some kind of index because that initially sounded impossible to maintain, eg. when a record is deleted all the others should somehow shift position. Should I reconsider it? Is there a better way?
Pretty sure that using self here is the "best practice" because that is how that keyword was designed to be used.
In regards to refactoring, i personally can't think of optimizing the query as is but instead you could create a function that preloads all the position then use it normally. Assuming your model has a unique key 'id' and you are passing in a collection of model then, you can try something like this:
public static function populateOrderPositions($modelCollection){
// Optimize this query to include your "other condition"
$idCollection = Model::orderBy('created_at') // this will make it in the order of creation
->pluck('id'); // this will only retrieve the id field
// This array will contain an array with the model object ids as key and a numeric position (starts at 0)
$positionArr = $idCollection->flip()->all();
// Then just load all the position into the object and return it.
return $modelCollection->map(function($modelObj) use ($positionArr){
return $modelObj->position = $positionArr[$modelObj->id] + 1; // +1 because array key starts at 0
};
}
You would also need to adjust your attribute code to use the loaded attribute instead of ignoring the loaded attribute like so:
public function getPositionAttribute() {
return $this->attributes['position'] ?? self::where([
// Some other condition
['created_at', '<', $this->created_at->toDateTimeString()]
])->count();
}
With these changes, you can then prepopulate the position then use it afterward without the need to query the database.
These code are untested as i don't know how your model and query will be structured and is more of an example. Also you would need to compare the performance vs your original code.
I have the following static method in my Guest model to retrieve all guests at location 1:
public static function getGuests()
{
return self::where('location_id', '=', 1)->get();
}
I also got the following static method to retrieve and display the number of guests at location 1.
public static function getCount()
{
return self::getGuests()->count();
}
I later call the getGuests() in my GuestController and pass all the guests to the view guests/index.blade.php to display data in a table.
I also call getCount() from my BaseController (see below) to make the count variable available both in the menubar in the layout/layout.blade.php file and the header of guests/index.blade.php.
View::share('numGuests', Guest::getCount());
By doing this i naturally end up with an expensive duplicated query to the DB since GetCount() calls getGuests(). Is there a better way to display the number of counts, both in the master layout file and the embedded view, without having to do the duplicate query call?
View::share shouldn't be calling the `Guest::getCount()' twice. It should just call it once and then pass it in. If not though can't you just cache the value in a variable and then pass it in? Then its definitely not getting queried twice.
$guestCount = Guest::getCount();
View::share('numGuests', $guestCount);
I might be misunderstanding here - are you also calling Guest::getCount() later on from your GuestController? Sorry - can't comment on main questions yet to ask.
I found a quick and low-cost solution by simply just calling the count() directly on the query, instead on the function call.
public static function getAll($locationId)
{
return self::whereLocationId($locationId)->with('country')->get();
}
public static function countAll($locationId)
{
return self::whereLocationId($locationId)->count();
}
This left me me with two separate queries, where the count is onsiderably lower cost:
select * from `guests` where `location_id` = '2'
and
select count(*) as aggregate from `guests` where `location_id` = '2'
It can probably be made even quicker by selecting only the neccesary columns instead of *. In cases where the query is more complicated and require more WHERE clauses, it can easily be kept DRY by using query scopes. Thanks for massaging my brain.
So I have a many to many relationship between Users and Photos via the pivot table user_photo. I use belongsToMany('Photo') in my User model. However the trouble here is that I have a dozen columns in my Photo table most I don't need (especially during a json response). So an example would be:
//Grab user #987's photos:
User::with('photos')->find(987);
//json output:
{
id: 987,
name: "John Appleseed",
photos: {
id: 5435433,
date: ...,
name: 'feelsgoodman.jpg',
....// other columns that I don't need
}
}
Is it possible to modify this method such that Photos model will only return the accepted columns (say specified by an array ['name', 'date'])?
User.php
public function photos()
{
return $this->belongsToMany('Photo');
}
Note: I only want to select specific columns when doing a User->belongsToMany->Photo only. When doing something like Photo::all(), yes I would want all the columns as normal.
EDIT: I've tried Get specific columns using "with()" function in Laravel Eloquent but the columns are still being selected. Also https://github.com/laravel/laravel/issues/2306
You can use belongsToMany with select operation using laravel relationship.
public function photos()
{
return $this->belongsToMany('Photo')->select(array('name', 'date'));
}
Im assuming you have a column named user_id. Then you should be able to do the following:
public function photos()
{
return $this->belongsToMany('Photo')->select(['id', 'user_id', 'date', 'name']);
}
You have to select, the foreign key, else it will have no way of joining it.
Specifying the exact columns you want for the Photos relationship will likely end up biting you in the butt in the future, should your application's needs ever change. A better solution would be to only specify the data you want to return in that particular instance, i.e. the specific JSON response you're delivering.
Option 1: extend/overwrite the toArray() Eloquent function (which is called by toJson()) and change the information returned by it. This will affect every call to these methods, though, so it may end up giving you the same problems as doing select() in the original query.
Option 2: Create a specific method for your JSON response and call it instead of the general toJson(). That method could then do any data building / array modifications necessary to achieve the specific output you need.
Option 3: If you're working with an API or ajax calls in general that need a specific format, consider using a library such as League/Fractal, which is built for just such an occasion. (Phil is also working on a book on building APIs, and it doesn't suck.)