Я создал API, где я получаю предложения, в которых есть 2 отношения:
Затем предложения синхронизируются и сохраняются в отношениях, а в возвращенном json вы можете видеть объекты по дням и местам.
То, что я сейчас пытаюсь сделать, это использовать haversine, чтобы получить расстояние от места проведения предложения lat / lng до значения haversine. В настоящее время я использую этот красноречивый запрос, чтобы получить предложения с соответствующими отношениями:
$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;
}
}
Это отлично работает, и у меня нет проблем. Теперь я хотел бы получить предложения, используя haversine и местоположение места, прикрепленного к предложению, но я изо всех сил пытаюсь увидеть, как это будет работать в красноречивом запросе.
Вот модели для каждого отношения:
День
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');
}
}
место встречи
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');
}
}
Предлагает
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');
}}
Может ли кто-нибудь помочь мне с этим и пролить немного света?
==== изменить ====
Вот пример вывода JSON с запросом Eloquent, который мне нужен:
Смотрите дни и места. Я хочу это в необработанном запросе, который я начал ниже, но у меня есть прямые запросы к таблице дней, было бы лучше сделать запрос непосредственно из таблицы предложений и объединить объекты мест и объекты дней, как в приложении:
$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();
Я предполагаю, что в конце концов вы хотите, чтобы иметь возможность найти предложения на основе пользовательских координат? Если вы получите 10 000 предложений или мест в будущем — вы не хотите проходить их один за другим, рассчитывать расстояние и затем отображать самые близкие совпадения — это было бы просто невозможно.
Я бы предложил геопространственные запросы (поддерживаемые MySQL) — например. дайте мне 50 предложений (или мест), расположенных в радиусе 5 км от широты X и долготы Y.
К сожалению, Eloquent не поддерживает геопространственные запросы, поэтому вам нужно будет выполнять необработанные запросы, используя фасад БД, но производительность будет отличной — вы получите результаты мгновенно.
Это разумный путь, по моему мнению. Разбирая весь набор предложений / мест проведения, выполнение вычисления расстояния как Черта иррационально.
Других решений пока нет …