68 lines
3.4 KiB
PHP
68 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\InvestmentZone;
|
|
use App\Support\StructuredData;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/** Public park observations remain individual source records, never regional estimates. */
|
|
final class InvestmentMapIndicators
|
|
{
|
|
public const INDICATORS = ['employment', 'investment', 'production', 'exports', 'local_procurement'];
|
|
|
|
/** @param Collection<int, InvestmentZone> $zones
|
|
* @return array<string,mixed> */
|
|
public function forZones(Collection $zones, bool $zoneLimitReached = false): array
|
|
{
|
|
$zoneLimitReached = $zoneLimitReached || $zones->count() > 30;
|
|
$zones = $zones->take(30)->values();
|
|
$details = app(InvestmentZoneOperationalDetails::class);
|
|
$result = ['state' => $details->installed() ? 'available' : 'unavailable', 'records' => [],
|
|
'zones_consulted' => $zones->count(), 'zone_limit' => 30, 'record_limit' => 200, 'truncated' => $zoneLimitReached];
|
|
if ($result['state'] === 'unavailable') {
|
|
return $result;
|
|
}
|
|
foreach ($zones as $zone) {
|
|
// This is the already selected public envelope; never decrypt the private preparation.
|
|
$public = $details->publicData($zone);
|
|
$observations = StructuredData::collectionItems($public['integral']['observations'] ?? []);
|
|
$values = [];
|
|
if ($observations !== []) {
|
|
// Extract decimal text from this exact loaded snapshot, not a newer database version or a PHP float.
|
|
foreach (DB::select("SELECT item->>'id' AS id, item->>'value' AS value FROM jsonb_array_elements((?::jsonb)->'public'->'integral'->'observations') AS item", [$zone->getRawOriginal('operational_details')]) as $number) {
|
|
$values[$number->id] = $number->value;
|
|
}
|
|
}
|
|
foreach ($observations as $row) {
|
|
if (! in_array($row['indicator'] ?? null, self::INDICATORS, true)) {
|
|
continue;
|
|
}
|
|
if (count($result['records']) === 200) {
|
|
$result['truncated'] = true;
|
|
|
|
return $result;
|
|
}
|
|
$knowledge = $row['knowledge'] ?? 'unknown';
|
|
$rawValue = $values[$row['id'] ?? ''] ?? null;
|
|
$value = $knowledge !== 'unknown' && is_numeric($rawValue) ? $rawValue : null;
|
|
$missing = [];
|
|
foreach (['unit', 'period_start', 'period_end', 'scope', 'population', 'methodology', 'source_reference', 'source_date'] as $field) {
|
|
if (trim((string) ($row[$field] ?? '')) === '') {
|
|
$missing[] = $field;
|
|
}
|
|
}
|
|
$result['records'][] = [
|
|
...array_intersect_key($row, array_flip(['id', 'label', 'description', 'indicator', 'unit', 'period_start', 'period_end', 'scope', 'population', 'methodology', 'source_reference', 'source_date', 'phase_id', 'plot_id'])),
|
|
'zone_id' => $zone->id, 'zone_name' => $zone->name, 'zone_version' => (int) $zone->version_no, 'url' => '/zonas/'.$zone->id,
|
|
'theme' => $row['indicator'] === 'employment' ? 'workforce' : 'economic_potential',
|
|
'value' => $value, 'knowledge' => $knowledge, 'missing_metadata' => $missing,
|
|
];
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|