Files
home_automatization/laravel-app/app/Http/Resources/DeviceResource.php
cacto be1f238f89 Перевод защищённой части приложения на Vue.js + Inertia
Дашборд, зоны, устройства, правила автоматизации и профиль теперь
Vue 3 + Inertia вместо Blade+Alpine — гостевые страницы Breeze
(логин/регистрация) сознательно оставлены на Blade, чтобы не трогать
уже протестированную аутентификацию. Контроллеры возвращают
Inertia::render() вместо view(), переиспользуют существующие
API Resources и FormRequest.

Ключевой нюанс: Resource/ResourceCollection, переданные напрямую в
проп Inertia, заворачиваются в ключ "data" (Inertia вызывает
toResponse() у Responsable-объектов) — везде используется ->resolve()
и явное резолвление вложенных ресурсов (zone/device_type внутри
Device и т.п.), иначе вложенные поля тоже задваивались бы обёрткой.

Alpine.js и все Blade-вьюхи защищённой части удалены как мёртвый код.
Тесты (ZoneControllerTest/DeviceControllerTest) переведены на
assertInertia(). UserFactory теперь явно задаёт role=owner — без
этого Eloquent не подтягивает DB-default обратно в модель после
create(), что уронило бы общий auth.user проп на любой странице.
2026-08-12 10:52:04 +05:00

39 lines
1.5 KiB
PHP

<?php
namespace App\Http\Resources;
use App\Models\Device;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* @mixin Device
*
* `devices.status` in Postgres is only a stale snapshot (see migration
* comment) — Redis (Device Shadow) is authoritative. The controller stamps
* the live value onto the model as `live_status` before wrapping it here;
* `status` in the JSON always prefers that when present.
*/
class DeviceResource extends JsonResource
{
/** @return array<string, mixed> */
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'external_id' => $this->external_id,
'protocol' => $this->protocol,
'status' => $this->live_status ?? $this->status,
// Nested resources are resolved (not returned as bare Resource
// instances) — a Resource embedded as a value gets wrapped in its
// own `data` key when the parent response goes through Laravel's
// Responsable pipeline (Inertia props, ->response() in the API),
// which would double up with the outer collection's own wrapping.
'zone' => $this->whenLoaded('zone', fn ($zone) => (new ZoneResource($zone))->resolve()),
'device_type' => $this->whenLoaded('deviceType', fn ($type) => (new DeviceTypeResource($type))->resolve()),
'created_at' => $this->created_at,
];
}
}