How do I Transform specific fields in Laravel?
For example:
$user = \Auth::User();
return [
'user_id' => $user->id,
'articles' => $user->articles,
'pages' => $user->pages,
];
$user->articles will show the entries the articles table and $user->pages from the pages table.
In the User model, it would be defined something like that:
public function articles()
{
return $this->hasMany(Article::class);
}
I do not want to return all the fields from $user->articles, just id, name, and description. What is good way to transform this collection?
I would like to do something like:
'articles' => transformArticle($user->articles),
In the relationship:
return $this->hasMany('Article::class')->select(array('id', 'name','description'));
Or whenever you need it:
User::with(array('articles'=>function($query){
$query->select('id','name','description');
}))->get();
Transformers
maybe you need this.
Related
I am calling an array of all the comments of a poll by using the following code:
$poll = Poll::find($id);
return view('pages.poll', ['poll' => $poll, 'comments' => $poll->comments]);
and the links between Comments and Polls are the following:
Comment.php
public function poll() {
return $this->belongsTo(Poll::class, 'poll_id');
}
Poll.php
public function comments() {
return $this->hasMany(Comment::class, 'poll_id');
}
Finally, I would like to sort the array comments coming from $poll->comment by the column likes in the Comment table, something like DB::table('comment')->orderBy('likes')->get();.
Is there any way to do that?
$poll->comments->sortBy('likes')
There's a number of ways you can do this.
Add orderBy('likes') directly to your comments relationship:
Poll.php:
public function comments() {
return $this->hasMany(Comment::class, 'poll_id')->orderBy('likes');
}
Now, any time you access $poll->comments, they will be automatically sorted by the likes column. This is useful if you always want comments in this order (and it can still be overridden using the approaches below)
"Eager Load" comments with the correct order:
In your Controller:
$poll = Poll::with(['comments' => function ($query) {
return $query->orderBy('likes');
})->find($id);
return view('pages.poll', [
'poll' => $poll,
'comments' => $poll->comments
]);
with(['comments' => function ($query) { ... }]) adjusts the subquery used to load comments and applies the ordering for this instance only. Note: Eager Loading for a single record generally isn't necessary, but can be useful as you don't need to define an extra variable, don't need to use load, etc.
Manually Load comments with the correct order:
In your Controller:
$poll = Poll::find($id);
$comments = $poll->comments()->orderBy('likes')->get();
return view('pages.poll', [
'poll' => $poll,
'comments' => $comments
]);
Similar to eager loading, but assigned to its own variable.
Use sortBy('likes'):
In your Controller:
$poll = Poll::find($id);
return view('pages.poll', [
'poll' => $poll,
'comments' => $poll->comments->sortBy('likes')
]);
Similar to the above approaches, but uses PHP's sorting instead of database-level sorting, which can be significantly less efficient depending on the number of rows.
https://laravel.com/docs/9.x/eloquent-relationships#eager-loading
https://laravel.com/docs/9.x/eloquent-relationships#constraining-eager-loads
https://laravel.com/docs/9.x/collections#method-sortby
https://laravel.com/docs/9.x/collections#method-sortbydesc
I have 2 models: User and Transaction with user_id, type, and amount fields. I want to be able to select users with array of transactions grouped by type like so:
{ // User instance
'id': 123,
'username': 'John'
'transactions': [
'type1': '231', // `type`: `sum(amount)`
'type2': '543'
]
}
I will select arrays of users so I need this to load eagerly. How should I write an Eloquent model for that? I've read all docs but still don't know how to approach this.
You Can try Like :
$column = [DB::raw('SUM(order_qty) as volume'),
DB::raw('SUM(order_qty*price) as value')];
$oldValueVolume = OrderProduct::select($column)
->where('order_id', $ordersId)
->first();
User model:
public function transactions()
{
return $this->hasMany(Transaction::class, 'user_id');
}
So then the call:
User::with(
[
'transactions' => function ($q) {
return $q->groupBy(['type', 'user_id'])
->selectRaw('sum(amount) as sum, type, user_id');
}
]
)->get();
Notes
I used 'with' for eager loading.
You mentioned a custom structure (pairs) in a question:
This part
'transactions': [
'type1': '231', // `type`: `sum(amount)`
'type2': '543'
]
That's not what Eloquent does by-default, but you can always remap it.
I have three tables: users, organizations, organization_user. organization_user is a pivot table for the many-to-many relationship between users and organizations. The many-to-many relationships have been setup correctly in the corresponding models.
I need to obtain all users who are not associated with a given organization. How should this be done using eloquent. Below is what I have tried, but it is returning no results:
public function associate_user($organization_id){
$data = [
'organization' => \App\Organization::find($organization_id),
'users' => \App\User::whereDoesntHave('organizations', function($query) use ($organization_id){
$query->where('organization_id', $organization_id);
})
];
return view('admin.associateUser', $data);
}
You are never actually executing the query.
You need to call get() at the end of the query builder.
public function associate_user($organization_id) {
$data = [
'organization' => \App\Organization::find($organization_id),
'users' => \App\User::whereDoesntHave('organizations', function($query) use ($organization_id){
$query->where('organization_id', $organization_id);
})->get(); // Add the call to get()
];
return view('admin.associateUser', data);
}
Good day!
I have small problem with CakePHP 3. I have association like that:
$this->belongsToMany('AdminUserGroup',[
'classname' => 'AdminUserGroup',
'foreignKey' => 'admin_user_id',
'targetForeignKey' => 'group_id',
'joinTable' => 'AdminUsersGroups'
]);
I am returning records with this code:
public function getAll()
{
$ble = $this->find()
->contain(['AdminUserGroup' ]);
return $ble;
}
Until that it works, but when i want to select specified fields i have problem. When I add select method i don't see columns from contained table:
public function getAll()
{
$ble = $this->find()->select(['id', 'name', 'surname'])
->contain(['AdminUserGroup']);
return $ble;
}
So I added callback query:
public function getAll()
{
$ble = $this->find()->select(['id, name, surname'])
->contain(['AdminUserGroup' => function ($q) { return $q->select(['group_name']);}]);
return $ble;
}
But it still dont work. I can see only fields from main table. Fields with contained table doesn't appear.
{
"id": "8",
"name": "Ola",
"lastname": "BleBle",
"admin_user_group": []
},
Haw can I repair it?
The manual includes the following comments:
When you limit the fields that are fetched from an association, you must ensure that the foreign key columns are selected. Failing to select foreign key fields will cause associated data to not be present in the final result.
and
If you have limited the fields you are loading with select() but also want to load fields off of contained associations, you can pass the association object to select().
and
Alternatively, if you have multiple associations, you can use autoFields().
And there are helpful examples there. So:
$ble = $this->find()
->select(['id', 'name', 'surname'])
->contain(['AdminUserGroup' ])
->autoFields(true);
or if you're using 3.1 or higher:
$ble = $this->find()
->select(['id', 'name', 'surname'])
->select($this->AdminUserGroup);
From the example, it looks like the contain call may not be required in the second version, so I've left it out.
Try something like this.
$ble = $this->find()->select(['Table.id, Table.name, Table.surname'])->contain(['AdminUserGroup']);
I'm trying to give ability on user to see his orders. How can I query the database.. I'm trying something like this but I got empty page.. I mean nothing from database. May be my query ins't correct.
This is my controller
public function viewOrders() {
$user_order = self::$user->user_id;
$orders = Order::where('user_id', '=', $user_order);
return View::make('site.users.orders', [
'orders' => $orders
]);
}
Am I getting correctly user_id here? I'm not sure...
Update: I have this in my User model
public function orders() {
return $this->hasMany('Order', 'user_id', 'user_id');
}
Ok, so based on your route+button+model do it like this
$orders = self::$user->orders()->orderBy('order_id', 'asc')->get();
return View::make('site.users.orders', [
'orders' => $orders
]);
this should work.. You can remove orderBy clause if you don't need it.
If you have Authentication set properly you can do the following.
public function viewOrders(){
$user = Auth::user();
return view('site.users.orders',[
'orders' => $user->orders
]);
}
When you use the relationship without using the calling parentheses you get a collection of models which are queried if they're not already loaded. This is called lazy loading, if you want to load a relationship before accessing it you can use eager loading. In this case, it is not necessary though.