use or and whereHas in eloquent - laravel

I have an orders table which contains 2 columns, user_id and unregistered_address. One of the columns has to be null as the user can either be registered with an address, or unregistered and just has address details.
Both user.address and unregistered_address are linked to a city. (user.address.city & unregistered_address.city)
I want to get the orders, for a specific cities, for both registered users and unregistered users. I am using eloquent's whereHas but it seems that when one of the two columns is null i get no results. This is my code:
$orders = Order::whereHas('user.address', function($query) use ($cityIds){
$query->whereIn('city_id', $cityIds);
})
->whereHas('unregisteredAddress', function ($query) use ($cityIds){
$query->whereIn('city_id', $cityIds);
})-> with(['user.address','unregisteredAddress'])->get();
Can anyone help? thanks.

Related

Laravel Relationship with 4 Table

I've got 4 tables:
users
teams
locations
users_teams
my teams table has relationship with locations. (it has location_id field)
users and teams have belongsToMany relationship with users_teams.
users doesn't have directly relationship with locations.
But I need to get coaches in this location.
It means; "get me all coaches; which are belongs to teams of that location"
But couldnt move any to make this.
How can this be possible?
how my "coaches" function of my "Location" model?
If your relationships are set up correctly, and assuming you have an enum column named type with coach as a possible value, you should be able to do something like this:
$coaches = User::where('type', 'coach')
->whereHas('teams.locations', function($query)
{
$query->where('name', 'some place');
})->get();

Lean Eloquent Results ->with() Eager Loading

I have a query I am working on that feeds into a javascript engine where there is a lot of information returned that isn't used in the javascript. The results are over 1MB and some of that is because of some eager loading. Here is the query:
$customers = Customer::where('customers.office_id', $officeid)
->where("customers.parent_id", null)
->with('lastAppointment')
->with('nextAppointment')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value")
->get();
The relationship of lastAppointment creates a returned nested object with all the columns from the appointments table, where I really only want a single column of start_at
If I do a ->leftJoin() I can limit my results using the final select like this:
->leftJoin(DB::raw("(select customer_id, MAX(start_at) as lastAppointment from appointments group by customer_id) as appt"), 'customers.id', '=', 'appt.customer_id')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value", "appt.lastAppointment")
I am just wondering if there is a way of doing something similar using ->with()?
You can use this code
->with('lastAppointment:_relation_id,start_at')
where _relation_id is customer_id or primary key of lastAppointment correspond model: depends on your table relation. See docs part of Nested Eager Loading
https://laravel.com/docs/5.5/eloquent-relationships#eager-loading p
The with function will accept a callback as the array value of the relationship key. You then have access to the underlaying query builder instance, I think this is what you want:
->with(['lastAppointment' => function($query) {
return $query->latest()->select('customer_id', 'start_at')
->groupBy('customer_id');
}])

How do I access relation of a relation in laravel eloquent

I have a user, group, group profile, group members, table.
Relation:
users belongs to many groups,
groups belongs to many users (name of function is groupMembers),
group has one groupProfile
I want to display the groups of a certain user with group profile and group member count.
Currently, I have this:
$userGroups = UserView::findOrFail($userId)
->groups()
->get();
I also have this: it return everything I want, except the fact that it is not user specific. (it returns all groups)
$userGroups = GroupView::with(['groupProfile'])
->withCount('groupMembers as groupMemberCount')
->get();
$userGroups = UserView::findOrFail($userId)
->groups()
->with(['groupProfile'])
->withCount('groupMembers as groupMemberCount')
->get()
Laravel relations return a query builder (if you call the function instead of the property) this means anything you can do with a collection of models you can do the same with the collection of related models.

Laravel Order by in one to many relation with second table column

Hi i have tables with one to many relation
sectors
id
name
position
seat_plans
id
name
sector_id
I just want to select all seat plans order by sectors.position. I tried
$seat_plans = SeatPlan::with(['sector' => function($q){
$q->orderBy('position');
}
])->get();
but it is not working. when i check The SQL it is generating query like
select * from seat_plans
can anybody please tell me how to do this?
I don't think you need a custom function for your use case. Instead try this:
$users = DB::table('seat_plans')
->join('sectors', 'seat_plans.sector_id, '=', 'sectors.id')
->select('seat_plans.*')
->orderBy('sectors.position')
->get();

Laravel Many to Many - 3 models

Some help with many to many relationships in Laravel:
Using the example for roles and users - basically:
a table for all the roles
a table for the users
and table with user_id and role_id.
I want to add to the third table, eg Year. basically the pivot table will have user_id, role_id and year_id.
I want to be able to make a query to pull for example all users assigned a specific role in a specific year. Eg All users with role_id = 2, and year_id = 1.
Any help will be appreciated
Before answering, I would like to suggest you not to put year on database like this.
All your tables should have created_at and updated_at which should be enough for that.
To filter users like you want. You could do this:
// This queries all users that were assigned to 'admin' role within 2013.
User::join('role_users', 'role_users.user_id', '=', 'users.id')
->join('roles', 'roles.id', '=', 'role_users.role_id')
->where('roles.name', '=', 'admin')
->where(DB::raw('YEAR(role_users.created_at)', '=', '2013')
->get();
This example may not be the precise query you are looking for, but should be enough for you to come up with it.
The best way to achieve a three way relation with Eloquent is to create a model for the table representing this relation. Pivot tables is meant to be used for two way relations.
You could have then a table called roles_users_year which could have data related to this 3 way relation like a timestamp or whatever...
A very late answer to a very old question, but Laravel has supported additional intermediate (pivot) table columns of at least Laravel 5.1 judging from the documentation, which hasn't changed at least through Laravel 6.x.
You can describe these extra columns when defining your many-to-many relationship:
return $this->belongsToMany(Role::class)->withPivot('column1', 'column2');
or in your case, the below would also do the job:
return $this->belongsToMany(Role::class)->withTimestamps();
which you can then access via the pivot attribute on your model:
$user = User::find(1);
foreach ($user->roles as $role) {
echo $role->pivot->created_at;
}
Note that the pivot attribute is on the distant relationship model (a single Role) and not on the relationship itself.
To get all the Roles assigned to Users in any given year, you might create a special relationship:
// User.php
public function rolesInYear($year) {
return $this->belongsToMany(Role::class)
->wherePivot('created_at', '>=', Carbon::create($year))
->wherePivot('created_at', '<', Carbon::create($year + 1));
}

Resources