Laravel Eloquent Query Issue with checking data through relationship - php

I have a problem with retrieving the data from Users table:
User:
-id int
-name string
-compartment_id int
This is related with compartments table:
Compartment:
-id int
-name string
-country_id int
Which is related to countries table:
Country:
-id int
-name string
User model:
public function compartment()
{
return $this->belongsTo(Compartment::class, 'compartment_id');
}
Compartment model:
public function country()
{
return $this->belongsTo(Country::class, 'country_id');
}
public function users()
{
return $this->hasMany(User::class);
}
Country model:
public function compartments()
{
return $this->hasMany(Compartment::class);
}
I am using Livewire PowerGrid to display data in data tables.
I wanted to get All Users with compartment_id = null and All Users that compartment->country_id is equal to Auth::user()->compartment->country_id.
I'm stuck with:
User::whereIn('compartment_id', Compartment::select('country_id')
->where('country_id', Auth::user()->compartment->country_id))->where('compartment_id', null);
It must be the builder, without ->get() because it's interpreted by PowerGrid correctly.
Can someone instruct?

You can use the below query,
You will get all users without compartment assigned and those whose compartment country matches with compartment
User::whereHas('compartment',function($q){
$q->where('country_id', Auth::user()->compartment->country_id);
})
->orWhereNull('compartment_id');

I found the solution by myself.
User::whereIn('compartment_id', Compartment::select('compartment_id')
->where('country_id', Auth::user()->compartment->country_id))
->where('id', '!=', Auth::user()->id)
->orWhereNull('compartment_id');
I thought wrongly (by mistake) that it should be AND clause, not OR.
Thanks all for help.

Related

Laravel Eloquent wherePivot method returns column 'pivot' not found

I have a many-to-many database relationship set up in an existing Laravel installation between users and agencies.
On the frontend I'm using a drop down filter to send an agency_id to the server that is supposed to filter/return all the users by this agency_id variable.
In my models:
User.php
/**
* The agencies that belong to the user.
*/
public function agencies()
{
return $this->belongsToMany('App\Agency');
}
Agency.php
/**
* The users that belong to the agency.
*/
public function users()
{
return $this->belongsToMany('App\User');
}
When I query the database, I check if the agency parameter is present in the header
->when($request->agency, function ($q) use ($request, $schema) {
// Determine whether agency_id foreign key exists or if it's a pivot relationship
if(Schema::hasColumn($schema, 'agency_id'))
{
return $this
->repository
->whereAgency($q, \Hashids::decode($request->agency)[0]);
}
else
{
return $this
->repository
->whereAgencyPivot($q, \Hashids::decode($request->agency)[0]);
}
})
In the repository I do the following:
public function whereAgencyPivot($q, string $agency)
{
return $q->wherePivot('agency_id', $agency);
}
This returns the following error:
Column not found: 1054 Unknown column 'pivot' in 'where clause'
I have also tried:
public function whereAgencyPivot($q, string $agency)
{
return $q->agencies()->where('agency_user.agency_id', $agency);
}
which returns:
Call to undefined method Illuminate\Database\Eloquent\Builder::agencies()
Is there anything I'm missing?
So you want to get all the users against a pre selected agency which is linked with users in many-many relationship. Please correct me if I have miss understood.
To get many to many relationship
Agency::with('users')->where('id', 1)->get(); // id is injected dynamically.
To conditionally load relationship
if(some condition) {
$agency->load('users'); // It'll fetch all users against the given agency.
}
To get only users information
$data = Agency::with('users')->where('id', 1)->first();
$data->users; // gives you only users collection
The answer ended up being:
return $q->whereHas('agencies', function($query) use ($agency) {
$query->where('id', $agency);
});

Make Laravel Accessor return query results

UPDATED:
I'm trying to add my own attribute with subquery results to the results of main query.
Now, I have Many-To-Many relation between three tables: Tournaments, Participants and Users.
Here is the defining of relation in Tournaments model:
public function users() {
return $this->belongsToMany('App\User', 'Participants', 'Id_tourn', 'Id_user')->withPivot('Rating');
}
The structure of tables is:
Users:
-Id
-Name
Participants:
-Id
-Id_user
-Id_tournament
-Final
-Final_place
Tournaments:
-Id
-Name
I need to have extra Winners attribute in my final query result where I'll have info of first three places.
Following the documentation, I've created an accessor and tried different variants:
That just freeze the system. Nothing happenes and in 30 second I get timeout error.
public function getWinnersAttribute() {
return Tournaments::where("Id","=",$this->attributes['Id'])->where("Finals","=",1)->limit(3)->orderBy("Final_place","asc")->get();
}
This returns an error that "finals" column is not fount in Tournaments table, so $this doesn't have relation:
public function getWinnersAttribute()
{
return $this->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This returns blank white page without anything:
public function getWinnersAttribute()
{
return $this->with('users')->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This return "Winners" attribute empty:
public function getWinnersAttribute()
{
return $this->with("users")->where("Finals","=",1)->limit(3)->orderBy("final_place","asc");
}
I've created $appends variable to apply the accessor: protected $appends = ['Winners'];
However, I've checked the accessor, it works. If I return just:
public function getWinnersAttribute()
{
return "123";
}
it works fine and I get "123" inside "winners" attribute of main query result.
The main query is:
Tournaments::with(['users'])->get();
The Finals column is in pivot table of Many-To-Many relation.
UPDATED:
When I try to return query to that Model without relation:
public function getWinnersAttribute($value)
{
return $this->where("Finals",'=',2);
}
I get nothing in winners attribute as well. Like the subquery is not executed.
And if I add get() in the end of return:
return $this->where("Finals",'=',2)->get();
I get blank white page.
How can I solve that problem?
Thanks a lot.
If the getWinnersAttribute is on the Tournament model that means you already have a Tournament model you are calling by doing for example Tournament::find(1)->winners In your attribute you are trying too find the model again, and that could make it a forever loop trying to find a new one already having one etc. try using $this instead
public function getWinnersAttribute()
{
return $this->where("finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}

Laravel belongsToMany not returning results

I have the following schema set up:
users:
id
departments:
id
department_user:
id
department_id
user_id
I also have the following relationships set up:
User Model
public function departments()
{
return $this->belongsToMany('App\Resources\Eloquent\Models\Department', 'department_users');
}
Department Model
public function users()
{
return $this->belongsToMany(User::class, 'department_users');
}
For some reason, when I am trying to access through the user model $user->departments, it doesn't work - but $department->users does.
Outputting the eloquent query is as follows:
select `departments`.*, `department_users`.`user_id` as `pivot_user_id`, `department_users`.`department_id` as `pivot_department_id` from `departments` inner join `department_users` on `departments`.`id` = `department_users`.`department_id` where `department_users`.`user_id` is null
I can't seem to figure out why it is looking to see if department_users.user_id is null, when it should be looking for the user's id.
Any ideas?
Why don't you set up your models like it is suggested in the documentation here:
So your models would look something like this:
User Model
public function departments()
{
return $this->belongsToMany('path\to\your\model\Department');
}
Department Model
public function users()
{
return $this->belongsToMany(path\to\your\model\User);
}
Eloquent will join the two related model names in alphabetical order.So you don't need extra arguments when defining your relationship and Laravel also by default, makes model keys present on the pivot object. And then you can do something like this:
$department = path\to\your\model\Department::find(1);
foreach ($department->users as $user) {
echo $user;
}
For some reason, if I make the relationship the following - it works.
return $this->belongsToMany(Department::class, 'department_users')->orWhere('department_users.user_id', $this->id);
If anyone knows why, please let me know

Laravel belongsTo returning null when using 'with'

I'm just getting started with Laravel so please forgive any noobness.
I have a User and Order model, a user has many orders:
# Inside User model
public function orders()
{
$this->hasMany('Order');
}
# Inside Order
public function user()
{
return $this->belongsTo('User');
}
// Not sure if this is upsetting anything (also in Order)
public function products()
{
return $this->belongsToMany('Product');
}
So I think I have the above right.
But when I do this:
$users = User::with('orders')->find(1);
return $users;
I get Call to a member function addEagerConstraints() on null.
However, if I do it the other way around, it works great:
$orders = Order::with('User')->get();
return $orders;
What am I doing wrong / what don't I understand?! Or is my problem bigger than I think?
Database:
The problem is you don't have return for your orders relationship. It should be:
public function orders(){
return $this->hasMany('Order');
}
You should also use your relationships case sensitive. you showed:
$orders = Order::with('User')->get();
is working, but you should rather use
$orders = Order::with('user')->get();
to avoid extra queries to your database in future
For anyone else that runs across this, I was having the same issue, but my problem was that I had the foreign/local keys swapped. Example:
// This is correct for hasX relationships
public function user() {
return $this->hasOne('App\Models\User', 'user_id', 'local_key_user_id');
}
// This is correct for belongsTo relationships
public function user() {
return $this->belongsTo('App\Models\User', 'local_key_user_id', 'user_id');
}
Notice that for hasX relationships, the foreign key is the second parameter, and the local key is the third. However, for belongsTo relationships, these two are swapped.
Probably doesn't answer this particular question but it relates to the title. I had the same issue here is the wrong query
$offer = Offer::with([
'images:name,id,offer_id',
'offer_options:offer_option,value,id,offer_id',
'user:id,name,avatar'])
->select(['id', 'views', 'type', 'status'])
->where('id', $id)->get();
the model look like this
class Offer extends Model {
function user(): BelongsTo {
return $this->belongsTo(User::class);
}
}
The User
class User extends ..... {
function offer(): HasMany {
return $this->hasMany(Offer::class);
}
}
The issue with the query is I was not selecting user_id, i.e in my select function user_id column was not included and that is why I was getting null for user
according to Laravel 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.
So the correct query is
$offer = Offer::with([
'images:name,id,offer_id',
'offer_options:offer_option,value,id,offer_id',
'user:id,name,avatar'])
->select(['id', 'views', 'type', 'status','user_id'])
->where('id', $id)->get();

Laravel eager relationships empty query

I have 3 tables : hotels, hotels_data, hotels_types
Table hotels have id, type, stars, etc... type field is set as foreign key referencing type_id in hotels_types. I'm managing to get the correct data from hotels_data but have an empty result on getting hotels_types title and I don't understand why.
The code is the following :
class Hotel extends Eloquent {
public function getList() {
$data = Hotel::select('id','stars')->with('HotelData', 'HotelType')->paginate(10);
return View::make('hotels.index')->with('hotels', $data);
}
public function HotelData()
{
return $this->hasOne('HotelsData')->select('id','hotel_id','title');
}
public function HotelType()
{
return $this->hasOne('HotelType','type_id', 'type')->select('id','type_id','title');
}
}
You're using the wrong relationship for HotelType()
Your Hotel model should use the inverse of hasOne, which is belongsTo, because it contains the foreign key to HotelType (when a table contains a foreign key, it always belongs to the table being pointed to).
The following should work:
public function hotelType() {
return $this->belongsTo('HotelType','type', 'type_id')->select('id','type_id','title');
}
I've obtained the desired result with the following:
Hotel::select('hotels.*','hotels_types.title as type')
->join('hotels_types', 'hotels.type', '=', 'hotels_types.type_id')
->with('HotelData');

Categories