PHP Slim Framework Create Controller

18,438

Solution 1

Turn the controller into a functor:

class HomeController
{
    public function __invoke($req, $resp) {}
}

and then route like this:

$app->get('/', HomeController::class);

For reference, see

Solution 2

PHP 5.6 Slim 2.6.2

require 'vendor/autoload.php';

class HelloController {
    public static function index()  {
        global $app;

        echo "<pre>";
        var_dump($app->request);
        echo "</pre>";
    }
}

$app = new \Slim\Slim();
$app->get('/', 'HelloController::index');
$app->run();

Update: PHP 5.6 Slim 3.0.0

require 'vendor/autoload.php';

class HelloController {
    public static function hello(\Slim\Http\Request $req, \Slim\Http\Response $response, $args)  {
        echo "<pre>";
        var_dump($args);
        echo "</pre>";
    }
}

$app = new \Slim\App();
$app->get('/hello/{name}', 'HelloController::hello');
$app->run();

The problem with class based routing in Slim 3.0 is access to $this/$app. I think you will need to use global $app to access it.

In my pet project I use route groups with require_once. Something like

$app->group('/dashboard', function () {
    $this->group('/auctions', function () use ($app){
        require_once('routes/dashboard/auctions.php');
    });
    $this->group('/rss', function () {
        require_once('routes/dashboard/rss.php');
    });
    $this->group('/settings', function () {
        require_once('routes/dashboard/settings.php');
    });
});

Looks not as beauty as could be with pure classes but works like expected with all features accessible without additional coding.

Solution 3

Here's an example:

Controller

<?php

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;

/**
 * @property LoggerInterface $logger;
 */
class Controller
{
    /**
     * @var LoggerInterface
     */
    protected $logger

    /**
     * @param LoggerInterface $logger
     */
    public function __construct($logger)
    {
        $this->logger = $logger;
    }

    public function action(ServerRequestInterface $request, ResponseInterface $response, $args=[])
    {
        $this->logger->info((string)$request->getUri());
        /* some actions */
        return $response;
    }
}

Application

<?php

use Slim\App;
use Slim\Container;
use Psr\Container\ContainerInterface;

$autoloader = require(__DIR__.'/vendor/autoload.php');

$container = new Container();

$container['logger'] = function($container) {
    return new Logger();
}

$container['some.controller'] = function ($container) {
    /**
     * @var ContainerInterface $container
     */
    $logger = $container->get('logger');

    return new Controller($logger);
};

$app = new App($container);
$app->get('/some/route', 'some.controller:action');

$app->run();

Profit!

This method is described in the documentation click me

Solution 4

Smooth & short way to use a controller as an object (not a static way)

in index.php

namespace MyApp;

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require __DIR__ . '/../vendor/autoload.php';

$app->get('/myroute', [new Controller\MyClass, 'get']); // <=== that is pretty short  and neat
$app->post('/myroute', [new Controller\MyClass, 'post']);
$app->map(['GET', 'POST'], '/myotherrout', [new Controller\MyOtherClass, 'run']);

in Controller/MyClass :

namespace MyApp\Controller;

class MyClass{

    public function __construct(){
       //some code
    }

    public function get(\Slim\Http\Request $request, \Slim\Http\Response $response, $args = []) {
       //some super foobar code
    }

    public function post(\Slim\Http\Request $request, \Slim\Http\Response $response, $args = []) {
       //some other code
    }

The Controller\MyClass is resolved through the use of PSR autoload

in Controller/MyOtherClass :

namespace MyApp\Controller;

class MyOtherClass{

    public function __construct(){
       //some code
    }

    public function run(\Slim\Http\Request $request, \Slim\Http\Response $response, $args = []) {
       //some amazing foobar code
    }

Solution 5

Nikic's Fast Route is a very minimal router, so some of the niceties of the bigger frameworks are removed. Here's a basic solution:

routes.php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

$app->get('/', function($req, $resp, $args) use ($app){return FooBar::asdf($app, $req, $resp);});

controller use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ResponseInterface as Response;

class FooBar{
    static public function asdf(Slim\App $app, Request $req, Response $resp, $args = [])
    {
        return $resp->withJson(['asf']);
    }
}
Share:
18,438
James Okpe George
Author by

James Okpe George

A developer has not stack but works with: PHP Ruby / Ruby on Rails C# Javascript/ NodeJS

Updated on June 09, 2022

Comments

  • James Okpe George
    James Okpe George almost 2 years

    I am creating an API using the Slim framework. Currently I use a single file to create the route and pass a closure to it:

    $app->get('/', function($req, $resp){
    //Code...
    })
    

    But I realise that my file has grown rapidly. What I want to do is use controllers instead, so I will have a controller class and just pass the instance/static methods to the route, like below

    class HomeController
    {
       public static function index($req, $resp){}
    }
    

    and then pass the function to the route

    $app->get('/', HomeController::index);
    

    I tried this, but it does not work, and I wonder if there is a way I can use it to manage my files.

  • Elby
    Elby over 7 years
    Which folder is used for add controller ?
  • malte
    malte over 7 years
    If you subclass slim\application and include the route file inside there then you can use $this consistently throughout the route configuration. I added an example here stackoverflow.com/questions/41981048/… Also, it would be possible to have a route configuration class that takes the Application as a constructor dependency
  • Strnm
    Strnm about 6 years
    Very nice indeed! Thanks! How would you inject a service directly into the controller without going through the container using this?
  • Zamrony P. Juhara
    Zamrony P. Juhara about 6 years
    @Roman when you use proper namespace and using composer, you do not need to call require() on your own because autoload.php will do it for you.
  • Zamrony P. Juhara
    Zamrony P. Juhara about 6 years
    While this works, controller instance creation should be done inside dependency container registration
  • crafter
    crafter about 5 years
    I see you pass $logger to the controller, should you not pass the container?
  • Ivan Dudarev
    Ivan Dudarev about 5 years
    @crafter passing a container to a controller is a bad practice. see en.wikipedia.org/wiki/Single_responsibility_principle and en.wikipedia.org/wiki/Dependency_injection
  • crafter
    crafter about 5 years
    I hear you. You are correct, that container is too large to drag along into your classes.