PHP Slim Framework Create Controller
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
- http://www.slimframework.com/docs/objects/router.html#how-to-create-routes
- http://www.slimframework.com/docs/objects/router.html#route-callbacks.
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']);
}
}
James Okpe George
A developer has not stack but works with: PHP Ruby / Ruby on Rails C# Javascript/ NodeJS
Updated on June 09, 2022Comments
-
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 over 7 yearsWhich folder is used for add controller ?
-
malte over 7 yearsIf 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 about 6 yearsVery nice indeed! Thanks! How would you inject a service directly into the controller without going through the container using this?
-
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 about 6 yearsWhile this works, controller instance creation should be done inside dependency container registration
-
crafter about 5 yearsI see you pass $logger to the controller, should you not pass the container?
-
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 about 5 yearsI hear you. You are correct, that container is too large to drag along into your classes.