Laravel - Get array with relationship - laravel

I have an ajax call that returns an array:
$reports = Report::where('submission_id', $submissionID)
->where('status', 'pending')
->get(['description','rule']);
return [
'message' => 'Success.',
'reports' => $reports,
];
From this array, I only want to return the fields 'description' and 'rule'. However I also want to return the owner() relationship from the Report model. How could I do this? Do I have to load the relationship and do some kind of array push, or is there a more elegant solution?

You can use with() to eager load related model
$reports = Report::with('owner')
->where('submission_id', $submissionID)
->where('status', 'pending')
->get(['id','description','rule']);
Note you need to include id in get() from report model to map (owner) related model

you will have probably one to many relationship with Reports and owners table like below
Report Model
public function owner() {
return $this->belongsTo('App\Owner');
}
Owner Model
public function reports() {
return $this->hasMany('App\Report');
}
your controller code
$reports = Report::with('owner')->
where('submission_id', $submissionID)->where('status', 'pending')->get()
return [
'message' => 'Success.',
'reports' => $reports,
];

This is what I ended up going with:
$reports = Report::
with(['owner' => function($q)
{
$q->select('username', 'id');
}])
->where('submission_id', $submissionID)
->where('status', 'pending')
->select('description', 'rule','created_by')
->get();
The other answers were right, I needed to load in the ID of the user. But I had to use a function for it to work.

Related

Laravel 8 eager loading, how to access subquery fields

This is working:
$clients = Client::with([
'contacts' => function ($query) {
$query
->select('client_id', 'first_name', 'last_name')
->where('contact_type_id', '=', 1);
}])
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state']);
dd($clients);
However, I'm unsure of how to access first_name and last_name on the subquery. They're showing up in the "relations" object in the dump, but in my mind I'm envisioning a dataset that I would access like,
$client->first_name, etc.
When I try to add the fields to the get() method at the end, it doesn't recognize them, so I'm doing something wrong, or I need to access the subquery fields differently.
When you are eager loading the relationships, you are just preloading them.
If your relationship is defined as hasMany (which seems to be the case here, a Client hasMany Contact), then you'll always get a collection from eager loading.
If you defined another relationship in your model in order to get only one result, for instance:
public function contact()
{
return $this->hasOne(Contact::class)->where('contact_type_id', 1)->latest('id');
}
Your new relationship contact would return only one result:
$clients = Client::with('contact')
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state']);
foreach($clients as $client){
dd($client->contact->first_name);
}
// each Client of $clients would have a ->contact relationship
You should add field id to select() method in subquery and field contact_id to get() method
$clients = Client::with(['contacts' => function ($query) {
$query->select('id', 'client_id', 'first_name', 'last_name')->where('contact_type_id', '=', 1);
}])
->orderBy('client_name')
->get(['id', 'client_name', 'city', 'state', 'contact_id']);
foreach ($clients as $key => $client) {
dd($client->contacts->first_name);
// Or
dd($client->contacts()->first()->first_name);
}

Get values from relationship Laravel

I have a query where I get values from 3 tables, for first 2 I use leftJoin, and is Ok, but for third one I try to get an array of objects, and I am not sure how.
In relationship table a have multiple rows for each ID from People table. HasMany type.
$q = Person::leftJoin('registers', 'people.register_id', '=', 'registers.id')
->leftJoin('relationships', 'people.id', '=', 'relationships.person_id') //if I comment this it works for first 2 tables
->find($id);
return response()->json($q);
Person
public function relationship()
{
return $this->hasMany(Relationship::class);
}
public function register()
{
return $this->belongsTo(Register::class);
}
Relationship
public function person()
{
return $this->belongsTo(Person::class, 'person_id');
}
Register
public function people(){
return $this->hasOne(Person::class);
}
UPDATE -> this works,but is kind of ugly, I think that should be a better way in Laravel
$q = Person::leftJoin('registers', 'people.register_id', '=', 'registers.id')
->find($id);
$q2 = Person::find($id)->relationship;
return response()->json([
'values' => $q,
'relationship' => $q2,
]);
You can just use with like this:
Person::with(['register', 'relationship'])->find($id);

How to manipulate a Laravel collection with related models and return a customized instance?

My model relation
return $this->hasMany('App\Models\Opportunity')->with('user');
My Attempt
$project = Project::find(1);
$$opportunities = $project->opportunities
->where('status', "confirmed");
$opportunities->each(function ($opportunity) {
return $opportunity->get('user');
});
Goal
My goal is to return the data in the following structure:
Opportunities:
Opportunity:
Status,
Amount
Currency
Name
Note that the user is a subset of the opportunity itself.
Problem
This returns a 1024 SQL error.
Ideally
It would be ideal if I can return all this information with the query itself.
Call get() method on your query to get its results first:
$oppurtunities = $project->opportunities()
->where('status', "confirmed")
->get();
You have eager loaded the user instance for each opportunity so just call $opportunity->user to return each opportunity's user:
$project = Project::find(1);
$opportunities = $project
->opportunities()
->where('status', "confirmed")
->get();
$filtered = $opportunities->map(function ($opportunity) {
return [
'status' => $opportunity->status,
'amount' => $opportunity->amount_pledged,
'currency' => $opportunity->currency,
'name' => optional($opportunity->user)->full_name
];
})->all();

Laravel - condition on nested models

I'm writing a code to get nested objects in Laravel. I was wondering if it is possible to write conditions in hasMany or belongsTo.
Here is what I'm doing, that makes the question clear:
$posts = Post::where(
array(
'status' => 'active'
)
)
->orderBy('id', 'asc')
->with(['postResponsibilities' => function($query){
$query->where('status', 'active');
}])
->with(['postRequirements' => function($query){
$query->where('status', 'active');
}])
->with(['postSalaries' => function($query){
$query->where('status', 'active');
}])
->skip($limit * ($page - 1))->take($limit)->get();
So, I have to put nested queries to get only those records whose status is active.
In the Post model, I've written:
public function postRequirements(){
return $this->hasMany('App\Models\PostRequirement', 'post_id');
}
public function postResponsibilities(){
return $this->hasMany('App\Models\PostResponsibility', 'post_id');
}
public function postSalaries(){
return $this->hasMany('App\Models\PostSalary', 'post_id');
}
Is there a way such that I can define status condition inside the nested models?
So that I can write:
$posts = Post::where(
array(
'status' => 'active'
)
)
->orderBy('id', 'asc')
->with('postResponsibilities')
->with('postRequirements')
->with('postSalaries')
->skip($limit * ($page - 1))->take($limit)->get();
I hope the question is clear, thanks
What you can do is apply those conditions inside the relationship methods you put on the Post model, for example:
class Post
{
public function postRequirements() {
return $this->hasMany('App\Models\PostRequirement', 'post_id')
->where('status', 'active');
}
}
Yes it is possible to eager load multiple relationships.
See: https://laravel.com/docs/master/eloquent-relationships#eager-loading
In your case it would be something like:
Post::with('postResponsibilities', 'postRequirements', 'postSalaries')->where()....

Can't return object with belongsToMany relationship attached

I'm trying to return a list of $users with an array of roles.
Here's my controller:
$users = DB::table('users')->take(5)->skip(2)->get();
foreach ($users as $user)
{
$user = User::with('roles')->find($user->id);
}
return Response::json(array(
'users' => $users
));
And here's the model relationship:
public function roles()
{
return $this->belongsToMany('Role')->withTimestamps();
}
But this just returns the users without the role attached to it. However, if I do this:
return Response::json(array(
'users' => User::with('roles')->get()
));
I get the full list with the roles attached to each user. So, what am I doing wrong?
Oddly, if I do this:
return Response::json(array(
'users' => User::with('roles')->find($user->id)
));
Then it returns that user with the roles as I expected, so why not return it in the foreach statement?
You are loosing the whole Eloquent relations functionality when using DB queries.
You could just
$users = User::with('roles')->take(5)->skip(2)->get();
A good practice is to not mix Eloquent model "style" queries (User::...->get()) with direct DB queries (DB::table('user')...->get).
The foreach uses pass by value. That means you are not changing the actual array item but just a copy of the value. To change that and get the item passed by reference add a &:
foreach ($users as &$user) {
$user = User::with('roles')->find($user->id);
}
However why don't you just do it this way?
$users = User::with('roles')->take(5)->skip(2)->get();
return Response::json(array(
'users' => $users
));

Resources