php Slim3からSlim4へ移行する際のメモ


以下の手順を参考に作業。
https://codezine.jp/article/detail/11904


## ライブラリのバージョンアップ  + 追加インストール	
```
//update
composer require slim/slim
composer require monolog/monolog

//追加
composer require slim/psr7
composer require php-di/php-di

```

## 移行作業

### index.phpの修正
DIコンテナの変更のため、index.phpとdependencies.phpの設定を変更。
Slim\Factory\AppFactoryとDI\Containerを使うように変更。

```
use Slim\Factory\AppFactory; 
use DI\Container;

```
以下の流れ
settingのjsonを取得。
containerを作成。
containerにsettingをsetしてdependenciesにcontainerを渡してまたcontanierを返してもらう

そのcontainerを素にAppFactoryでcreateする。

```
// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';


// Set up dependencies
$container = new Container();
$container->set('settings', $settings['settings']);
$dependencies = require __DIR__ . '/../src/dependencies.php';
$container = $dependencies($container);

AppFactory::setContainer($container); 
$app = AppFactory::create(); 

```

dependencies.phpはcontainerを受け取るように修正して、
contaier->setで保存するようにする。

```
use DI\Container;
return function (Container $container) {
  $container->set('renderer', function ($c) {

...省略

```

### App/HTTP/系をSlim\Psr7\系に変更
```
// use Slim\Http\Request;
// use Slim\Http\Response;
use Slim\Psr7\Request;
use Slim\Psr7\Response;

```

### middlewareを変更
クロージャーで作成していたmiddlewareにうまく引数がわたせなくなったので、classで作成するように修正。

```
$requireLogin = function ($request, $response, $next) {
   // 
}
//上記処理を
$app->get('/user/index', UserController::class . ':index')->add($requireLogin);
```
↓以下の感じに直す

```
//classを1ファイルで作成
<?php
class RequireLoginMiddleware
{
    public function __construct($db)
    {
       // 
    }

    public function __invoke(Request $request, RequestHandler $handler): Response
    {  
        //処理
    }
}

//インスタンスをaddする
//引数を渡すときはコンストラクタに渡して保持してもらう。
$app->get('/user/index', UserController::class . ':index')->add(new RequireLoginMiddleware());
```

### エラー1

``` 
Uncaught TypeError: Slim\Handlers\Strategies\RequestResponse::__invoke(): Return value must be of type Psr\Http\Message\ResponseInterface, null 
```
controllerの中でresponseを明確にreturnしないと上記エラーがでるようになった。middlewareの影響かも。各所にreturn $response;を追加。


### エラーハンドリングの修正
dependencies.phpで設定していたエラーハンドラはCustomErrorHandlerとして別ファイルに外だし。
index.phpの中で設定を追加。
参考https://codezine.jp/article/detail/12397?p=3

```
class CustomErrorRenderer implements ErrorRendererInterface
{
	private $container;	
	public function __construct(ContainerInterface $container)
	{
		$this->container = $container;
	}
	
	public function __invoke(Throwable $exception, bool $displayErrorDetails): string
	{
        $msg =[];
        if($exception instanceof HttpNotFoundException) {
           $msg = ['message' => 'Not Found'];        
        }elseif($exception instanceof HttpMethodNotAllowedException) {
           $msg = ['message' => 'Method Not Allowed'];       
        }else{
           $msg =['message' => 'Internal Server Error'];
        }
        return json_encode($msg);

	}
}
```

```
# index.php
$app = AppFactory::create(); 

//　以下追加
$app->addRoutingMiddleware();
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->forceContentType('application/json'); 
$errorHandler->registerErrorRenderer('application/json', CustomErrorRenderer::class);
```


### UnitTestの修正

- settingやcontainer周りはindex.phpと同じように修正。

- responseの取得をprocessからhandleに変更

```
$response = $app->process($request, $response);
↓
$response = $app->handle($request);    
```

-`Request::createFromEnvironment($environment);`が使えなくなったので、自前でcreateRequst()を追加。
参考
https://github.com/slimphp/Slim-Skeleton/blob/master/tests/TestCase.php#L68
https://discourse.slimframework.com/t/migrating-from-slim-3-to-4-writing-php-unit-tests/4193/2

- 合わせてgetのquery parameterの渡し方の変更が必要になった。URLに?＋クエリーをそのままつけていたが、?がついているとエスケープされて404になってしまう。以下のように修正。

```
$request =$request->withQueryParams(['key'=> 'value']);

```