kithkin/app/Models/Location.php

129 lines
3.9 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $table = 'locations';
protected $fillable = [
'display_name',
'place_name',
'raw_address',
'street',
'city',
'state',
'postal',
'country',
'lat',
'lon',
'phone',
'hours_json',
];
protected $casts = [
'lat' => 'float',
'lon' => 'float',
];
/**
* find an existing location by its normalized components or create it.
* backfills lat/lon/raw_address/place_name if the found row is missing them.
*/
public static function findOrCreateNormalized(array $norm, ?string $raw = null): self
{
$lookup = [
'display_name' => $norm['display_name'] ?? null,
'street' => $norm['street'] ?? null,
'city' => $norm['city'] ?? null,
'state' => $norm['state'] ?? null,
'postal' => $norm['postal'] ?? null,
'country' => $norm['country'] ?? null,
];
$existing = static::where($lookup)->first();
// fallback: try matching by the raw label (useful for seeds like "Home")
if (!$existing && $raw) {
$existing = static::where('display_name', $raw)
->orWhere('raw_address', $raw)
->first();
}
if ($existing) {
$changed = false;
// backfill coords if missing (and we have them)
$hasNewCoords = (!empty($norm['lat']) || !empty($norm['lon']));
if (($existing->lat === null || $existing->lon === null) && $hasNewCoords) {
$existing->lat = $norm['lat'] ?? $existing->lat;
$existing->lon = $norm['lon'] ?? $existing->lon;
$changed = true;
}
// backfill raw address if missing
if ($raw && $existing->raw_address === null) {
$existing->raw_address = $raw;
$changed = true;
}
// backfill place_name if missing
if ($existing->place_name === null && !empty($norm['place_name'])) {
$existing->place_name = $norm['place_name'];
$changed = true;
}
if ($changed) {
$existing->save();
}
return $existing;
}
return static::create([
'display_name' => $norm['display_name'] ?? ($raw ?: 'Unknown'),
'place_name' => $norm['place_name'] ?? null,
'raw_address' => $norm['raw_address'] ?? $raw,
'street' => $norm['street'] ?? null,
'city' => $norm['city'] ?? null,
'state' => $norm['state'] ?? null,
'postal' => $norm['postal'] ?? null,
'country' => $norm['country'] ?? null,
'lat' => $norm['lat'] ?? null,
'lon' => $norm['lon'] ?? null,
]);
}
/**
* thin alias for backwards compatibility with older call-sites.
* prefer using findOrCreateNormalized() directly.
*/
public static function firstOrCreateNormalized(array $norm, ?string $raw = null): self
{
return static::findOrCreateNormalized($norm, $raw);
}
/**
* create/find a label-only location (no geocode)
*/
public static function labelOnly(string $label): self
{
return static::firstOrCreate(
['display_name' => $label],
['raw_address' => null]
);
}
/**
* accessor: short label for ui (falls back gracefully)
*/
public function getShortLabelAttribute(): string
{
return $this->place_name
?? $this->display_name
?? trim(collect([$this->street, $this->city])->filter()->join(', '));
}
}