Files
Investidor-V2/app/Services/InvestmentMapIndicators.php
T
2026-11-04 11:45:42 +02:00

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;
}
}