I have user role relation (many to many) defined as follows in Role model:
public function users()
{
return $this->belongsToMany('App\User');
}
Now I want to show all users in certain role. I execute the following:
$list = Role::find(1)->users()->select('name')->orderBy('name')->paginate(10);
Here $list contain all users that belong to role with id 1 and that is correct. But the problem is: when adding breakpoint on $list it shows that: all user model's attributes are retrieved just like select('name') has no effect.
This is a big problem especially when i want to return the $list as json. User password is retrieved even though it's in the $hidden array of User Model.
My question is:
why paginate() on querybuilder does not respect select() nor attributes in model's $hidden array?
Note: I know that there is other solutions to achieve what I want. I just want an answer to my question to figure out what is going on?
select('name') has no effect because paginate() method takes columns as second parameter
$list = Role::find(1)->users()->orderBy('name')->paginate(10, ['name']);
You can read more about parameters and methods here
https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Builder.html#method_paginate
Since users have the role_id then why don't you fetch the users as:
User::where('role_id', 1)->orderBy('name')->paginate(10);
You are basically getting a role and then fetching a list against that role.
Related
I am a bit curious about the performance of my app. Therefore I just want to know that when the queries for the hasMany and belongsTo are executed?
Here is the relevant sample code for example:
class Article extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
class User extends Authenticatable
{
public function articles()
{
return $this->hasMany(Article::class);
}
}
If I fetch all the user with:
$user = App\User::find(1);
Now if I need the articles for this user, I would do it like this:
$user->articles;
This in the backend in Laravel executes the following query:
SELECT * FROM articles WHERE user_id = 1
and it will give me all the articles for the user. So far so good. But in most scenarios, I will just need the information of the user and would not want Laravel to execute that query for getting articles of the user. The same I need for the belongsTo.
My Question is, does laravel execute the query for articles at the time when I execute the query for User? or it executes the query at the time when I call:
$user->articles;
This is just an example scenario. I have many real world scenarios where one model has relationship with many other models.
So here if I fetech all users with:
$users = App\User::all();
Will it execute that articles query for all users one by one? or at once? and at what time does it query for the articles? if I do not call:
$user->articles;
does it still query database for articles of the user?
Update
So after some efforts I found out that when you query a user/users:
$user = App\User::find(1);
it does not get the articles for the user until you call articles on it:
$user->articles;
But now there is another problem. If I am fetching all users and I also need the articles for each of them, I will have to do something like this:
$users = App\User::all();
and then in a loop I will get the articles for each of the users, and the articles query will be executed for each user separately. Which is still a performance concern. If there are 100 users so I will have to query users table once with all() method and then 100 queries for articles of each user. Which is not what I want. I need one query for users and one query for articles. Once the articles for all users have been brought then the relevant articles should be assigned to each user.
But it seems like there is no such thing in Laravel. I will have to get user_ids of all the users and make a query like this:
$articles = \App\Article::whereIn("user_id", $user_ids_array)->get();
Then I will have to loop through the articles and assign each user their articles.
I just wanted to find a short way using Laravel.
But it seems like that is not possible for now. I wish if this would be available in future versions of Laravel.
You need to read more about Eager-loading in Laravel.
In your case, you need to do :
$users = App\User::with('articles')->get();
The "with" method is here exactly for this.
Another alternative to get all articles after your initial query call is this :
$users = App\User::get();
$users->load('articles');
Of course, this is implying you have a working relationship and a "public function articles() {}" in your User Model. Probably something like this :
public function articles() {
return $this->hasMany(Article::class);
}
You can read more about this feature here : https://laravel.com/docs/6.x/eloquent-relationships#eager-loading
I used to have a query like this
$topReferrals = User::orderBy('user_referrals', 'DESC')->get();
Recently I changed my database structure to not count user_referrals for each user in an int datatype, but to have a column for each user called referred_by and have its value who they have been referred by, I need to adapt my query to work with the new system.
I'm not quite sure how I would go about this, I was hoping someone could help?
Eloquent offers several means of counting relations. One approach would be to set the $withCount property on the User model:
// assuming your model has a referrals method.
protected $withCount = ['referrals'];
This will append an attribute on each queried model that can be used in subsequent queries or collection modifications.
User::all()->sortByDesc('referrals');
Just add referred_by column in User table as it denotes foreign key linked to the user.
Use query below to get count of users that have been referred for each referrer:
User::where('referred_by', $referred_user_id)->count();
OR
User::where('referred_by', $referred_user_id)->orderByDesc('referred_by')->get();
Note: Just make sure you have created a table for referrers to store all the details for referrers in case you want to grabs other data regarding them. You just need to add relations to the User model to directly access to the database.
public function hasReferrers () {
$this->hasOne('App\Referrer');
}
Where App\Referrer is model for your referrers table.
As I’ve understood the question, I think this is how I’d approach getting the number of referrals per user..
$all = User::all();
foreach ($all as $current) {
$current->referrals = User::where('referred_by', $current)->count();
}
$all->sortBy('referrals');
$all should now be a list of users sorted by the number of referrals.
Say I have an orders table and a users table and a guests table, for a company who accept orders from both users and guests.
I also have a is_guest boolean on the orders table which lets me know quickly whether the order has been made by a guest or a registered user.
I have a model method called customer which returns the eloquent relation like so:
public function customer()
{
return $this->is_guest ? $this->belongsTo('Guest', 'user_id') : $this->belongsTo('User', 'user_id');
}
This works very well when I pass orders to the view and access the customer's data like so:
// Maps to either $order->user->firstname OR $order->guest->firstname
echo $order->customer->firstname;
But when I try to use this functionality when using eager loading it doesn't quite work:
$orders = Order::with('customer')->get();
return Response::make($orders);
It only returns the eager loaded customer data for either the user or the guest and never both.
I'm wondering why this is and how to get round it?
Is it because of the way the eager loading works - it only calls the customer() method once just as it only hits the database once, so whatever the first result of the query is, it will use that to determine the rest of the query too?
If I am trying to get a JSON response of all the order data with all of the customer's details too, how would I do that?
Thanks.
UPDATE
Yes, turns out I was abusing the Laravel relationship method by adding a condition.
Using the polymorphic relations is a much better approach as suggested by #lukasgeiter.
http://laravel.com/docs/4.2/eloquent#polymorphic-relations
I did have trouble loading other relations based on the polymorphic relation. For example if both User and Guest had corresponding tables UserDetail and GuestDetail then I couldn't get the eager loading to work. So I added this to both the User and Guest models:
protected $with = ['detail'];
This means that whenever the customer polymorphic relation is eager loaded, then both User and Guest will load their relationships automatically. I think I could have also used the 'lazy loading' functionality $order->load('customer') but I didn't try it out.
public function detail()
{
return $this->hasOne('UserDetail');
}
Thanks guys.
A company hasMany users, this relationship is achieved through a pivot table. I want to be able to get the company.ID of the company an individual user is related to:
$company_id = User::find(Auth()->$id)->companies->get('$id');
Unfortunately, I have also tried the pluck() method, but to no success. How can one retrieve a specific value from a formula like this?
in your user model you should add the relationship belongsTo (if the user belongs only to one company)
public function company(){
return belongsTo('company');
}
then you can get the id of the company like this
$user = User::find($id);
$company = $user->company;
$companyId = $company->id;
I hope this will be helpful
Well if the User can only be associated with one company, then your relationship should reflect this. Then you'd be able to use eager loading to do something like this:
// assumes the user is logged in
$user = Auth::user();
// assuming your relationship is set up correctly, you can do this:
echo $user->company->id;
You'd need to post the code relating to your models / relationships for a fuller answer, however.
how can I pull all the posts of a certain user? should i foreach all the posts of a certain user? Like if user1 posted something and I want to pull out whatever he posted and only shows when he's logged in.
In Laravel, if you are using Eloquent relationships things would look something like this.
First, define your relationships within your models. If you're following the example below, I'm going to assume the following.
Your users table in database is named users. Your posts table in
database is named posts, and has an integer column named user_id
corresponding to the id of the user the post belongs to. If your
table and column names are different, make sure you read the Laravel
docs to learn how to set custom table names and column names for
Eloquent models.
app/models/User.php
<?php
class User extends Eloquent {
// All the default User.php stuff....
public function posts()
{
return $this->hasMany('Post');
}
}
app/models/Post.php
class Post extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
After we've defined those relationships, you can get a particular user using something like this.
$user = User::find(1); // This will get the user with an ID of one.
Then, you retrieve that user's posts, we can use the Eloquent relationship we defined earlier.
$posts = $user->posts()->all();
If the user is already logged in, you can user the Auth class to do this for the logged in user.
$posts = Auth::user()->posts()->all();
You'll now realize that ->posts() actually returns a Collection, and you can use all of the Query and Eloquent methods on that collection as normal.