Series Contents

Part 4. Converting Route Closures to Controller Classes

Route Control

Right now we have all of our routing and controller logic in one procedural file that we are treating like a service definition. This is not good practice for anything more than a single page site and will become unruly fairly quickly.

Having the route definitions here makes sense but we need to break the logic and functionality out. We will be putting our logic into controller classes and then loading those classes as Services.

Lets set up our structure.

Create the directory src/App/Controller. This will hold our controller classes. In this directory create a file called DefaultController.php with a matching class inside.

Now lets create a file, configuration/services/controllers.php, to put our service definitions into. Add the following code for now.

Now lets take a look at our default route. You’ll notice that it requires some information in order to function. Namely the logger and the renderer. These are themselves services that are defined in services.php. Here is where Dependency Injection comes into play. Our service container already knows how to create these objects when needed, so lets let it do the work for us and just pass those objects into the controller’s constructor.

Note: the logger would normally be pushed down to the Service level of our application. This will happen later when we get that far, but for now we’ll just move it here as it is part of the current route closure.

In the DefaultController class, add properties to hold these two objects. Then assign them in the constructor as passed arguments.

And in the controllers.php modify our DefaultController definition to pass the service calls into the controller.

We now have a default controller that knows how to instantiate itself!

Lets add our functionality to the Default Controller’s index class. I should mention here that all controller methods have three parameters by default.

  • $request, which is a Request object. Slim uses PSR-7 so this implements the RequestInterface.
  • $response, which is the Response object and implements the ResponseInterface.
  • $args, an associative array of placeholders which represents the query parameters.

First include the interfaces in the file header.

Then add our default controller method, type hinting the parameters, and add the code from the route’s closure. Your index function should look like this.

Now that everything is set up lets fix out route definition to use this new setup.

Instead of containing a closure function as it’s callback, our route will take the name of the controller service created above. The Pimple container works as a Service Locator here to find the ‘DefaultController’ service and ‘index’ methods. It then passes it back to the Router. The request, response, and passed arguments array will be automatically injected into the index method by our container.


That’s it, the route will now call our controller classes’ index method and automatically pass it everything it needs to render our output. All of our routes can now be defined, and cleanly read, in the routes.php configuration file. While all of the control functionality will be kept in controller classes that correspond to the specific aspects of our application. Separating our concerns.


See the final code for this article on github. 004 Converting Routes to Controller Classes


Slim-OO Part 5. Install and Configure Twig.