Is there any chance to make laravel only loading specific items when the user is authenticated?
Assuming this code:
public function getCategory(Category $category){
$items = $category->products()->with(['otherRelation', 'favouriteUsers' => function($query){
$query->where('user_id', Auth::id())->select(['product_id', 'user_id']);
}])->withCount([
'views',
])->latest()->paginate(20);
At the moment the favouriteUsers relation would be loaded, either the user is authenticated or not, is there any way I can prevent laravel from executing this query unless the user is authenticated?
You need to have the relation favoriteProducts() in the User::class
That way it will be easier to get
$user = Auth::user();
$favoriteProducts = $user->favoriteProducts()
->with('otherRelation')
->withCount('views')
->whereHas('category', function($categoryQB) use($category) {
$categoryQB->where('id', $category->id);
})
->latest()->paginate(20);
Related
I have a table named 'Feedbacks' with 5 fields:
('id', 'user_id', 'instruction', 'description', 'fk_eleve')
The admin can create several recordings, here is a screenshot.
Here, I have a recording which is Menier Jeremy it's the student
In my rubric 'Eleves' (english: Student) we can see several recordings:
Here, Menier Jeremy has like email address test#gmail.com.
Menier Jeremy wants to connect...
There are 2 rubrics for now:
- Student Profil and Feedback
the user Menier Jeremy can see his profil
However, when the user wants to see his 'feedback'.
Unfortunately, I get the following error message:
SQLSTATE [42S22]: Column not found:
1054 Field Field 'email' unknown in where (SQL: select count (*) as aggregate fromreturnswhere email= test#gmail.com)
I have a problem with the email ?
public function index(Request $request)
{
$user = $request->user();
$feedbacks = Feedback::query()
->when($user->hasRole('admin') !== true, function (Builder $query) use ($user) {
$query->where('email', $user->email);
})
->when($request->has('search'), function (Builder $query) use ($request) {
$query->join('eleves', 'feedbacks.fk_eleve', '=', 'eleves.id')
->orderBy('eleves.nom', 'asc')
->where('eleves.nom', 'like', '%'.$request->input('search').'%');
})
->paginate(5);
return view('admin.feedbacks.index', compact('feedbacks'))
->with('display_search', $user->hasRole('admin'));
}
Do know you where is the problem?
Thank you a lot
Edit code #Watercayman
When, the user Jeremy Menier is connected, I see several recordings:
I have to retrieve only ID n° 1
public function index(Request $request)
{
$user = $request->user();
$feedbacks = Feedback::query()
->when($user->hasRole('admin') !== true, function (Builder $query) use ($user) {
\Auth::user()->load('feedbacks');
$feedbacksForThisUser = \Auth::user()->feedbacks;
})
->when($request->has('search'), function (Builder $query) use ($request) {
$query->join('eleves', 'feedbacks.fk_eleve', '=', 'eleves.id')->orderBy('eleves.nom', 'asc')->where('eleves.nom','like','%'.$request->input('search').'%');
})
->paginate(5);
return view('admin.feedbacks.index', compact('feedbacks'))
->with('display_search', $user->hasRole('admin'));
}
My model User:
public function feedbacks()
{
return $this->hasMany('App\Feedback', 'user_id', 'id');
}
My model Feedback
public function user()
{
return $this->belongsTo('App\User', 'id', 'user_id');
}
Sure, you can get the email for the users that have provided feedback using the FK. But I don't think you need all of the query you are using. I think you can make this much simpler. Because the user has a relation with the Feedback model (I assume through an Eleve model), you can simply eager load the relationship using the name search if you wish:
// Note I have removed the query() method you had in your original query
$feedbacks = Feedback::with('eleves', function ($query) use($request)
$query->orderBy('eleves.nom','asc')->where('eleves.nom','like','%'.$request->input('search').'%');
})->paginate(5);
To simplify the explanation I've removed the where from the query. To demonstrate I'll just use an if check before the query - you can make this more complex if you wish, but it is a little easier to see this way.
Something like:
if($request->has('search'){ do the query above }
else { $feedbacks = Feedback::with('eleves')->paginate(5); }
Then, because you have pulled the relations, you can then just get the email from any eleves that have been loaded:
$feedback->first()->eleve->email
So if you use the $feedbacks in a loop in your blade file:
#foreach($feedbacks as $feedback)
{{ $feedback->eleve->email }}
#endforeach
OK, I think because of the edit, the question is pretty different than what was first asked, so I'll add another answer rather than try to convey this in the comments.
I think you are asking that when the user tries to see his feedbacks, you are getting the SQL error. If the user is selecting the feedback option, it may only be the single user that is looking for his own feedbacks. I suggest you change your query to the reverse (pull the feedbacks from the user instead of pulling all the feedbacks and then getting user to match):
\Auth::user()->load('feedbacks');
$feedbacksForThisUser = \Auth::user()->feedbacks;
Or if you want to get another user's feedbacks (and the user has permission to see them), just query on that user:
$user = User::with('feedbacks')->find($idOfUserYouWantToSee);
$feedbacks = $user->feedbacks;
Same thing goes for if you want to search for feedbacks from a user with a specific name:
$user = User::with('feedbacks')->where('nom','like','%'.$request->input('search').'%')->first();
$feedbacksForSearchedUser = $user->feedbacks;
The key is to forget about the emails - the relationship will link all feedbacks to the user. You don't need to join, or query on the email. You always have it on the $user object. (i.e. $user->email will always work).
If you want to see ALL feedbacks from ALL users, this isn't really any harder, just query all users and eager load the feedbacks relationship:
$users = User::with("feedbacks")->get();
Then in your blade:
#foreach($users as $user)
// If you want to display only a special set of users to the Auth::User(), then do an if-check here
#if(\Auth::user()->hasPerm("someperm") && $user->isInSomeCategory)
#foreach($user->feedbacks as $feedback)
{{ $feedback->text // or whatever the field you want to show }}
#endforeach
#endif // The if check is totally optional in this - just giving you an example
#endforeach
EDIT: to show a simple index()
public function index(Request $request)
{
if(!\Auth::user()->hasRole('admin')) {
\Auth::user()->load('feedbacks');
$feedback = \Auth::user()->feedbacks;
}
elseif($request->has('search')) {
$user = User::with('feedbacks')->where('nom','like','%'.$request->input('search').'%')->first();
$feedbacks = $user->feedbacks;
}
return view('admin.feedbacks.index', compact('feedbacks'));
}
Note: to make this as simple as possible, I also removed:
->with('display_search', $user->hasRole('admin'));
You can check this on the Blade page because \Auth::user() is already loaded automatically.
Let's say I have the relation: Role has many Users. Role and user stores a code value.
If I want to select all roles that have users with same code, how would be this query using whereHas clause?
What I tried:
$roles = Role::whereHas('users', function ($users) {
// Obviously doesn't work but it is what I need to access.
$code = $users->first()
->role
->code;
return $users->where('code', $code);
})->get();
Use this:
$roles = Role::whereHas('users', function ($query) {
$query->whereColumn('users.code', 'roles.code');
})->get();
In my application, I have setup a User model that can have subscribers and subscriptions through a pivot table called subscriptions.
public function subscribers()
{
return $this->belongsToMany('Forum\User', 'subscriptions', 'subscription_id', 'subscriber_id');
}
public function subscriptions()
{
return $this->belongsToMany('Forum\User', 'subscriptions', 'subscriber_id', 'subscription_id');
}
My question is, what relationship should I use to get a list of paginated Post models (belong to a User) from the User's subscriptions?
You can use the whereHas method to filter based on relationships. Assuming your Post model has a user relationship defined, your code would look something like:
// target user
$user = \App\User::first();
$userId = $user->id;
// get all of the posts that belong to users that have your target user as a subscriber
\App\Post::whereHas('user.subscribers', function ($query) use ($userId) {
return $query->where('id', $userId);
})->paginate(10);
You can read more about querying relationship existence in the documentation.
You can do something like this
\App\Post::with(['subscriptions' => function ($query) {
$query->where('date', 'like', '%date%');
}])->paginate(15);
Or without any conditions
\App\Post::with('subscriptions')->paginate(15);
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.
How to List all rows from a DB where $id matches the logged user id.
I'm using default Auth from Laravel.
At the moment i can list them all with this method in my controller:
public function index(){
$invoices = Invoice::all();
return view('index', compact('invoices'));
}
But i just want the ones that are from this user which is logged in:
Something like
$invoices = Invoice::where('id', '=', Auth::user()->id);
Your code Seems almost right. I would do:
$invoice = Invoice::where('id', Auth::user()->id)->get();
So basically use the get in order to fetch a collection. And maybe I would separate the user id in a varaible in case that you change the authentication in the future ;)
When using any condition then of course you must need to add the get() method. Otherwise, you can't show your data.
$invoices = Invoice::where('id', '=', Auth::user()->id)->get();
This means that you want to see data on which user is logged in now