framework
framework copied to clipboard
[9.x] Get JsonResource from the container
It's not always possible to resolve the JsonResource from the container. This is because the JsonResource expects a argument in the constructor. This argument can be anything (mixed).
I often do this because both my FormRequest and JsonResource vary by version. An example where $resource
could be ProductResourceV1
or ProductResourcev2
:
public function index(ProductIndexRequest $request, ProductResource $resource): ResourceCollection
{
$products = Product::query()
->deleted($request->isDeleted())
->orderBy($request->sort(), $request->direction())
->search($request->search())
->with($resource->withRelationships($request->includes()));
return $resource::collection($products->paginate($request->limit()));
}
Illuminate\Contracts\Container\BindingResolutionException : Unresolvable dependency resolving [Parameter #0 [ <required> $resource ]] in class App\Http\Resources\ProductResource
Workarounds:
Option 1. Make parameter optional:
abstract class ProductResource extends JsonResource
{
/**
* @param Product[]|Product $resource Optional to allow dependency injection.
*/
public function __construct($resource = null)
{
parent::__construct($resource);
}
Option 2. Make sure the binding adds a null value:
app()->bind(ProductResource::class, function(Container $container){
return new ProductV2Resource(null);
});
Resolving the resource is very common in a package I use: https://github.com/reindert-vetter/api-version-control . I normally use option 1, but because more and more users are also using this package, it would be great if this hack is no longer needed.
I don't feel this is a good idea for core. The JsonResource is a value object.
If you need varying implementations, you should just create varying implementations you should create and inject a Factory and have the logic to determine which resource to create abstracted behind the factory.
public function index(ProductIndexRequest $request, ProductResourceFactory $factory)
{
$products = Product::query()
// ...
->with($resource->withRelationships($request->includes()));
return $factory->collection($products->paginate($request->limit()));
}
It's never meant for JsonResource to be resolved from core. Please see the docs: https://laravel.com/docs/9.x/eloquent-resources. Also see Tim's suggesting above.