Laravel Eloquent query on pivot table - laravel

I have the following tables in my database:
trips
start - date
end - date
type - string
users
name - string
age - integer
trip_users (pivot table for many to many relationship)
trip_id - integer
user_id - integer
I want to get users with age between x-y having trips between dateA and dateB using Eloquent.

Try adding a scope or two to your model.
// User.php
protected $with = ['trips'];
public function trips() {
return $this->belongstoMany(Trip::class);
}
// scope for age
public function scopeAgeBetween($query, $age1, $age2) {
return $query->whereBetween('age', [$age1, $age2]);
}
// scope for trip dates
public function scopeTripDatesBetween($query, $dateStart, $dateEnd) {
return $query->whereDate('trips.start', '>=', $dateStart)
->whereDate('trips.end', '<=', $dateEnd);
}
Then in your code:
User::with('trips')->ageBetween(20, 30)->tripDatesBetween('2020-01-01', '2020-02-01')->get();

I think you are looking for something like this:
User::query()
->whereBetween('age', [$x, $y])
->whereHas('trips', function ($q) {
$q->where('start', '>', $dateA)
->where('end', '<', $dateB)
})
->get();

Related

How to order by column in nested level relationship in Laravel and get first order by?

I have two model.finance has many price.i want to get just one price (last record according to time) for every finance.so used function and order by and first of each orderby.but this just works for first finance and the other i get null in the with relation.
public function prices()
{
return $this->hasMany(Price::class, 'finance_id');
}
public function finances()
{
return $this->belongsTo(Finance::class, 'finance_id');
}
$finances = Finance::with(['prices' => function ($query) {
$query->orderBy('created_at', 'desc')->first();
}])->get();
Create new relationship in your Finance model to get latest price:
public function latestPrice()
{
return $this->hasOne(Price::class)->latest();
}
Change your query as below:
$finances = Finance::with('latestPrice')->get();

Laravel: How to get data from 3 tables with relationship

I have 3 Tables:
Customers
id
name
Sales
customer_id
sale_date
Contacts
customer_id
contact_date
There aren't any update operations in the contacts table. Each process opens a new record in the contacts table. So, a user can have more than one records in the contacts table.
Here are my relations in models:
Customer
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function sales()
{
return $this->hasMany(Sale::class);
}
Contact
public function customer()
{
return $this->belongsTo('App\Customer', 'customer_id');
}
Sale
public function customer()
{
return $this->belongsTo('App\Customer');
}
I would like to have the latest record of the contacts table and make it join with the other related tables.
Here is the query which I have tried:
$record = Contact::groupBy('customer_id')
->select(DB::raw('max(id)'));
$result = Customer::query();
$result->where('is_active', 'YES');
$result->with('sales');
$result->whereHas('contacts', function ($q) use($record){
return $q->whereIn('id', $record)->where('result', 'UNCALLED');
});
return $result->get();
In the blade file, I get some result in foreach loops. However, I am unable to get the related data from the sales and contacts table.
#foreach($result as $item)
#foreach($item->sales as $sale) // Has no output and gives error: Invalid argument supplied for foreach()
#foreach($item->contacts as $contact) // Has no output and gives error: Invalid argument supplied for foreach()
Can anyone help me how to display the sale and contact date? Or any idea for how to improve this code quality?
If you want the latest record of the contacts you can declare another relationship on the Customer model, e.g.:
public function latest_contact()
{
return $this->hasOne(Contact::class)->latest('contact_date');
}
BTW you can always declare one or more hasOne additional relationship if you have a hasMany in place the foreign key used is the same.
In this way you can retrieve latest_contact eager loaded with your Customer model:
$customer = Customer::with('latest_contact')->find($id);
Or use this relationship in your queries, something like that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->whereHas('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
Or that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->with('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
If you want you can declare last_contact with the additional where:
public function latest_contact()
{
return $this->hasOne(Contact::class)
->where('result', 'UNCALLED')
->latest('contact_date');
}
This way all other queries should be easier.
I hope this can help you.
I'm not sure, but can you try to do the following:
return Customer::where('is_active', 'YES')
->with([
'sale',
'contact' => function ($query) use($record) {
return $query->whereIn('id', $record)->where('result', 'UNCALLED');
}
])->get();

Eloquent: How to find in text fileds via polymorphic relations?

Table structure
entity
id - integer
title - string
...
person
id - integer
name - string
...
customers
id - integer
body - text
concrete_id - integer
concrete_type - string
Models:
class Customer extends Model
{
...
public function concrete()
{
return $this->morphTo();
}
...
}
Person and Entity models have
public function customers()
{
return $this->morphMany(Customer::class, 'concrete');
}
How to find all customers where type is 'entity' and where entity.title = 'abc'?
I try do something like this,
$obj = Customer::whereHas(['concrete' => function($query){
$query->where('title', 'like', 'foo%');
}])->get();
but I have an error:
ContextErrorException in Builder.php line 825: Warning: strpos()
expects parameter 1 to be string, array given
For example, i can do this via native MySQL request:
SELECT *
FROM `customers`
LEFT JOIN `entities` ON (entities.id = customers.concrete_id )
WHERE `concrete_type` = "entity" AND entities.title LIKE "%foo%"
How to do this via Eloquent?
You work in right way, try this code:
Customer::whereHas('concrete', function ($query) {
$query->where('title', 'like', 'foo%')
})->get();
Or you can try another way:
Entity::has('concrete')->where('title', 'like', 'foo%')->get()
Rewrote the answer according to your raw MySQL:
Customer::
->join('entities', function($join)
{
$join->on('entities.id', '=', 'customers.concrete_id')
->where('entities.title', 'like', 'foo%');
})
->get();
I hope this helps :)
Laravel now not support 'whereHas' for 'MorphTo' relations.
Look laravel/framework issue 5429
And, if you want to do what is planned, you can use BelongsToMorph relation.
I added to Customer model:
public function entity()
{
return BelongsToMorph::build($this, Entity::class, 'concrete');
}
and after that, request working as need it:
Customer::whereHas('entity', function ($query) {
$query->where('entities.title', 'like', '%foo%');
})->get()->toArray();

How to fetch specific columns from multiple tables in Laravel 5?

I have 3 tables,
Country:
id,
name
Province:
id,
name,
country_id
City:
id,
name,
province_id
I have defined relationships in Model as follows,
Country Model:
public function Provinces()
{
return $this->hasMany('App\Province');
}
Province Model:
public function Country()
{
return $this->belongsTo('App\Country');
}
public function Cities()
{
return $this->hasMany('App\City');
}
City Model:
public function Province()
{
return $this->belongsTo('App\Province');
}
I am using the below query, but it overwrites all the data with Country name.
$city = DB::table('cities')
->join('provinces', 'cities.province_id', '=', 'provinces.id')
->join('countries', 'provinces.country_id', '=', 'countries.id')
->select('cities.name','provinces.name','countries.name')
->get();
I want to fetch a result of only City Name, Province Name, Country Name from these tables in laravel 5. Can you help me with that ?
Try just using as:
->select('cities.name as city_name', 'provinces.name as province_name', 'countries.name as country_name')
Would you try with this :
$city = DB::table('cities')
->join('provinces', 'cities.province_id', '=', 'provinces.id')
->join('countries', 'provinces.country_id', '=', 'countries.id')
->get(['cities.name', 'provinces.name', 'countries.name']);
I hope it helps you !
ok this is going to be a specific answer
learn about realtions in laravel and look at these
class example1 extends Model
{
public function examplefunction() {
return $this->hasMany('App\othermodel', 'id');
}
}
then use this query
$abc=example1::with('examplefunction')->get();
and there you go just take a look at a laravel relationship by using this u can get combined result
$products = User::select('id', 'email', 'first_name', 'last_name','country_code','mobile')->get()->toArray();
$gaurang = Ticket_Thread::select('body','title','resolv_note')

Laravel: Querying and accessing child objects in nested relationship with where clauses

I am trying to access the child objects of nested relationships that return many results from the parents object.
Let's say I have 4 models : Country - Provinces - Cities - Municipalities
Their relationships are as follows :
Country Model
class Country extends Eloquent
{
protected $table = 'countries';
public function provinces()
{
return $this->hasMany('Province');
}
}
Province Model
class Province extends Eloquent
{
protected $table = 'provinces';
public function cities()
{
return $this->hasMany('City');
}
public function country()
{
return $this->belongsTo('Country');
}
}
City Model
class City extends Eloquent
{
protected $table = 'cities';
public function municipalities()
{
return $this->hasMany('Municipality');
}
public function province()
{
return $this->belongsTo('Province');
}
}
Municipality Model
class Municipality extends Eloquent
{
protected $table = 'municipalities';
public function cities()
{
return $this->belongsTo('City');
}
}
Now what I am trying to do is get all municipalities in a given country that have a population over 9000 and are located in provinces that are considered West.
So far I have something like this :
$country_id = 1;
$country = Country::whereHas('provinces', function($query){
$query->where('location', 'West');
$query->whereHas('cities', function($query){
$query->whereHas('municipalities', function($query){
$query->where('population', '>', 9000);
});
});
})->find($country_id);
Now I can easily get the provinces with $country->provinces but I can't go any deeper than that.
EDIT1 : Fixing the belongsTo relationship as noticed by Jarek.
EDIT2: In addition to Jarek's answer, I wanted to share what I also found however Jarek's is probably the more proper method.
Instead of trying to go from top to bottom (Country -> Municipality) I decided to try the other way (Municipality -> Country) Here's how it works (and I tested it, also works)
$municipalities = Municipality::where('population', '>', 9000)
->whereHas('city', function($q) use ($country_id){
$q->whereHas('province', function($q) use ($country_id){
$q->where('location', 'West');
$q->whereHas('country', function($q) use ($country_id){
$q->where('id', $country_id);
});
});
})->get();
I have no idea if this is an actual proper way or if performance would be accepted but it seemed to do the trick for me however Jarek's answer looks more elegant.
Your Municipality-City is probably belongsTo, not hasMany like in the paste.
Anyway you can use hasManyThrough relation to access far related collection:
Country - City
Province - Municipality
Unfortunately there is no relation for 3 level nesting, so you can't do this just like that.
Next, your code with whereHas does not limit provinces to west and municipalities to 9000+, but only limits countries to those, that are related to them. In your case this means that result will be either Country (if its relations match these requirements) or null otherwise.
So if you really want to limit related collections, then you need this piece:
$country = Country::with(['provinces' => function($query){
$query->where('location', 'West');
}, 'provinces.cities.municipalities' => function ($query){
$query->where('population', '>', 9000);
}])->find($country_id);
This is applying eager loading constraints, and what it does is:
1. loads only West provinces for country with id 1
2. loads all the cities in these provinces
3. loads only 9k+ municipalities in these cities
Since you're not interested in cities, you could use hasManyThrough on the Province:
// Province model
public function municipalities()
{
return $this->hasManyThrough('Municipality', 'City');
}
then:
$country = Country::with(['provinces' => function($query){
$query->where('location', 'West');
}, 'provinces.municipalities' => function ($query){
$query->where('population', '>', 9000);
}])->find($country_id);
However in both cases you can't access the municipalities directly, but only like this:
// 1 classic
$country->provinces->first()->cities->first()->municipalities;
// 2 hasManyThrough
$country->provinces->first()->municipalities;
That being said, if you'd like to work with all those municipalities, you need this trick:
$country = Country::with(['provinces' => function($query){
$query->where('location', 'West');
}, 'provinces.municipalities' => function ($query) use (&$municipalities) {
// notice $municipalities is passed by reference to the closure
// and the $query is executed using ->get()
$municipalities = $query->where('population', '>', 9000)->get();
}])->find($country_id);
This will run additional query, but now all the municipalities are in single, flat collection, so it is very easy to work with. Otherwise you likely end up with a bunch of foreach loops.

Resources