feat: show immediate administrative subdivisions and map coverage gaps
This commit is contained in:
@@ -8,15 +8,20 @@ use Illuminate\Support\Facades\DB;
|
||||
final class TerritoryGeometry
|
||||
{
|
||||
/** @return array<string,mixed> */
|
||||
public function context(string $id, bool $management = false): array
|
||||
public function context(string $id, bool $management = false, bool $includeChildren = false): array
|
||||
{
|
||||
$geography = app(InvestmentGeography::class);
|
||||
abort_unless($geography->references($management)->where('id', $id)->exists(), 404);
|
||||
$selected = $geography->references($management)->where('id', $id)->first(['location_type']);
|
||||
abort_unless($selected !== null, 404);
|
||||
$path = $geography->path($id, $management);
|
||||
$ids = array_map(fn ($node) => $node->id, $path);
|
||||
$ids = array_values(array_unique([$id, ...array_map(fn ($node) => $node->id, $path)]));
|
||||
$childType = ['country' => 'province', 'province' => 'district', 'district' => 'admin_post', 'admin_post' => 'locality'][$selected->location_type] ?? null;
|
||||
$children = $geography->references($management)->where('parent_id', $id)->where('location_type', $childType ?? 'none');
|
||||
$childCount = $includeChildren && $childType ? (clone $children)->count() : 0;
|
||||
$childIds = $includeChildren && $childType ? $children->orderBy('name')->orderBy('id')->limit(500)->pluck('id')->all() : [];
|
||||
$approved = app(ApprovedAdministrativeBoundaries::class);
|
||||
$rows = DB::table('geo_geometries as g')->join('geo_locations as l', 'l.id', '=', 'g.geo_location_id')
|
||||
->whereIn('g.geo_location_id', $ids)->whereNull('g.deleted_at')->whereNull('l.deleted_at')
|
||||
->whereIn('g.geo_location_id', [...$ids, ...$childIds])->whereNull('g.deleted_at')->whereNull('l.deleted_at')
|
||||
->where(function ($query) use ($management, $approved) {
|
||||
$query->where('g.data_classification', 'public');
|
||||
$query->orWhere(function ($internal) use ($management, $approved) {
|
||||
@@ -29,20 +34,22 @@ final class TerritoryGeometry
|
||||
->whereRaw("g.properties->>'purpose' = 'administrative_boundary'")
|
||||
->whereIn('g.geometry_type', ['polygon', 'multipolygon'])
|
||||
->whereRaw('ST_IsValid(g.geom) AND NOT ST_IsEmpty(g.geom) AND ST_SRID(g.geom)=4326')
|
||||
->orderByRaw('CASE WHEN g.geo_location_id = ? THEN 0 WHEN g.geo_location_id IN ('.implode(',', array_fill(0, count($ids), '?')).') THEN 1 ELSE 2 END', [$id, ...$ids])
|
||||
->orderBy('g.geo_location_id')->orderBy('g.id')->limit(101)
|
||||
->get(['g.id', 'g.geo_location_id', 'l.name', 'l.location_type', 'g.properties', 'g.data_classification',
|
||||
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry'),
|
||||
DB::raw("encode(sha256(ST_AsEWKB(g.geom)),'hex') as geometry_sha256"),
|
||||
DB::raw("encode(sha256(convert_to(g.properties::text,'UTF8')),'hex') as properties_sha256")]);
|
||||
$queryTruncated = $rows->count() > 100;
|
||||
if (! $management) {
|
||||
$rows = $rows->filter(fn ($row) => $row->data_classification === 'public'
|
||||
|| $approved->allows($row->id, $row->geo_location_id, $row->geometry_sha256, $row->properties_sha256))->values();
|
||||
}
|
||||
$areas = $rows->take(100)->map(function ($row) use ($id, $management) {
|
||||
$areas = $rows->take(100)->map(function ($row) use ($id, $management, $childIds) {
|
||||
$source = json_decode($row->properties, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
return ['id' => $row->id, 'territory_id' => $row->geo_location_id, 'location_type' => $row->location_type,
|
||||
'selected_territory' => $row->geo_location_id === $id, 'geometry' => json_decode($row->geometry, true, 512, JSON_THROW_ON_ERROR),
|
||||
'selected_territory' => $row->geo_location_id === $id, 'child_territory' => in_array($row->geo_location_id, $childIds, true), 'geometry' => json_decode($row->geometry, true, 512, JSON_THROW_ON_ERROR),
|
||||
'title' => 'Limite administrativo: '.$row->name, 'purpose' => 'administrative_boundary',
|
||||
'source_reference' => $source['authority'] ?? null, 'source_date' => $source['source_version'] ?? null,
|
||||
'source_url' => $source['source_url'] ?? null, 'source_sha256' => $source['source_sha256'] ?? null,
|
||||
@@ -51,6 +58,9 @@ final class TerritoryGeometry
|
||||
|
||||
return ['territory_id' => $id, 'territory_registered' => true,
|
||||
'selected_geometry_available' => $rows->contains('geo_location_id', $id), 'context_geometry_count' => count($areas),
|
||||
'areas' => $areas, 'truncated' => $rows->count() > 100, 'investment_site' => false];
|
||||
'areas' => $areas, 'truncated' => $queryTruncated || $childCount > 500, 'investment_site' => false,
|
||||
'child_coverage' => $includeChildren ? ['location_type' => $childType, 'registered_count' => $childCount,
|
||||
'represented_count' => count(array_unique(array_column(array_filter($areas, fn ($area) => $area['child_territory']), 'territory_id'))),
|
||||
'reference_limit' => 500, 'geometry_limit' => 100] : null];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user