I wondered if it was possible to create a DB query and build into that query a similar approach to the way eager loading works with laravel eloquent.
I have a query in my controller that gets offers with their relationship which is this point is days and venue. My models are as follows:
Day model:
use Illuminate\Database\Eloquent\Model;
class Day extends Model
{
/**
* Get the offer days for the offer.
*/
protected $fillable = ['start_time','end_time'];
public function offers()
{
return $this->belongsToMany('App\Offer');
}
}
My offer model:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use DB;
class Offer extends Model
{
/**
* The database table used by the model.
*
* @var string
*/
use SoftDeletes;
protected $table = 'offers';
protected $dates = ['deleted_at'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $hidden = ['map_location', 'regular', 'name'];
protected $fillable = ['id','venue_id','type_id','day', 'venue_address','is_featured','repeater_days','image', 'venue_description', 'offer_headline','offer_subheader','offer_terms','venue_phone_number','venue_website', 'venue_name', 'venue_headline','venue_description','venue_latitude','venue_longitude','offer_when','offer_end_time','offer_start_time','offer_start_date','offer_end_date','featured_date','current_time','current_date'];
public static $rules = array(
'image' => 'image|mimes:jpeg,jpg,png,bmp,gif,svg'
);
protected $casts = [
'is_featured' => 'boolean',
'is_regular' => 'boolean',
'offer_when' => 'array'
];
/**
* Get the offers for the offer.
*/
public function days()
{
return $this->belongsToMany('App\Day','day_offer', 'offer_id', 'day_id');
}
public function types()
{
return $this->belongsToMany('App\Type', 'offer_type');
}
public function venue()
{
return $this->belongsToMany('App\Venue', 'offer_venue', 'offer_id', 'venue_id');
}
}
My venue model:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Venue extends Model
{
//
use SoftDeletes;
protected $table = 'venues';
protected $dates = ['deleted_at'];
protected $fillable = ['id','address','description','phone_number','website','name', 'headline','lat','lng','days'];
public static $rules = array(
'name' => ''
);
protected $casts = [
'lat' => 'float(10,8)',
'lng' => 'float(11,8)'
];
public function offers()
{
return $this->belongsTo('App\Offer','offer_venue');
}
}
I want to get each relationship and load the results into the query so that i have the main object and the relationships like so:
The problem with this is it looks great and works and the eloquent is so simple but I cannot do further more complex things on it like:
"Getting the distance from the venue and loading the offers based on the distance of the venue with a haversine formula I used."
This would require a query like so and in an ideal world the distance would be in the main returned offer object on every offer not within the venue[] relationship:
$radius = '10000';
$query->having('distance', '<', $radius);
$query->orderBy('distance', 'desc');
Where i am becoming stuck is that I do not know how to write the proper DB query to do exactly what you see in the image above which is what I want and eventually I can then do the "offers based on the location" and order them.
I have started with the eloquent query below:
public function indexAll(Offer $offer)
{
$mytime = Carbon::now('Europe/London');
$time = $mytime->format('H:i');
$timeInt = $this->hourMinToInteger($time);
$today = $mytime->format('m/d/Y');
$day = strtolower($mytime->format('l'));
$tomorrow = strtolower(Carbon::now()->addDay(1)->format('l'));
// $offers = Offer::all();
//$haversine = DB::raw('3959 * acos( cos( radians(37) ) * cos( radians( $offer ) ) * cos( radians( $offer ) - radians(-122) ) + sin( radians(37) ) * sin( radians( $offer ) ) ) as distance');
$offersWithDays = Offer::with([
'days' => function($allDays){
$allDays->select('id','day');
},
'venue' => function($query){
$query->select('lat','lng','address','description','phone_number','website','name', 'headline')
->addSelect(DB::raw('3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) as distance')
);
}
])
->get();
$response = [
'now' => [],
'later' => [],
'tomorrow' => [],
'featured' => []
];
// validOffers are all offers that fall within this stuff
foreach ($offersWithDays as $offerAll) {
$relation = $offerAll->days()->get();
$relationVenues = $offerAll->venue();
//var_dump($relation);
$theDays = array();
foreach ($relation as $theDay) {
$theDayObj = $theDay->day;
array_push($theDays,$theDayObj);
}
extract($theDays);
if ($offerAll->is_featured) {
$response['featured'][] = $offerAll;
}
if (in_array($day,$theDays) && $offerAll->offer_start_time < $time) {
$response['now'][] = $offerAll;
}
if (in_array($day,$theDays) && $offerAll->offer_start_time > $time) {
$response['later'][] = $offerAll;
}
if (in_array($tomorrow,$theDays)) {
$response['tomorrow'][] = $offerAll;
}
}
return $response;
}
What I would like to know is that the code I have created in eloquent is as easily done with a normal DB query with joins and selects in it?