In Laravel 11, I'm trying to make a single interface for all of the CRUD resource controllers in my API. Something like this (showing for store() method only):
<?php
namespace App\Interfaces;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Foundation\Http\FormRequest;
interface ResourceInterface
{
/**
* Store a newly created resource in storage.
*
* @param T $request
* @return JsonResponse
*/
public function store($request): JsonResponse;
And then in the UserController@store:
<?php
namespace App\Http\Controllers\Api\V1;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Interfaces\ResourceInterface;
use App\Http\Requests\StoreUserRequest;
use App\Http\Controllers\Api\ApiController;
class UserController extends ApiController implements ResourceInterface
{
public function __construct(private AuthController $authController)
{
}
public function store(StoreUserRequest $request): JsonResponse
{
$user = $this->authController->register($request);
return $this->createdResponse($user, "User {$request->name} registered successfully");
}
As you can see, the UserController@store method uses a custom request class, which will be the case for all of my other resource controller methods. However, I have not been able to make the generic interface work.
I have tried using the FormRequest class in the controller method, as such:
public function store(FormRequest $request): JsonResponse
{
if (!$request instanceof StoreUserRequest) {
return $this->errorResponse("Invalid request type");
}
$request->validate();
$user = $this->authController->register($request);
return $this->createdResponse($user, "User $request->name registered succesfully");
}
Together with replacing the generic interface with one that uses FromRequest, since my StoreUserRequest class extends FormRequest, but this did not work as the custom validation was not being applied.
And using PHPDoc comments as such:
public function store(FormRequest $request): JsonResponse
{
/** @var StoreUserRequest $request */
$user = $this->authController->register($request);
return $this->createdResponse($user, "User $request->name registered succesfully");
}
But none of these seem to work. What am I dowing wrong?,
-
"However, I have not been able to make the generic interface work." what does this mean? PHP has never had support for generics, and nothing you put in doc blocks is going to stop your code from working.miken32– miken322024年09月26日 17:18:09 +00:00Commented Sep 26, 2024 at 17:18
-
"I have tried using the FormRequest class in the controller method" that won't work, the controller method needs to be type hinted with the class you want injected.miken32– miken322024年09月26日 17:20:44 +00:00Commented Sep 26, 2024 at 17:20
-
This means that what I am trying to do is not working. I know that PHP does not natively support generics, but I imagine that there must be a way to make a single interface reusable around multiple classes that implement its methods but with different parameter types. This might be with some method that I am not aware of, might be using union types which seems ugly, etc.Simon_Paul_99– Simon_Paul_992024年09月26日 17:29:24 +00:00Commented Sep 26, 2024 at 17:29
-
Not without violating contravariance; you can't make method parameters more restrictive than ones declared in the interface. php.net/manual/en/language.oop5.variance.phpmiken32– miken322024年09月26日 17:41:59 +00:00Commented Sep 26, 2024 at 17:41
-
See this answer for a good explanation.miken32– miken322024年09月26日 17:43:04 +00:00Commented Sep 26, 2024 at 17:43
2 Answers 2
Let try Laravel' service container: https://laravel.com/docs/11.x/container#contextual-binding
Your case:
$this->app->when(UserController::class)
->needs(FormRequest::class)
->give(YourExtendClassOfFormRequest);
Add this code in boot function of AppServiceProvider
Comments
Seems like this is not possible or at least evil since it violates contravariance, and the way forward is to rethink the structure around my controller methods and my usage of interfaces.
1 Comment
Explore related questions
See similar questions with these tags.