I have created an api where I get offers that have 2 relationships in them:
- venues belongsToMany offer (manyToMany)
- days belongsToMany offer (manyToMany)
The offers then have the relationships synced and saved to them and in the returned json you can see the objects for days and venues.
What I am trying to do now is use haversine to get the distance of an offers venue lat/lng with the haversine value. I am currently using this eloquent query to get offers with their respective relationships:
$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'));
$offersWithDays = Offer::with(['days','venues'])->get();
$response = [
'now' => [],
'later' => [],
'tomorrow' => [],
'featured' => []
];
// validOffers are all offers that fall within this stuff
foreach ($offersWithDays as $offerAll) {
$relation = $offerAll->days()->get();
$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;
}
}
This works perfectly and I have no issues. I would now like to get the offers using haversine and the location of the venue attached to the offer but I am struggling to see how this would work in the eloquent query.
Here are the models for each relation:
Day
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');
}
}
Venue
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->belongsToMany('App\Offer','offer_venue');
}
}
Offer
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
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', 'distance_to_offer'];
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 venues()
{
return $this->belongsToMany('App\Venue', 'offer_venue', 'offer_id', 'venue_id');
}
}
Can anyone help me with this and shed some light?
==== edit ====
Here is sample output of json with Eloquent query that I need:
See days and venues. I want this in a raw query which I have started below but I have directly queries on the days table, it would be better to query directly from the offers table and join venues objects and days objects like in the attachment:
$query = DB::table('days AS od')
->select('o.*',
'ot.type',
'od.day',
'v.name AS venue_name',
'v.headline AS venue_headline',
'v.description AS venue_description',
'v.phone_number AS venue_phone_number',
'v.website AS venue_website',
'v.lat AS venue_latitude',
'v.lng AS venue_longitude', 'v.address AS venue_address',
// TODO : remove the 37, -122 lat lng co-ordinate pair that is hardcoded into this string and adjust the radius variable below
DB::raw('3959 * acos( cos( radians(37) ) * cos( radians( v.lat ) ) * cos( radians( v.lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) as distance'))
->join('day_offer AS odp', 'odp.day_id', '=', 'od.id')
->join('offers AS o', 'o.id', '=', 'odp.offer_id')
->join('offer_type AS otp', 'otp.offer_id', '=', 'o.id')
->join('types AS ot', 'ot.id', '=', 'otp.type_id')
->join('venues AS v', 'v.id', '=', 'o.venue_id');
$radius = '10000';
$query->having('distance', '<', $radius);
$query->orderBy('distance', 'desc');
$validOffers = $query->get();