In Laravel 5.7 I have read the Has Many Through documentation but I still can't use it correctly for my case.
Here's the DB:
Analytics
id
data
subscriber_id
Subscribers
id
city_id
Cities
id
name
I need the Analytics model to get data from Analytics
with subscribers.id
and cities.name
What I have done:
Connected Analytics and Subscribers models
<?php
class Analytics extends Model
{
public function subscriber()
{
return $this->belongsTo('App\Models\Subscriber');
}
}
class Subscriber extends Model
{
public function analytics()
{
return $this->hasMany('App\Models\Analytics');
}
}
Made a request that gets the data from the Analytics
table with subscribers data:
$results = Analytics::where('survey_id', '4')
->with('subscriber')
->whereDate('created_at', '>=', $last_survey_date)
->orderBy('data')
->get();
If anybody has any ideas how to get city names, please, share it.
Thank you Nick Surmanidze and Namoshek for your answers! I have found the way it works last night:
class Subscriber extends Model
{
public function analytics()
{
return $this->hasMany('App\Models\Analytics');
}
public function subscriberCity()
{
return $this->belongsTo('Modules\Directories\Entities\City', 'city_id', 'id');
}
}
class City extends Model
{
public function subscriber()
{
return $this->hasMany('App\Models\Subscriber');
}
}
And the needed result can be get by this way:
$results = Analytics::where('survey_id', '4')
->with(['subscriber' => function($i){
$i->with(['subscriberCity']);
}])
->whereDate('created_at', '>=', $last_survey_date)
->orderBy('data')
->get();
// maybe this will work for you?
class Analytics extends Model
{
public function subscriber()
{
return $this->belongsTo('App\Models\Subscriber');
}
public function cities() {
return $this->hasManyThrough('App\City', 'App\Subscriber');
}
}
I'm not sure if I understood your request correctly. Do you want to get all Analytics
of Subscribers
of a given City
? Or do you want the city name of an analytics' subscriber? Either way, here are both solutions.
To get all analytics for subscribers of a given city:
$city = 'Vienna';
$results = Analytics::query()
->with('subscriber')
->whereHas('subscriber', function ($query) use ($city) {
$query->whereHas('city', function ($query) use ($city) {
$query->where('name', $city);
});
})
->where('survey_id', '4')
->whereDate('created_at', '>=', $last_survey_date)
->orderBy('data')
->get();
Or to get the city name for an analytics record, you have two options. One is to use the Laravel eager loading for relationships, which works, but will probably load a lot of unnecessary data into memory:
$results = Analytics::query()
->with('subscriber.city') // you can nest relationships as far as they go
->where('survey_id', '4')
->whereDate('created_at', '>=', $last_survey_date)
->orderBy('data')
->get();
foreach ($results as $analytics) {
$city = $analytics->subscriber->city->name;
}
The other is to join the tables yourself and select only the necessary data:
$results = Analytics::query()
->join('subscribers', 'subscribers.id', '=', 'analytics.subscriber_id')
->join('cities', 'cities.id', '=', 'subscribers.city_id')
->where('analytics.survey_id', '4')
->whereDate('analytics.created_at', '>=', $last_survey_date)
->orderBy('analytics.data')
->select('analytics.*', 'cities.name as city_name')
->get();
foreach ($results as $analytics) {
$city = $analytics->city_name;
}
Beware that you could use select('analytics.*', 'cities.name')
, but this will override a name
column selected of the analytics
table if one exists. So it is better to use a column alias with as col_alias
.