PHP Slim Framework Create Controller

2020-07-23 03:52发布

问题:

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.

回答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.


回答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.



回答3:

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
    }


回答4:

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



回答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']);
    }
}