From phpBB Development Wiki
This page aims to clearly explain the process of creating and using a front controller for extensions as well as for core phpBB functionality.
What is a Controller?
In the MVC (Model, View, Controller) framework, the controller is routing system that, well, controls where the user is on the site, based on the URL. All requests to the website are routed through a single script, the controller, and the appropriate information is displayed based on what the user has requested.
Creating a Controller
A controller consists of 3 components at a minimum:
- The service file - ./config/services.yml - This file contains a list of services; a service is basically the definition of a class and its dependencies (For more information read Dependency Injection Container and its linked pages).
- The routing file - ./config/routing.yml - This file contains a list of controller access names (i.e. what the user puts in the URL) associated with the service
- The controller class - (filename and location can vary) - This is a class that implements the phpbb_controller_interface and is responsible for serving the user content based on what they requested in the URL.
The Service File
Following the implementation of a Dependency Injection Container, core phpBB objects are now available as services. This allows you to easily access their instances using the container without having to mess with global variables or having to remember what arguments are needed and in what order they are needed.
To make it easier and safer for controllers to specify its dependencies, we require that they be defined as services. For core controllers, this should be done in the ./phpBB/config/services.yml file. The syntax is fairly straightforward:
#Comments use hash tags #Do NOT use tabs for indentation. Instead, 4 spaces = 1 tab service_name: class: phpbb_my_class arguments: - @request - literal_text - %core.php_ext%
The @request specifies that the first parameter of phpbb_my_class requires an instance of the phpbb_request class (or a subclass). The order of arguments here should match the order of parameters on your __construct() method definition.
The Routing File
This file is responsible for associating a controller's access name (i.e. what is typed in the URL) with its service (located in services.yml). When someone types the access_name in the URL, the service is located and the associated class is instantiated using the required dependencies.
#This is also YML, so the comments above apply here my_controller: service: service_name #This will reference the service we created above
This will eventually cause the class phpbb_my_class to be instantiated when the URL contains "controller=my_controller" in the query string.
The Controller Class
The controller class is instantiated when the controller is requested from the URL. The controller class name should follow the class naming guidelines. For an extension, the class should be called something like phpbb_ext_myext_controller_main if your controller is located at ./ext/myext/controller/main.php. Every controller class "must" implement the phpbb_controller_interface interface.
Controller files must be located in the ./controller/ directory (for extensions, this is the ./ext/my_ext/controller/ directory) . While this is not due to any coded restrictions, it makes it so that the extension package is organized and uniform.
Every controller should contain two methods. The first is the __construct() method. This is optional if you have no dependencies defined for your service; otherwise, this method must contain the same arguments as are listed for your service, in the same order. To go along with the above example, an appropriate __construct() method might look like:
public function __construct(phpbb_request $request, $my_variable = 'literal_text', $phpEx = '.php')
$this->request = $request;
$this->my_variable = $my_variable;
$this->php_ext = $phpEx;
The second method, which is absolutely required (because it is in the implemented interface), is handle(). This method takes no arguments and must return an instance of the Symfony Response object. To use the Response object, you should have the following code at the top of your class file just above the class definition: use Symfony\Component\HttpFoundation\Response; By using the above statement, you can simply refer to the Response object as Reponse without having to resolve the namespace on every usage.
The Reponse object takes two arguments:
- Response message - Should be an empty string on success; otherwise, its error message will be sent to trigger_error() automatically. Do not make direct calls to trigger_error from within your controller.
- Status code - This defaults to 200, which is the status code \"OK\". If you are sending a response about being unable to find some information, you would use the 404 (\"Not Found\") status. 403 would be used if the user lacks the appropriate permissions.