Laravel pluck nested collection to root collection - php

I have a data structure like you can see in the picture above.
I want some fields from user field in the root collection, but I don't know how can I can get that.
public function index (Request $request) {
$draw = $request->get('draw');
$start = $request->get('start');
$length = $request->get('length');
$order = Order::with('user');
$total_order = $order->count();
$orders = Order::with('user')->offset($start)->limit($length)->get();
/*$draw = ceil($total_order/$length);*/
return response()->json([
'draw' => $draw,
'recordsTotal' => $total_order,
'recordsFiltered' => $total_order,
'data' => $orders,
]);
}

The flatmap approach seems weird, you have two models Order and Users, either you have to add extra properties to orders on the fly, which is weird in Laravel if you want to save the model again. Or you have to convert it to arrays and you loose the Model functionality.
Instead of trying to flatten the user object onto the order. You are already using with(), so your user is eager loaded and can rely on that. Instead use Eloquent Getters and map your user fields to the order.
class Order extends Model
{
public function getUserNameAttribute() {
return $this->user->name;
}
}
Eloquent getters function name has to be in the format getPropertyAttribute. Now you would be able to access it like so, which also can be done in blade etc.
foreach ($orders as $order) {
$userName = $order->userName;
}

If you truly want the related values in the root collection, you could do a left join on the table:
$orders = Order::leftJoin('users', 'users.id', '=', 'orders.user_id')
(Based on the model names, these would be the correct table and column names).
However, like Mrhn just pointed out, it is not very Eloquent-like to try and have data of related tables in the root collection of the main model.
P.S. If you do use the left join, be sure to only select the data you need, otherwise it will overwrite Order data (such as id)

Related

Copying Data from table to another table and applying one to many relationship

This is my Report Model
protected $fillable = [
'site_url',
'reciepients',
'monthly_email_date'
];
public function site()
{
return $this->belongsTo('App\Site');
}
This is my Site Model
public function report()
{
return $this->hasMany('App\Report');
}
This is my ReportController
public function showSpecificSite($site_name)
{
$records = DB::table('reports')
->select('email_date','url','recipient')
->whereHas('sites', function($query){
$query->where('site_name',$site_name);
})
->get();
return view('newsite')->with('records',$records)
->with('site_name',$site_name);
}
My Controller is not yet working as well.
The thing is I would like to copy all the three files from sites table to reports table.
Is it possible in insertInto ?
My code on ReportController shows you that I'm selecting data from reports table but I am the one who puts data to reports table to see the output but it is not yet working because of the it cant reach out the value of site_name even though I already put a relationship between the two tables.
You're not actually using Eloquent in your controller you're just using the Query Builder (DB). This will mean that you don't have access to anything from your Eloquent models.
Try:
$records = \App\Report::whereHas('site', function($query) use($site_name) {
$query->where('site_name', $site_name);
})->get(['id', 'email_date', 'url', 'recipient']);
I've added id to the list of columns as I'm pretty sure you'll need that to use whereHas.
NB to use a variable from the parent scope inside a closure you need to pass it in using use().

fetch records from two tables relating to each other - symfony

I have two table in symfony. The images table has a foreign key to the users table. I want to retrieve records where user id is equal to the argument passed. Here is my attempt
private function serializeUsers(Users $usr) {
return array(
'username' => $usr->getUsername(),
'email' => $usr->getEmail(),
'id' => $usr->getId(),
//I have tried using getter method to retrieve image value here but I cannot because image is related to users
);
}
Here is the controller codes
$restresults = $this->getDoctrine()
->getRepository('xxxBundle:Users')
->findBy(['id' => $id]);
array_push($data, $this->serializeUsers($restresult));
As you can see from my above attempts, I am unable to retrieve data for the image table having a foreign key to the users table. Is my design wrong or I have not yet figured out the logic or a better way to approach this
EDIT:
You could use the entity Repository:
Add
* #ORM\Entity(repositoryClass=UsersRepository::class)
* #ORM\Table(name="Users")"
On your Users entity annotation And you'll be able to use it, it's way cleaner than writing the needed query in your controller
$restresults = $this->getDoctrine()
->getRepository('xxxBundle:Users')
->findBy(['id' => $id]);
Write instead:
$restresults = $this->getDoctrine()
->getRepository('xxxBundle:Users')
->findWithImages($id);
And in your UsersRepository wirte a function getting the images:
public function findWithImages($id)
{
$queryBuilder = $this->createQueryBuilder('u')
->join('u.images', 'i')
->where('u.id = :id')
->setParameter('id', $id);
return $queryBuilder->getQuery()->getResult();
}
END OF EDIT
Have you reversed your relation ?
$user->images should be an private ArrayCollection initialized in your class constructor and accessible via a $user->getImages();
This variable does not correspond to a database column but allow you to access the image even from the user side (not being the owner side in the case).
Also you might want to have a look at What is the difference between fetch="EAGER" and fetch="LAZY" in doctrine
For some more details on how your data are accessed.
Also check this: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional
Right here you are normalizing your data more than serializing it.
Have a look at: https://symfony.com/doc/current/components/serializer.html

how to make fetching from two three model with clause and fetch selected fields in laravel [duplicate]

I have two tables, User and Post. One User can have many posts and one post belongs to only one user.
In my User model I have a hasMany relation...
public function post(){
return $this->hasmany('post');
}
And in my post model I have a belongsTo relation...
public function user(){
return $this->belongsTo('user');
}
Now I want to join these two tables using Eloquent with() but want specific columns from the second table. I know I can use the Query Builder but I don't want to.
When in the Post model I write...
public function getAllPosts() {
return Post::with('user')->get();
}
It runs the following queries...
select * from `posts`
select * from `users` where `users`.`id` in (<1>, <2>)
But what I want is...
select * from `posts`
select id,username from `users` where `users`.`id` in (<1>, <2>)
When I use...
Post::with('user')->get(array('columns'....));
It only returns the column from the first table. I want specific columns using with() from the second table. How can I do that?
Well I found the solution. It can be done one by passing a closure function in with() as second index of array like
Post::query()
->with(['user' => function ($query) {
$query->select('id', 'username');
}])
->get()
It will only select id and username from other table. I hope this will help others.
Remember that the primary key (id in this case) needs to be the first param in the
$query->select() to actually retrieve the necessary results.*
You can do it like this since Laravel 5.5:
Post::with('user:id,username')->get();
Care for the id field and foreign keys as stated in the docs:
When using this feature, you should always include the id column and
any relevant foreign key columns in the list of columns you wish to
retrieve.
For example, if the user belongs to a team and has a team_id as a foreign key column, then $post->user->team is empty if you don't specifiy team_id
Post::with('user:id,username,team_id')->get();
Also, if the user belongs to the post (i.e. there is a column post_id in the users table), then you need to specify it like this:
Post::with('user:id,username,post_id')->get();
Otherwise $post->user will be empty.
For loading models with specific column, though not eager loading, you could:
In your Post model
public function user()
{
return $this->belongsTo('User')->select(['id', 'username']);
}
Original credit goes to Laravel Eager Loading - Load only specific columns
When going the other way (hasMany):
User::with(['post'=>function($query){
$query->select('id','user_id');
}])->get();
Don't forget to include the foreign key (assuming it is user_id in this example) to resolve the relationship, otherwise you'll get zero results for your relation.
In Laravel 5.7 you can call specific field like this
$users = App\Book::with('author:id,name')->get();
It is important to add foreign_key field in the selection.
If you want to get specific columns using with() in laravel eloquent then you can use code as below which is originally answered by #Adam in his answer here in response of this same question, the answer's main code is as below :
Post::with('user:id,username')->get();
So i have used it in my code but it was giving me error of 1052: Column 'id' in field list is ambiguous, so if you guys are also facing same problem
Then for solving it you have to specify table name before the id column in with() method as below code:
Post::with('user:user.id,username')->get();
I came across this issue but with a second layer of related objects. #Awais Qarni's answer holds up with the inclusion of the appropriate foreign key in the nested select statement. Just as an id is required in the first nested select statement to reference the related model, the foreign key is required to reference the second degree of related models; in this example the Company model.
Post::with(['user' => function ($query) {
$query->select('id','company_id', 'username');
}, 'user.company' => function ($query) {
$query->select('id', 'name');
}])->get();
Additionally, if you want to select specific columns from the Post model you would need to include the user_id column in the select statement in order to reference it.
Post::with(['user' => function ($query) {
$query->select('id', 'username');
}])
->select('title', 'content', 'user_id')
->get();
In your Post model:
public function userWithName()
{
return $this->belongsTo('User')->select(array('id', 'first_name', 'last_name'));
}
Now you can use $post->userWithName
There is another alternative you can eager load specific columns
public function show(Post $post)
{
$posts = $post->has('user')->with('user:id,name,email,picture')->findOrFail($post->id);
return view('your_blade_file_path',compact('posts);
}
In your Post model you should have user relationship also
public function user()
{
return $this->belongsTo( User::class, 'user_id')->withDefault();
}
Note: It is mentioned in Laravel docs.
https://laravel.com/docs/8.x/eloquent-relationships#eager-loading-specific-columns
Note that if you only need one column from the table then using 'lists' is quite nice. In my case i am retrieving a user's favourite articles but i only want the article id's:
$favourites = $user->favourites->lists('id');
Returns an array of ids, eg:
Array
(
[0] => 3
[1] => 7
[2] => 8
)
If you use PHP 7.4 or later you can also do it using arrow function so it looks cleaner:
Post::with(['user' => fn ($query) => $query->select('id','username')])->get();
I faced the same issue while using belongsToMany relationship with my user model (Laravel 8.x.x).
After a long search and trial and test method. I found out this answer
You have to make sure you are selecting the id's and any foreign keys that would be needed for the relationship from either side of that relationship. This allows Eloquent to match up parents to their children.
Original credit goes to https://stackoverflow.com/a/64233242/1551102
So I included
Groups::select('groupid')
...
And it worked like a charm. Although now I want to know how to hide the groupid field after fetching.
I know I can simply loop through the array and remove it. But is there any other method? potentially a simpler and better one.
You can also specify columns on related model at the time of accessing it.
Post::first()->user()->get(['columns....']);
You can try this code . It is tested in laravel 6 version.
Controller code
public function getSection(Request $request)
{
Section::with(['sectionType' => function($q) {
$q->select('id', 'name');
}])->where('position',1)->orderBy('serial_no', 'asc')->get(['id','name','','description']);
return response()->json($getSection);
}
Model code
public function sectionType(){
return $this->belongsTo(Section_Type::class, 'type_id');
}
Be careful that if you don't add the key column(s) it won't return anything. If you want to show only the username without the id you could instead define the $visible/$hidden properties within the Model, like so:
app/Models/User.php
protected $visible = ['username'];
Then it will retrieve only username column with:
Post::with('user')->get();
Hiding the key columns:
Alternatively you could hide the key column(s) and then retrieve only the columns you wish.
app/Models/User.php
protected $hidden = ['id'];
Specify which columns you want including the key or else it won't return anything, but this will actually only return the username, because id is $hidden.
Post::with('user:id,username')->get();
Now you can use the pluckmethod on a Collection instance:
This will return only the uuid attribute of the Post model
App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
all: [
"1",
"2",
"3",
],
}
Try with conditions.
$id = 1;
Post::with(array('user'=>function($query) use ($id){
$query->where('id','=',$id);
$query->select('id','username');
}))->get();
So, similar to other solutions here is mine:
// For example you have this relation defined with "user()" method
public function user()
{
return $this->belongsTo('User');
}
// Just make another one defined with "user_frontend()" method
public function user_frontend()
{
return $this->belongsTo('User')->select(array('id', 'username'));
}
// Then use it later like this
$thing = new Thing();
$thing->with('user_frontend');
// This way, you get only id and username,
// and if you want all fields you can do this
$thing = new Thing();
$thing->with('user');
EmployeeGatePassStatus::with('user:id,name')->get();

How to return model rows where id is equal to id on other table with relations in laravel?

For example I have:
// Returns all projects
$projects = Projects::all();
To return categories, belonging to project, I use relationships and can do something like:
foreach($projects as $project) { ...show $project->categories... }
I need only specific projects, which are followed by specific user. On my projects_followers table I have user_id and project_id.
To retrieve projects which were followed I have this peace of code:
$projects = Project::rightJoin(DB::raw('(select * from projects_followers group by project_id) projects_followers'),'projects_followers.project_id','=','projects.id')->get();
// Note: This code doesn't include specifuc user_id.
It does retrieve specific rows, but the problem with this code is that laravel relationhips dont work on them. For example $project->categories return empty.
// Relationship
public function categories()
{
return $this->belongsToMany('App\Category');
}
How do I retrieve my model specific rows and make relationships to work?
Actually your question is:
How do I get projects liked/followed by Auth/Logged in User ?
Unfortunately you described it in such a way that it looks something else, anyways. Lets try to find the solution and for this I would like to use something like this:
$projects = Auth::user()->favorite_projects;
So how we can implement this to work, first of all the User Model should contain the method favoriteProjects so lets create it:
public function favoriteProjects()
{
return $this->belongsToMany(
'App\Project',
'projects_followers', // This table already exists as you mentioned
'user_id',
'project_id'
);
}
That's it. You will be able to load the projects followed by the current user and other relationship methods will work on every single project as well.
My workaround:
// I don't know how to create empty collection, so impossible conditions here.
$projects = Project::where('id', 0)->get();
$follows = DB::table('projects_followers')->where('follower_id', Auth::user()->id)->get();
foreach($follows as $follow) {
$project = Project::where('id', $follow->project_id)->first();
$projects = $projects->add($project);
}

Get Specific Columns Using “With()” Function in Laravel Eloquent

I have two tables, User and Post. One User can have many posts and one post belongs to only one user.
In my User model I have a hasMany relation...
public function post(){
return $this->hasmany('post');
}
And in my post model I have a belongsTo relation...
public function user(){
return $this->belongsTo('user');
}
Now I want to join these two tables using Eloquent with() but want specific columns from the second table. I know I can use the Query Builder but I don't want to.
When in the Post model I write...
public function getAllPosts() {
return Post::with('user')->get();
}
It runs the following queries...
select * from `posts`
select * from `users` where `users`.`id` in (<1>, <2>)
But what I want is...
select * from `posts`
select id,username from `users` where `users`.`id` in (<1>, <2>)
When I use...
Post::with('user')->get(array('columns'....));
It only returns the column from the first table. I want specific columns using with() from the second table. How can I do that?
Well I found the solution. It can be done one by passing a closure function in with() as second index of array like
Post::query()
->with(['user' => function ($query) {
$query->select('id', 'username');
}])
->get()
It will only select id and username from other table. I hope this will help others.
Remember that the primary key (id in this case) needs to be the first param in the
$query->select() to actually retrieve the necessary results.*
You can do it like this since Laravel 5.5:
Post::with('user:id,username')->get();
Care for the id field and foreign keys as stated in the docs:
When using this feature, you should always include the id column and
any relevant foreign key columns in the list of columns you wish to
retrieve.
For example, if the user belongs to a team and has a team_id as a foreign key column, then $post->user->team is empty if you don't specifiy team_id
Post::with('user:id,username,team_id')->get();
Also, if the user belongs to the post (i.e. there is a column post_id in the users table), then you need to specify it like this:
Post::with('user:id,username,post_id')->get();
Otherwise $post->user will be empty.
For loading models with specific column, though not eager loading, you could:
In your Post model
public function user()
{
return $this->belongsTo('User')->select(['id', 'username']);
}
Original credit goes to Laravel Eager Loading - Load only specific columns
When going the other way (hasMany):
User::with(['post'=>function($query){
$query->select('id','user_id');
}])->get();
Don't forget to include the foreign key (assuming it is user_id in this example) to resolve the relationship, otherwise you'll get zero results for your relation.
In Laravel 5.7 you can call specific field like this
$users = App\Book::with('author:id,name')->get();
It is important to add foreign_key field in the selection.
If you want to get specific columns using with() in laravel eloquent then you can use code as below which is originally answered by #Adam in his answer here in response of this same question, the answer's main code is as below :
Post::with('user:id,username')->get();
So i have used it in my code but it was giving me error of 1052: Column 'id' in field list is ambiguous, so if you guys are also facing same problem
Then for solving it you have to specify table name before the id column in with() method as below code:
Post::with('user:user.id,username')->get();
I came across this issue but with a second layer of related objects. #Awais Qarni's answer holds up with the inclusion of the appropriate foreign key in the nested select statement. Just as an id is required in the first nested select statement to reference the related model, the foreign key is required to reference the second degree of related models; in this example the Company model.
Post::with(['user' => function ($query) {
$query->select('id','company_id', 'username');
}, 'user.company' => function ($query) {
$query->select('id', 'name');
}])->get();
Additionally, if you want to select specific columns from the Post model you would need to include the user_id column in the select statement in order to reference it.
Post::with(['user' => function ($query) {
$query->select('id', 'username');
}])
->select('title', 'content', 'user_id')
->get();
In your Post model:
public function userWithName()
{
return $this->belongsTo('User')->select(array('id', 'first_name', 'last_name'));
}
Now you can use $post->userWithName
There is another alternative you can eager load specific columns
public function show(Post $post)
{
$posts = $post->has('user')->with('user:id,name,email,picture')->findOrFail($post->id);
return view('your_blade_file_path',compact('posts);
}
In your Post model you should have user relationship also
public function user()
{
return $this->belongsTo( User::class, 'user_id')->withDefault();
}
Note: It is mentioned in Laravel docs.
https://laravel.com/docs/8.x/eloquent-relationships#eager-loading-specific-columns
Note that if you only need one column from the table then using 'lists' is quite nice. In my case i am retrieving a user's favourite articles but i only want the article id's:
$favourites = $user->favourites->lists('id');
Returns an array of ids, eg:
Array
(
[0] => 3
[1] => 7
[2] => 8
)
If you use PHP 7.4 or later you can also do it using arrow function so it looks cleaner:
Post::with(['user' => fn ($query) => $query->select('id','username')])->get();
I faced the same issue while using belongsToMany relationship with my user model (Laravel 8.x.x).
After a long search and trial and test method. I found out this answer
You have to make sure you are selecting the id's and any foreign keys that would be needed for the relationship from either side of that relationship. This allows Eloquent to match up parents to their children.
Original credit goes to https://stackoverflow.com/a/64233242/1551102
So I included
Groups::select('groupid')
...
And it worked like a charm. Although now I want to know how to hide the groupid field after fetching.
I know I can simply loop through the array and remove it. But is there any other method? potentially a simpler and better one.
You can also specify columns on related model at the time of accessing it.
Post::first()->user()->get(['columns....']);
You can try this code . It is tested in laravel 6 version.
Controller code
public function getSection(Request $request)
{
Section::with(['sectionType' => function($q) {
$q->select('id', 'name');
}])->where('position',1)->orderBy('serial_no', 'asc')->get(['id','name','','description']);
return response()->json($getSection);
}
Model code
public function sectionType(){
return $this->belongsTo(Section_Type::class, 'type_id');
}
Be careful that if you don't add the key column(s) it won't return anything. If you want to show only the username without the id you could instead define the $visible/$hidden properties within the Model, like so:
app/Models/User.php
protected $visible = ['username'];
Then it will retrieve only username column with:
Post::with('user')->get();
Hiding the key columns:
Alternatively you could hide the key column(s) and then retrieve only the columns you wish.
app/Models/User.php
protected $hidden = ['id'];
Specify which columns you want including the key or else it won't return anything, but this will actually only return the username, because id is $hidden.
Post::with('user:id,username')->get();
Now you can use the pluckmethod on a Collection instance:
This will return only the uuid attribute of the Post model
App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
all: [
"1",
"2",
"3",
],
}
Try with conditions.
$id = 1;
Post::with(array('user'=>function($query) use ($id){
$query->where('id','=',$id);
$query->select('id','username');
}))->get();
So, similar to other solutions here is mine:
// For example you have this relation defined with "user()" method
public function user()
{
return $this->belongsTo('User');
}
// Just make another one defined with "user_frontend()" method
public function user_frontend()
{
return $this->belongsTo('User')->select(array('id', 'username'));
}
// Then use it later like this
$thing = new Thing();
$thing->with('user_frontend');
// This way, you get only id and username,
// and if you want all fields you can do this
$thing = new Thing();
$thing->with('user');
EmployeeGatePassStatus::with('user:id,name')->get();

Categories