It seems like you are using an ad blocker. To enhance your experience and support our website, please consider:

  1. Signing in to disable ads on our site.
  2. Sign up if you don't have an account yet.
  3. Or, disable your ad blocker by doing this:
    • Click on the ad blocker icon in your browser's toolbar.
    • Select "Pause on this site" or a similar option for lancecourse.com.

Workouts with Slim 3 - part 5- Action controllers

By zooboole

Hi, welcome to the fifth part of this series on Slim 3. You can have a look at the previous parts.

In part 3 we saw how to make simple routing by using anonymous functions to handle the route callbacks. In this part we will see how it's possible to use Slim's Callable Resolver Class(CRC) to handle our routing.

Now let's have a look at what exactly we're trying to achieve here. For that let's take a simple route as following:

$app->get('/users', function($request, $response, $args){

    // make some database queries

    // Make some conditions and validate data

    // Maybe, parse data again

    // Prepare data for template

    //...

    // render template

});

This is just one route. Imagine you have about ten, or why not, hundreds of them each one containing a lot of treatment like the route up there. It's definitely going to be hard to handle.

To solve this problem we can use what is called an invokable class and that's done like following:

$app->get('/some/path', 'ClassName:method');

This looks cleaner and more powerful. Because we can now align many routes without using much space.

Besides, by calling an invokable class, we have more control over what the callback can do and how it does it. In a class we can have as much as possible methods to handle our actions.

Let's look at a more featured example of how we can do that.

Routes.php

<?php

$app = new SlimApp();

// Route to get the list of users
$app->get('/users', 'UserController:users');

// Route to add new user
$app->post('/users','UserController:create');

// Route to delete a user with id {id}
$app->delete('/users/{id}', 'UserController:delete');

UserController.php

<?php
namespace Controllers;

use PsrHttpMessageServerRequestInterface as Request;
use PsrHttpMessageResponseInterface as Response;

class UserController{

    public function __construct($container)
    {
        // make the container available in the class
        $this->container = $container;
    }

    public function users(Request $request, Response $response, $args)
    {
        $users = Users::all();
        $this->container->view->render($response, 'list-users.twig', $users);
    }

    public function create(Request $request, Response $response, $args)
    {
        // proceed to creating a new user
    }

    public function delete(Request $request, Response $response, $args)
    {
        // proceed to deleting a new user
    }

    //...

}

You can see how simple and clear this looks. With a single User class we can handle must actions applied to users.

But, after doing that you to tell Slim were to find the particular invokable class by injecting it into the container:

dependencies.php

<?php

$container = $app->getContainer();

// Add our invokable class to the container
// Choose a name for it in the container

$container['UserController'] = function() {

// note the use of the namespace
// $container is injected to pass it to the class
// constructor
return new ControllersUserController($container);

}

// View dependency
//....

With this, we can access instances of the class every where by using $this->container->UserController. You can now extend or use the class in other classes.

Instead of using one class with many methods in it to handle our actions, Slim also offers the possibility to dedicate en entire class for an action. In that case the route will look like this:

$app->get('/some/path', 'Controller');

Note here we didn't precise a method to call. To make our class useful, we put in place an __invoke method. This method is a magic method which executes every time the class is called like a method. Here is how Slim treats it:

<?php

//.....

// check if string is something in the DIC 
// that's callable or is a class name which
// has an __invoke() method
$class = $toResolve;
if ($this->container->has($class)) {
    $resolved = $this->container->get($class);
} else {
    if (!class_exists($class)) {
        throw new RuntimeException(sprintf('Callable %s does not exist', $class));
    }
    $resolved = new $class($this->container);
}

Source from SlimCallableResolver

-First the class as to be passed to the container otherwise an exception is thrown.

-Once the class is injected in the container, Slim gets its name and creates a new instance of it.

Conclusion

That was it. A powerful tool with simple means. This can be pushed far with complex classes and namespaces. Meet me in the next and last part of these series where I will be talking of databases. How can we use Slim with PDO, or with Laravel's Eloquent ORM.

Stay tuned by subscribing to our newsletters or signing up. Share your thoughts too by commenting. Thanks for reading.

Last updated 2024-01-11 UTC