The article about the MVC pattern on Wikipedia states that the language Smalltalk-80 supported MVC in this form:
[...] a View represents some way of displaying information to the user, and a Controller represents some way for the user to interact with a View. A View is also coupled to a model object, [...].
Further, the article on Wikipedia states the following:
Controller:
Accepts input and converts it to commands for the model or view.
A Smalltalk-80 controller handles user input events, such as button presses or mouse movement. [...] If user input prompts a change in a model, the controller will signal the model to change, but the model is then responsible for telling its views to update.
Interactions:
The controller responds to the user input and performs interactions on the data model objects. The controller receives the input, optionally validates it and then passes the input to the model.
In regard of MVC, I decided to choose an approach similar to the one found in Smalltalk-80 and apply it to my MVC-based web applications:
- A controller receives data from the user input and updates (like "CUD" from "CRUD") the domain model with it, without expecting any response. For this, it uses a "use case" (e.g. a service), to which it passes the data from the user input. In turn, the "use case" communicates further with the domain model, updating it with that data.
- A view queries (like "R" from "CRUD") the domain model for the data requested by the user, in order to present it back to him. For this, it uses the same "use case" (e.g. service) as the controller, to which it passes the user input data. In turn, the "use case" reads further the domain model and passes the results back to the view.
In general, a controller can receive two types of values from the user input:
a. values used to update the domain model with. Like the data sent by a user upon submitting a POST form.
b. values used only as criteria to search for something in the domain model. Like the values passed by a user in the query string of a request URI.
In the first case (a) it is very clear that a controller MUST be defined:
<?php
use SampleMvc\App\{
Controller\Book\AddBook as AddBookController,
View\Book\AddBook as AddBookView,
};
// Define a route.
$routeCollection->post('/books/add', [
'controller' => [AddBookController::class, 'addBook'],
'view' => [AddBookView::class, 'output'],
]);
// Controller needed for updating the domain model (using a service, e.g. a "use case") with the data of the user input.
$controller = new AddBookController($addBookService);
// View needed for querying the domain model (using a service, e.g. a "use case") and returning a response.
$view = new AddBookView($addBookService, $responseFactory, $templateRenderer);
// Add a book. The user input data is used to update the domain model for.
$controller->addBook($bookName, $bookTitle);
// Diplay a message or a list of books.
$response = $view()->output();
// Present the response to the user.
$responseEmitter->emit($response);
In comparison though, in my opinion, in the second case (b) there is no need to define a controller at all. The values could be directly passed to the view, without the need of a controller. The view will use a specific "use case" (e.g. service) to query the domain model with these values and to receive a resultset. Finally, the view builds and sends a corresponding response back to the user.
<?php
use SampleMvc\App\View\Book\FindBooks as FindBooksView;
// Define a route.
$routeCollection->get('/books/find/{authorName}', [
'controller' => null,
'view' => [FindBooksView::class, 'findBooksByAuthorName'],
]
/* No controller needed: there's no data to update the domain model with !!! */
// View needed for querying the domain model (using a service, e.g. a "use case") and returning a response.
$view = new FindBooksView($findBooksService, $responseFactory, $templateRenderer);
// Finds books by author name. The user input data is used as criteria to search the domain model for.
$response = $view()->findBooksByAuthorName($authorName);
// Present the response to the user.
$responseEmitter->emit($response);
Taking the above into consideration, I have two questions:
- Is it mandatory to define a controller, even when the user input consists only of values used as criteria to search for something in the domain model - as in option (b)?
- If yes, then why?
Resources:
This is not really a yes-or-no answer because the "original" MVC pattern was "Traditionally used for desktop graphical user interfaces" as the wikipedia article states, while you are using PHP that is originating from dynamically created web pages (aka web applications) which have a browser involved.
For plain full-roundtrip-applications that send many of the user interactions as requests to the server and always receive a complete webpage, the browser has its own (domain object) model, can execute JavaScript, do interactive rendering changes with CSS, handle multimedia content etc.
So you should not stick to this classical MVC approach for this "classical" web applications, they were not made to fit together. But the MVC pattern evolved to suite also web applications, the Wikipedia article mentions some of the newer patterns.
On the other hand if we are talking about a single page application, that runs mainly inside the browser and only retrieves data from a backend, you can approach that original MVC pattern in a much better way - probably it's the model that is then kind of "split" between your browsers memory and the server.
So for the "classical" web applications I would answer your question "Must a controller always be defined?" definitely with "no", because you probably don't use the (classical) MVC pattern.
Or the other way around: if you don't define a controller, it's not the MVC pattern. Doesn't mean you can't create working applications without a controller. Its functions will be existing, probably just not separated that clearly.
For your situation, where you don't want to use a controller for e.g. searches - which part of the code handles the incoming search parameter? Which part triggers a search at all? Which part is responsible for navigation in your application? Usually all those parts are done by the controller.