Laravel to całkiem fajny framework PHP i zapewnia wiele przydatnych funkcji. Jedną z nich jest klasa Resource. Bardzo często pobieramy dane z np. bazy danych i wysyłamy je do naszego klienta aplikacji. Wysłanie całego modelu jest bardzo złą opcją i jest ku temu wiele powodów:

  • Prawdopodobnie nie chcemy ujawniać struktury naszych modeli
  • Niektóre dane mogą być poufne – być może nasz klient nie będzie korzystał z tych pól, ale każdy użytkownik będzie mógł zajrzeć do żądania, odpowiedzi i uzyskać te dane
  • Wielu klientów (np. urządzenia mobilne) nie potrzebuje wszystkich danych

Bez klasy Resource musimy stworzyć własną klasę i dokonać pewnych przekształceń, przygotować dane z bazy danych dla klientów. Jeśli zdecydujemy się na skorzystanie z wbudowanego Zasobu, będzie to znacznie, znacznie prostsze. Wystarczy, że zwrócimy takie instancje klas i przekażemy nasze dane do konstruktora, a następnie napiszemy, jakich pól naprawdę chcemy użyć. Istnieje prosty przykład zasobu Laravel, który przygotuje nasze dane do wysłania jako JSON:

declare(strict_types=1);
namespace App\Modules\MyModule\Resources;
use Illuminate\Http\Resources\Json\Resource;
class MyModelResource extends Resource
{
   /**
    * @var MyModel
    */
   public $resource;
   public function toArray($request)
   {
      return [
       “id” => $this->resource->getKey(),
       “name” => $this->resource->my_model_name,
       “count” => $this->resource->my_model_attribute,
       (...)
      ];
   }
}

Ten komentarz z $var MyModel jest opcjonalny, ale pomaga niektórym IDE rozpoznać, jakiego modelu użyjemy w naszym zasobie. I jest zastosowanie w naszym kontrolerze:

public function getModel(Request $request): JsonResponse
{
   // here some code for get model (or inject it with route)
   $model = MyModel::find($request->id);   
   return response()->json(
       new MyModelResource($model)
   );
}

Prosty, czysty i elegancki, ponieważ przekształcamy nasz model w osobnym miejscu. Jeśli jest to wymagane, możemy zmodyfikować nasze dane w bardziej złożony sposób, nie ma z tym problemu. Możemy również użyć... Zasób wewnątrz zasobu, więc można zrobić coś takiego:

public function toArray($request)
{
    return [
        "id" => $this->resource->getKey(),
        "name" => $this->resource->my_model_name,
        "relation" => new MyModelRelationResource($this->resource->relation),
        (...)
  ];
}

Zasoby

kolekcji Co zrobić, jeśli mamy dużo elementów i chcemy je wysłać w formacie JSON? Nie stanowi to również problemu, ponieważ możemy użyć wbudowanej klasy ResourceCollection, aby to osiągnąć. Jest jeszcze jeden przykład:

declare(strict_types=1);
namespace App\Modules\MyModule\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;
class MyModuleCollectionResource extends ResourceCollection
{
   public function toArray($request)
   {
       return MyModuleResource::collection($this->collection);
   }
}

Oczywiście możemy modyfikować lub przekształcać kolekcję w taki sam sposób, jak w normalnym Resource, tylko tablicę odpowiedzi. Zastosowanie w kontrolerze:

public function getModels(Request $request): JsonResponse
{
   $models = MyModel::all();   
   return response()->json(
       new MyModuleCollectionResource($models)
   );
}

Jak widać, jest bardzo łatwy w użyciu, pozwala nam wszystko lepiej zorganizować i rozwiązać wiele problemów.