升级指南

如果你打算从 Slim 2 升级到 Slim 3,这里有一些重要的变化,你必须清楚。

新的 PHP 版本要求

Slim 3 要求 PHP 5.5+

新的路由函数签名

$app->get('/', function (Request $req,  Response $res, $args = []) {
    return $res->withStatus(400)->write('Bad Request');
});

获取 _GET 和 _POST 变量

$app->get('/', function (Request $req,  Response $res, $args = []) {
    $myvar1 = $req->getParam('myvar'); //检查 _GET 和 _POST [不遵循 PSR 7]
    $myvar2 = $req->getParsedBody()['myvar']; //检查 _POST  [遵循 PSR 7]
    $myvar3 = $req->getQueryParams()['myvar']; //检查 _GET [遵循 PSR 7]
});

钩子 / Hooks

Slim v3 不再有钩子的概念。You should consider reimplementing any functionality associated with the default hooks in Slim v2 as middleware instead. If you need the ability to apply custom hooks at arbitrary points in your code (for example, within a route), you should consider a third-party package such as Symfony’s EventDispatcher or Zend Framework’s EventManager.

移除 HTTP 缓存

在 Slim v3 我们将 HTTP 缓存迁移到了单独的模块中: Slim\Http\Cache.

移除 Stop/Halt

Slim Core has removed Stop/Halt. In your applications, you should transition to using the withStatus() and withBody() methods.

重定向的改变

在 Slim v2.x 我们需要使用助手函数 $app->redirect(); 来触发重定向请求。在 Slim v3.x 中,我们可以使用响应类来做这事。

Example:

$app->get('/', function ($req, $res, $args) {
  return $res->withStatus(302)->withHeader('Location', 'your-new-uri');
});

中间件签名

中间件的签名已经从一个类变成了函数。

新的签名:

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

$app->add(function (Request $req,  Response $res, callable $next) {
    // Do stuff before passing along
    $newResponse = $next($req, $res);
    // Do stuff after route is rendered
    return $newResponse; // continue
});

你仍然可以使用类来做签名:

namespace My;

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

class Middleware
{
    function __invoke(Request $req,  Response $res, callable $next) {
        // Do stuff before passing along
        $newResponse = $next($req, $res);
        // Do stuff after route is rendered
        return $newResponse; // continue
    }
}

// Register
$app->add(new My\Middleware());
// or
$app->add(My\Middleware::class);

Middleware Execution

Application middleware is executed as Last In First Executed (LIFE).

Flash Messages

Flash messages are no longer a part of the Slim v3 core but instead have been moved to seperate Slim Flash package.

Cookies

In v3.0 cookies has been removed from core. See FIG Cookies for a PSR-7 compatible cookie component.

Removal of Crypto

In v3.0 we have removed the dependency for crypto in core.

New Router

Slim now utilizes FastRoute, a new, more powerful router!

This means that the specification of route patterns has changed with named parameters now in braces and square brackets used for optional segments:

// named parameter:
$app->get('/hello/{name}', /*...*/);

// optional segment:
$app->get('/news[/{year}]', /*...*/);

Route Middleware

The syntax for adding route middleware has changed slightly. In v3.0:

$app->get(…)->add($mw2)->add($mw1);

urlFor() is now pathFor() in the router

urlFor() has been renamed pathFor() and can be found in the router object:

$app->get('/', function ($request, $response, $args) {
    $url = $this->router->pathFor('home');
    $response->write("<a href='$url'>Home</a>");
    return $response;
})->setName('home');

Also, pathFor() is base path aware.

Container and DI … Constructing

Slim uses Pimple as a Dependency Injection Container.

// index.php
$app = new Slim\App(
    new \Slim\Container(
        include '../config/container.config.php'
    )
);

// Slim will grab the Home class from the container defined below and execute its index method.
// If the class is not defined in the container Slim will still contruct it and pass the container as the first arugment to the constructor!
$app->get('/', Home::class . ':index');

// In container.config.php
// We are using the SlimTwig here
return [
    'settings' => [
        'viewTemplatesDirectory' => '../templates',
    ],
    'twig' => [
        'title' => '',
        'description' => '',
        'author' => ''
    ],
    'view' => function ($c) {
        $view = new Twig(
            $c['settings']['viewTemplatesDirectory'],
            [
                'cache' => false // '../cache'
            ]
        );

        // Instantiate and add Slim specific extension
        $view->addExtension(
            new TwigExtension(
                $c['router'],
                $c['request']->getUri()
            )
        );

        foreach ($c['twig'] as $name => $value) {
            $view->getEnvironment()->addGlobal($name, $value);
        }

        return $view;
    },
    Home::class => function ($c) {
        return new Home($c['view']);
    }
];

PSR-7 Objects

Request, Response, Uri & UploadFile are immutable.

This means that when you change one of these objects, the old instance is not updated.

// This is WRONG. The change will not pass through.
$app->add(function (Request $request, Response $response, $next) {
    $request->withAttribute('abc', 'def');
    return $next($request, $response);
});

// This is correct.
$app->add(function (Request $request, Response $response, $next) {
    $request = $request->withAttribute('abc', 'def');
    return $next($request, $response);
});

Message bodies are streams

// ...
$image = __DIR__ . '/huge_photo.jpg';
$body = new Stream($image);
$response = (new Response())
     ->withStatus(200, 'OK')
     ->withHeader('Content-Type', 'image/jpeg')
     ->withHeader('Content-Length', filesize($image))
     ->withBody($body);
// ...

For text:

// ...
$response = (new Response())->getBody()->write('Hello world!')

// Or Slim specific: Not PSR-7 compliant.
$response = (new Response())->write('Hello world!');
// ...