軽量PHPフレームワークSlimを使ってサクッとWebアプリひな形を作ってみる
LaravelやCakePHPのようなWebアプリ開発に必要な機能が一通りそろったフレームワークをフルスタックフレームワークと呼ぶのに対し、Slimは軽量フレームワーク(マイクロフレームワーク)と呼ばれます。
フルスタックフレームワークとの違いは、必要最小限の機能だけを有していることによる、学習コストの低さと、軽量さ(ファイルサイズ、実行速度)です。
Slimを使って必要最小限の機能を備えたWebアプリのひな形を作ってみます。
公式サイト
GitHub
目次
プロジェクトの作成
Slim本体はComposerを使ってインストールします。バージョン4が出てますが3系の方が分かりやすかったのでこちらを使います。
まっさらな状態で始めることもできますが、スケルトンと呼ばれる、初期構成のフォルダ・ファイルが用意されたものでプロジェクトを作成します。
composer create-project slim/slim-skeleton:^3.* myapp
できあがるファイル・ディレクトリ構成は次のようになります(一部割愛)。
myapp/
├───logs/
├───public/
│ index.php
│ .htaccess
├───src/
│ dependencies.php
│ middleware.php
│ routes.php
│ settings.php
├───templates/
│ index.phtml
├───tests/
└───vendor
インストールできたらローカルサーバーで実行してみます。
cd myapp
php -S localhost:8888 -t public public/index.php
「http://localhost:8888/」にアクセスするとデフォルトページが表示されます。
サンプルページとフレームワークの処理
「http://localhost:8888/Slim」にアクセスすると、デフォルトで用意されているサンプルページが表示されます。このページの処理を追いかけてフレームワークの詳細をつかみます。
public/index.php
<?php if (PHP_SAPI == 'cli-server') { // To help the built-in PHP dev server, check if the request was actually for // something which should probably be served as a static file $url = parse_url($_SERVER['REQUEST_URI']); $file = __DIR__ . $url['path']; if (is_file($file)) { return false; } } require __DIR__ . '/../vendor/autoload.php'; session_start(); // Instantiate the app $settings = require __DIR__ . '/../src/settings.php'; $app = new \Slim\App($settings); // Set up dependencies $dependencies = require __DIR__ . '/../src/dependencies.php'; $dependencies($app); // Register middleware $middleware = require __DIR__ . '/../src/middleware.php'; $middleware($app); // Register routes $routes = require __DIR__ . '/../src/routes.php'; $routes($app); // Run app $app->run();フレームワークの起点となるファイルです。
.htaccess
で静的ファイル以外のURLへのリクエストをこのファイルにリライトします。
内部で以下のファイルを順にインクルードしていて、フレームワークそのものであるAppインスタンスにセット・実行しています。
- src/settings.php
- src/dependencies.php
- src/middleware.php
- src/routes.php
src/settings.php
<?php return [ 'settings' => [ 'displayErrorDetails' => true, // set to false in production 'addContentLengthHeader' => false, // Allow the web server to send the content-length header // Renderer settings 'renderer' => [ 'template_path' => __DIR__ . '/../templates/', ], // Monolog settings 'logger' => [ 'name' => 'slim-app', 'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log', 'level' => \Monolog\Logger::DEBUG, ], ], ];アプリケーションの設定を記述するファイルです。
エラー表示の有無や、テンプレートやログの配置をここで設定しています。
任意のキーでユーザー独自の設定も作れます。
設定は次のようにフレームワーク内で取得できます。
$container = $app->getContainer(); $settings = $container->get('settings');
src/dependencies.php
<?php use Slim\App; return function (App $app) { $container = $app->getContainer(); // view renderer $container['renderer'] = function ($c) { $settings = $c->get('settings')['renderer']; return new \Slim\Views\PhpRenderer($settings['template_path']); }; // monolog $container['logger'] = function ($c) { $settings = $c->get('settings')['logger']; $logger = new \Monolog\Logger($settings['name']); $logger->pushProcessor(new \Monolog\Processor\UidProcessor()); $logger->pushHandler(new \Monolog\Handler\StreamHandler($settings['path'], $settings['level'])); return $logger; }; };アプリケーションとコンポーネントの依存関係を設定するファイルです。
デフォルトではテンプレートエンジンとログの依存関係が設定してあります。
例えばロガーのコンポーネントを変えてもフレームワーク上は
$container['logger']
で変わらずインスタンスにアクセスできるようにする工夫ですね。
src/middleware.php
<?php use Slim\App; return function (App $app) { // e.g: $app->add(new \Slim\Csrf\Guard); };リクエスト・レスポンスとMVC処理の間に挟まる処理を記述するファイルです。
例えばデバッグツールバーの設定をここで行ったりします。
src/routes.php
<?php use Slim\App; use Slim\https\Request; use Slim\https\Response; return function (App $app) { $container = $app->getContainer(); $app->get('/[{name}]', function (Request $request, Response $response, array $args) use ($container) { // Sample log message $container->get('logger')->info("Slim-Skeleton '/' route"); // Render index view return $container->get('renderer')->render($response, 'index.phtml', $args); }); };URLから対応する処理へのルーティングを行う部分です。
上に書いたものから順にURLのパターンとhttpsメソッドに一致するか見ていき、一致した場合割り当てられた関数の処理が実行されます。
サンプルページは、URLの文字列を$name変数に入れ、
templates/index.phtml
のレンダリングを行っています。
以上がSlim3フレームワークの処理の大まかな流れです。
フルスタックフレームワークに比べシンプルでわかりやすいですね。
カスタマイズする
このままでも、十分ちょっとしたPHPアプリの作成には事足りそうですが、せっかくなのでもうちょっとMVCっぽくしてみます。コントローラーを分離する
デフォルトだとルーティングの中に匿名関数が埋め込まれていて、処理が大きくなると、コードの見通しが悪くなりそうです。コントローラーをクラスとして独立させて、ルーティングではメソッドを呼び出すだけにしてみます。
クラス作成
myapp
ディレクトリの中に新たにcontrollers
ディレクトリを作成し、その中にHello.php
というクラスファイルを作成します。
<?php namespace Slim\App\Controllers; class Hello { private $c; public function __construct($container) { $this->c = $container; } public function index($request, $response, $args) { // Sample log message $this->c->get('logger')->info("Slim-Skeleton '/' route"); // Render index view return $this->c->get('renderer')->render($response, 'index.phtml', $args); } }コントローラーのメソッドの処理はルーティングの中に書かれていた匿名関数の中身です。
ルーティングからコントローラーのメソッドを呼び出す。
<?php use Slim\App; use Slim\https\Request; use Slim\https\Response; return function (App $app) { $container = $app->getContainer(); $app->get('/[{name}]', function (Request $request, Response $response, array $args) use ($container) { $Hello = new Slim\App\Controllers\Hello($container); return $Hello->index($request, $response, $args); }); };ルーティングの中では先ほど用意したクラスのインスタンス化、メソッド呼び出しを行います。
オートロードの設定
このままでは、コントローラークラスがロードされないので、オートロードされるようcomposer.json
に記述を追加します。
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/",
"Slim\\App\\Controllers\\": "controllers/"
}
},
追加したら、下記のコマンドでオートローダーをリフレッシュします。
composer dump-autoload
これで、サンプルページにアクセスすると先ほどと変わらない表示ですが、コントローラーは分離されています。
データベースを使う
データベースを使ってみます。DB接続定義を外部ファイルに設定する
環境によって異なるDB接続定義は外部ファイルに記述するのが定石です。先にdotenvを使えるようにして、そこにDB接続定義を記述できるようにします。
composer require vlucas/phpdotenv
composerを使ってdotenvをインストールしたら、srcフォルダに.env
ファイルを作成し、データベースの情報を記述します。
host=localhost
dbname=test
user=test_user
pass=test_pass
src/settings.php
で.env
を読み込み、配列に接続情報をセットします。
<?php $dotenv = Dotenv\Dotenv::create(__DIR__); $dotenv->load(); return [ 'settings' => [ 'displayErrorDetails' => true, // set to false in production 'addContentLengthHeader' => false, // Allow the web server to send the content-length header // Renderer settings 'renderer' => [ 'template_path' => __DIR__ . '/../templates/', ], // Monolog settings 'logger' => [ 'name' => 'slim-app', 'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log', 'level' => \Monolog\Logger::DEBUG, ], // Database 'db' => [ 'host' => getenv('host'), 'dbname' => getenv('dbname'), 'user' => getenv('user'), 'pass' => getenv('pass'), ], ], ];
依存関係を設定する
src/dependencies.php
にPDOの依存関係を設定します。
// PDO $container['db'] = function ($c) { $db = $c['settings']['db']; $pdo = new PDO('mysql:host=' . $db['host'] . ';dbname=' . $db['dbname'], $db['user'], $db['pass']); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); return $pdo; };ここではMySQLを使います。
これでデータベース(PDO)を使う準備は完了です。
WebAPIを作る
PDOを使う機能をWebAPI形式で作ってみます。まずは
src/routes.php
にルーティングを追加します。
$app->get('/api/[{name}]', function (Request $request, Response $response, array $args) use ($container) { $Hello = new Slim\App\Controllers\Hello($container); return $Hello->getJson($request, $response, $args); });Helloクラスに
getJson
メソッドを追加します。
public function getJson($request, $response, $args) { $sql = <<< SQL SELECT * FROM animals ORDER BY name SQL; try { $stmt = $this->c->get('db')->prepare($sql); $stmt->execute(); $list = $stmt->fetchAll(); }catch(Exception $e){ $this->c->get('logger')->error($e->getMessage()); } $name = $request->getAttribute('name'); return $response->withJson([ "name" => $name, "list" => $list, ], 200); }SQLは実行環境に合わせて変更してください。
「http://localhost:8888/api/Slim」と実行すると次のようにJSONが返ります。
{ "name": "Slim", "list": [{ "id": "3", "name": "bird" },{ "id": "2", "name": "cat" },{ "id": "1", "name": "dog" }] }
ここまでやってみて、Slimが他のフレームワークと比べて圧倒的にシンプルで使いやすいことが分かりました。
個人的にも気に入ったので、ちょっとしたWebアプリの開発ならSlimをドンドン推していきたいですね。
では。
ディスカッション
コメント一覧
まだ、コメントがありません