I'm trying to apply Clean Architecture from uncle Bob in Laravel application.
What i'm concerning is: As uncle Bob describe, the Controller should belongs to third circle: Interface Adapters (from inside-out). It means the Controller only depends on Use Case Circle (2nd), and should not know anything about the framework in 4th circle.
But controller in some frameworks has to extends a base class (for example, an AbstractController class), It also needs to receive an Request object and sometimes return a Response object, so this kinda break the dependency rule of Clean Architecture, as it knows about the framework in the outer circle.
Do i misunderstand? If not is there any solution to not break the dependency rule?
My controller is looking like this:
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use User\UseCase\FetchUsers;
use User\UseCase\FetchUsersRequest;
class UserController extends Controller
{
public function index(Request $request, FetchUsers $fetchUsersUseCase)
{
$useCaseRequest = new FetchUsersRequest(
// extract data from Request
);
$useCaseResponse = $fetchUsersUseCase->handle($useCaseRequest);
return [
'users' => $useCaseResponse->users,
];
}
}
Correct.
Correct.
I did not get a problem with that. Just use the "AbstractController class" in the Interface Adapters layer, as well as other controllers.
This is an interesting statement. To clear things up let's refer to the primary source, the book "Clean Architecture: A Craftsman's Guide to Software Structure and Design":
I think I collected all the most important information from the book, related to the "controller" topic. Now let's use this guidance to analyze your question.
As you can see in the clean architecture controller does not have to "receive a Request object" or "return a Response object". It can define its own request model that represents the user input in a simple and framework-agnostic way. The controller can then convert the Request object from the framework into its own request model and pass it to the use case interactor, which belongs to the use cases circle. The use case interactor can then perform the business logic and return a response model, which is another simple and framework-agnostic data structure. The controller can then convert the response model into a Response object that is compatible with the framework and return it to the user. This way, the controller acts as an adapter between the framework and the use case interactor, translating the data and requests between them without creating any dependency on the framework.
So what I think you missed is that in the interface adapters layer, there are gateways interfaces, which are used to communicate with the outer layer, to avoid coupling between layers.
In short, by using simple data objects, abstract interfaces and their implementations in outer layers you can achieve a clean architecture without breaking dependency rules.