$row */ public function map(array $row): AssetData { $id = $this->integer($row['id'] ?? null); $assetTag = $this->text($row['asset_tag'] ?? null); if ($id === null || $id < 1 || $assetTag === null) { throw new SnipeItMappingException('A resposta do Snipe-IT contém um ativo sem ID ou etiqueta válida.'); } $modelName = $this->text(Arr::get($row, 'model.name')); return new AssetData( snipeAssetId: $id, assetTag: $assetTag, name: $this->text($row['name'] ?? null) ?? $modelName ?? $assetTag, serial: $this->text($row['serial'] ?? null), modelId: $this->integer(Arr::get($row, 'model.id')), modelName: $modelName, categoryId: $this->integer(Arr::get($row, 'category.id')), categoryName: $this->text(Arr::get($row, 'category.name')), manufacturer: $this->text(Arr::get($row, 'manufacturer.name')), statusId: $this->integer(Arr::get($row, 'status_label.id')), statusName: $this->text(Arr::get($row, 'status_label.name')), locationId: $this->integer(Arr::get($row, 'rtd_location.id') ?? Arr::get($row, 'location.id')), locationName: $this->text(Arr::get($row, 'rtd_location.name') ?? Arr::get($row, 'location.name')), requestable: $this->boolean($row['requestable'] ?? false), assignedType: $this->text(Arr::get($row, 'assigned_to.type')), assignedId: $this->integer(Arr::get($row, 'assigned_to.id')), imageUrl: $this->text($row['image'] ?? $row['image_url'] ?? null), sourceUpdatedAt: $this->date(Arr::get($row, 'updated_at.datetime') ?? Arr::get($row, 'updated_at.date') ?? $row['updated_at'] ?? null), ); } private function text(mixed $value): ?string { if (! is_scalar($value)) { return null; } $decoded = trim(html_entity_decode((string) $value, ENT_QUOTES | ENT_HTML5, 'UTF-8')); return $decoded === '' ? null : $decoded; } private function integer(mixed $value): ?int { return is_numeric($value) ? (int) $value : null; } private function boolean(mixed $value): bool { if (is_bool($value)) { return $value; } return in_array(strtolower((string) $value), ['1', 'true', 'yes', 'sim'], true); } private function date(mixed $value): ?CarbonImmutable { $text = $this->text($value); if ($text === null) { return null; } try { return CarbonImmutable::parse($text); } catch (Throwable) { return null; } } }