軽量フレームワーク Slimを試す - コントローラー・DB編

こんにちは、コバヤシです。
今回は前回に引き続き、Slimを試していきます。

tech.arms-soft.co.jp

前回はSlimのインストールとTwigを使えるまでやったので、今回はコントローラーの使用とDB接続をやっていきたいと思います。

コントローラーを作成する

前回はroutes.php内で直接twigをrenderし表示をしていましたが、これだとroutesが増えてきた時に煩雑になります。
Laravelと同じ様にコントローラーを作成して、その中でviewの処理を行うようにしたいと思います.

app/Http/Controllers/TestController.php を作成して以下を記述します。

<?php
namespace App\Http\Controllers;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Container\ContainerInterface;

class TestController
{
    private $app;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }
    
    public function index(RequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $view = $this->container->get(Twig::class);
        return $view->render($response, 'index.twig', []);
    }
}

コントローラー内でTwigを使用できるように、コンストラクタでContainerInterfaceをDIして、getでTwigのコンテナを取り出して使用しています。

routesでコントローラーを指定する

作成したコントローラーを使用するようにroutesに記述を変更します.

<?php
    // コメントアウト
    // $app->get('/', function (Request $request, Response $response) use ($app) {
    //     $twig = $app->getContainer()->get(Twig::class);
    //    return $twig->render($response, 'index.twig', []);
   // });

  // 以下を追加
  $app->get('/', '\App\Http\Controllers\TestController:index');

getの第2引数にコントローラー名:アクション名の形で記述すればOKです。

コントローラーが読み込まれるように設定する

上記のままではコントローラーが読み込まれないため、composerのautoloadに記述します。

    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "App\\Http\\Controllers\\": "app/http/controllers"
        }

ネームスペースと実際のパスを合うように追記します.

記述したら slimのあるディレクトリで以下を実行します。

composer dump-autoload

これでコントローラーを使用してviewが表示されるようになりました。

DBに接続する

今度はDBの接続をやっていきます。
Laravelで使用している「Eloquent」も利用できるようですが、今回はシンプルにPDOでの接続を行います。

app/settings.phpにDBの設定を追加します。

<?php
declare(strict_types=1);

use App\Application\Settings\Settings;
use App\Application\Settings\SettingsInterface;
use DI\ContainerBuilder;
use Monolog\Logger;

return function (ContainerBuilder $containerBuilder) {

    // Global Settings Object
    $containerBuilder->addDefinitions([
        SettingsInterface::class => function () {
            return new Settings([
                'displayErrorDetails' => true, // Should be set to false in production
                'logError'            => false,
                'logErrorDetails'     => false,
                'logger' => [
                    'name' => 'slim-app',
                    'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log',
                    'level' => Logger::DEBUG,
                ],
                'twig' => [
                    'strict_variables' => true,
                    'cache' => __DIR__ . '/../var/cache/twig',
                ],
                // 以下を追加
                // 設定内容は適宜書き換えてください
                'db' => [
                    'host'   => 'localhost',
                    'user'   => 'xxxxx',
                    'password'   => 'xxxxx',
                    'dbname' => 'xxxx_db',
                ]
            ]);
        }
    ]);
};

今回は直接記述していますが、本来はphpdotenvなどを使った方が良いですね。

github.com

次にコンテナに登録をします。

<?php
declare(strict_types=1);

use App\Application\Settings\SettingsInterface;
use DI\ContainerBuilder;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Monolog\Processor\UidProcessor;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Slim\Views\Twig;
use App\Application\Settings\Settings;

return function (ContainerBuilder $containerBuilder) {
    $containerBuilder->addDefinitions([
        LoggerInterface::class => function (ContainerInterface $c) {
            $settings = $c->get(SettingsInterface::class);

            $loggerSettings = $settings->get('logger');
            $logger = new Logger($loggerSettings['name']);

            $processor = new UidProcessor();
            $logger->pushProcessor($processor);

            $handler = new StreamHandler($loggerSettings['path'], $loggerSettings['level']);
            $logger->pushHandler($handler);

            return $logger;
        },
        Twig::class => function (ContainerInterface $container) {
            $settings = $container->get(SettingsInterface::class);
            return Twig::create(__DIR__ . '/../templates', $settings->get('twig'));
        },
       // 以下を追加します
        'db' => function(ContainerInterface $container) {
            $settings = $container->get(SettingsInterface::class);
            $dsn = 'mysql:host=%s;dbname=%s;charset=utf8mb4';
            $db  = $settings->get('db');
            $pdo = new \PDO(sprintf($dsn, $db['host'], $db['dbname']), $db['user'], $db['password']);
            $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
            $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
            return $pdo;
        }
    ]);
};

これでコントローラー内で使えるようになりました。
Twigと同じ様にコンテナを呼び出して使用します。

<?php
    public function index(RequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $view = $this->container->get(Twig::class);
        $container = $this->container->get('db');
  
        $sql = 'SELECT * FROM users';
        $query = $container->prepare($sql);
        $query->execute();
  
        $data = $query->fetchAll(\PDO::FETCH_ASSOC);
    
        return $view->render($response, 'index.twig', ['data' => $data]);
    }

まとめ

無事にコントローラーとDBを使用できるようになりました。
やはりフルスタックのフレームワークと違い準備までに時間が掛かりますね。
取り敢えずここまで試せたので、Slimは一段落とします。

これからも引き続きSlimなどのフレームワークを触っていきたいと思います。