*/ public function origin(string $id): array { $row = DB::query()->fromSub(app(PublicBusinessLocations::class)->points(), 'origin_point') ->joinSub(ExistingBusiness::published()->select('id', 'public_title'), 'origin_business', 'origin_business.id', '=', 'origin_point.existing_business_id') ->where('origin_point.existing_business_id', $id)->whereNotNull('origin_point.point') ->select('origin_point.location_recorded_at', 'origin_point.location_source_reference', 'origin_point.location_source_date', 'origin_business.public_title')->selectRaw('ST_AsEWKT(origin_point.point) AS ewkt')->first(); if (! $row) { throw ValidationException::withMessages(['near_business' => 'A ficha de referência não tem um ponto primário público exacto utilizável. Escolha outra referência ou pesquise por área.']); } return ['id' => $id, 'title' => $row->public_title, 'ewkt' => $row->ewkt, 'source_reference' => $row->location_source_reference, 'source_date' => $row->location_source_date, 'location_recorded_at' => $row->location_recorded_at ? CarbonImmutable::parse($row->location_recorded_at)->toIso8601String() : null]; } public function available(string $id): bool { return DB::query()->fromSub(app(PublicBusinessLocations::class)->points(), 'point') ->whereIn('existing_business_id', ExistingBusiness::published()->select('id')) ->where('existing_business_id', $id)->whereNotNull('point')->exists(); } /** @param Builder $query * @param array $origin * @return array */ public function constrain(Builder $query, array $origin, float $radius): array { $query->leftJoinSub(app(PublicBusinessLocations::class)->points(), 'public_point', 'public_point.existing_business_id', '=', 'existing_businesses.id'); $withPoint = (clone $query)->whereNotNull('public_point.point')->count(); $withoutPoint = (clone $query)->whereNull('public_point.point')->count(); $query->whereNotNull('public_point.point')->whereRaw('ST_DWithin(public_point.point::geography, ST_GeomFromEWKT(?)::geography, ?)', [$origin['ewkt'], $radius * 1000]) ->addSelect('public_point.location_recorded_at') ->selectRaw('ST_Distance(public_point.point::geography, ST_GeomFromEWKT(?)::geography) / 1000.0 AS distance_km', [$origin['ewkt']]) ->orderBy('distance_km')->orderBy('existing_businesses.id'); return ['origin_id' => $origin['id'], 'origin_title' => $origin['title'], 'radius_km' => $radius, 'origin_recorded_at' => $origin['location_recorded_at'], 'origin_source_reference' => $origin['source_reference'], 'origin_source_date' => $origin['source_date'], 'with_public_point' => $withPoint, 'without_public_point' => $withoutPoint, 'source' => 'Localizações primárias públicas do cadastro de negócios do portal', 'method' => 'Distância geodésica em linha recta entre pontos publicados; não é distância por estrada nem validação da localização real.']; } }