Help us understand the problem. What is going on with this article?

私家版 Slim Framework チュートリアル (2) 〜 ルーティングと新規作成編

この記事について

PHP のマイクロフレームワークのひとつである、Slim Framework ですが、チュートリアルがいまいちイケてないので、お題を流用しつつ、初学者にももう少し分かりやすくなるよう、アレンジしてみようという試みです。

本記事は第2回で、前回はこちら。

私家版 Slim Framework チュートリアル (1) 〜 特徴と準備編 - Qiita

概要

今回はルーティングについて説明し、新規作成フォームからチケットを作成してデータベースに保存するところまでを実装していきます。

3. ルーティング

3.1. ルーティングの書き方について

src/routes.php を開いてください。

インストール直後は、以下のような内容になっています。

routes.php
<?php

use Slim\Http\Request;
use Slim\Http\Response;

// Routes

$app->get('/[{name}]', function (Request $request, Response $response, array $args) {
    // Sample log message
    $this->logger->info("Slim-Skeleton '/' route");

    // Render index view
    return $this->renderer->render($response, 'index.phtml', $args);
});

ルーティングは、 $app->get(URL, 関数) の形式で記述し、 get の他に、post, put, patch, delete などがあります。

これらは HTTP リクエストメソッドに対応しており、上記5つが主に使われますが、ひとまずここでは基本となる getpost のみ覚えてください。

HTTP リクエストメソッド - HTTP | MDN

GET と POST の違いが分からない方はこちらの記事を参考に。

GETとPOSTの違いについて - Qiita

上の例では、名前付きプレースホルダーと呼ばれる(ルートパラメータと呼ばれることもあります)、変数が URL に含まれています。

試しに、ブラウザにて http://localhost:8080/John を開いてみてください。

Try SlimFramework と表示されていた部分が、Hello John! に置き換わりました。

templates/index.phtml の中を見ると、以下のように条件分岐されており、 $name という変数が使われています(この変数に、URL の末尾に追加した文字列が格納されて表示されます)。

        <?php if (isset($name)) : ?>
            <h2>Hello <?= htmlspecialchars($name); ?>!</h2>
        <?php else: ?>
            <p>Try <a href="http://www.slimframework.com">SlimFramework</a></p>
        <?php endif; ?>

3.2. ルーティングの追加

今回は以下のルーティングを使用します。チケットの一覧表示、新規作成、1件表示、編集、削除が一通りできるようになります。

  • GET /tickets - チケット一覧の表示
  • GET /tickets/create - チケットの新規作成用フォームの表示
  • POST /tickets - チケットの新規作成
  • GET /tickets/{id} - チケットの表示
  • GET /tickets/{id}/edit - チケット編集用フォームの表示
  • PATCH /tickets/{id} - チケットの更新
  • DELETE /tickets/{id} - チケットの削除

$app->get('/[{name}]', ...) の行よりに、以下のルーティングを追加してください。

routes.php
// 一覧表示
$app->get('/tickets', function (Request $request, Response $response) {
});

// 新規作成用フォームの表示
$app->get('/tickets/create', function (Request $request, Response $response) {
});

// 新規作成
$app->post('/tickets', function (Request $request, Response $response) {
});

// 表示
$app->get('/tickets/{id}', function (Request $request, Response $response, array $args) {
});

// 編集用フォームの表示
$app->get('/tickets/{id}/edit', function (Request $request, Response $response, array $args) {
});

// 更新
$app->patch('/tickets/{id}', function (Request $request, Response $response, array $args) {
});

// 削除
$app->delete('/tickets/{id}', function (Request $request, Response $response, array $args) {
});

routes.php 全体は以下をご覧ください。

https://github.com/nunulk/Tutorial-First-Application/blob/chapter3/src/routes.php

4. 新規作成

4.1. チケットの新規作成フォーム

まず最初に、チケットを作成するためのフォームをつくります。

新規作成用フォームを表示するためのルーティングを編集していきましょう。

routes.php
// 新規作成用フォームの表示
$app->get('/tickets/create', function (Request $request, Response $response) {
    return $this->renderer->render($response, 'tickets/create.phtml');
});

続いて、テンプレートファイルを作成します。

templates ディレクトリの下に、tickets ディレクトリをつくり、そこに create.phtml というファイルをつくります。

拡張子が .phtml となっていますが、単なる PHP ファイルですので、 .php でも構いません(本記事では公式に倣って .phtml で統一します)。

こんな感じに、まずは件名だけを入力できるようにします。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8"/>
  <title>チケット管理</title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>
<body>
  <div class="container">
    <h1>チケット管理</h1>
    <form method="POST" action="/tickets">
      <div class="card">
        <div class="card-body">
          <h2 class="card-title">チケット作成</h2>
          <div class="card-text">
            <div class="form-group">
              <label for="subject">件名</label>
              <input type="text" name="subject" id="subject" class="form-control">
            </div>
          </div>
        </div>
        <div class="card-body">
          <button class="btn btn-primary">作成</button>
        </div>
      </div>
    </form>
  </div>
</body>
</html>

form 要素の method と action を、

<form method="POST" action="/tickets">

新規作成用ルーティングのメソッドと URL に一致するようにしてください。

// 新規作成
$app->post('/tickets', function (Request $request, Response $response) {

4.2. 新規作成

では、新規作成用ルートの中身を実装していきます。

// 新規作成
$app->post('/tickets', function (Request $request, Response $response) {
    $subject = $request->getParsedBodyParam('subject');
    // ここに保存の処理を書く
    // 保存が正常にできたら一覧ページへリダイレクトする
    return $response->withRedirect("/tickets");
});

正常にリダイレクトされたことが分かるように、一覧表示のレスポンスにも少し手を加えておきます。

$app->get('/tickets', function (Request $request, Response $response) {
    return $response->write('tickets');
});

これで、 新規作成フォームの「作成」ボタンを押すと、

  1. 新規作成が行われる(未実装)
  2. チケット一覧表示ページにリダイレクトされる
  3. "tickets" と表示される

という流れになるはずです。

では、「作成」ボタンをクリックしてみましょう。

ページの左上に "tickets" と表示されましたでしょうか?

Slim では基本的に以下のようにレスポンスを返します。

  1. 単なるテキスト $response->write()
  2. PHP View $this->renderer->render($response, $templatePath)
  3. リダイレクト $response->withRedirect($url)
  4. JSON $response->withJson($data)

場合に応じて使い分けてください。

4.3. データベースに保存する

フォームからリクエストを送信して、データを受け取り、一覧表示へリダイレクトするところまで書きました。

ここからは、受け取ったデータをデータベースへ保存する処理を書いていきます。

4.3.1. データベースとテーブルの作成

データベースは MySQL (5.7) を使用します。インストールされてない場合は、お使いの OS 向けガイドにしたがってインストールしてください(5.7 の日本語版がまだないので 5.6 のを載せますが、インストール方法は同じなはずです)。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 2 MySQL のインストールと更新

macOS の場合は homebrew でインストールするのがいいでしょう。

$ brew install mysql

インストールができたら、ターミナルから MySQL クライアントを起動して、データベースとテーブルをつくります。

$ mysql -uroot

mysql> create database slim_tutorial default charset utf8mb4 collate utf8mb4_general_ci;
mysql> use slim_tutorial;
mysql> create table tickets(id int unsigned not null auto_increment, subject varchar(255) not null, primary key(id));

以降で、データベースの中身を確認することが度々あるので、Sequel Pro などの GUI クライアントをインストールしておくといいでしょう。

https://sequelpro.com/download

4.3.2. データベースの設定

src/settings.php を開いてください。

// database 以下を下記の場所に記述してください。

        // Monolog settings
        'logger' => [
            'name' => 'slim-app',
            'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log',
            'level' => \Monolog\Logger::DEBUG,
        ],

        // database
        'db' => [
            'host'   => 'localhost',
            'user'   => 'root',
            'pass'   => '',
            'dbname' => 'slim_tutorial'
        ],
    ],
];

4.3.3. コンテナへの追加

続いて、 src/dependencies.php を開きます。

同様に、 //database 以下の行を、以下の場合に記述してください。

// 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;
};

// database
$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;
};

データベースアクセスは、 PDO を使用します。

PDO の詳しい説明は以下をご覧ください。

PHP: PDO - Manual

これで準備は OK です。

4.3.4. 保存処理を書く

src/routes.php にある、新規作成用ルートの処理に、データベースへの保存処理を追加します。

// 新規作成
$app->post('/tickets', function (Request $request, Response $response) {
    $subject = $request->getParsedBodyParam('subject');
    // ここに保存の処理を書く
    $sql = 'INSERT INTO tickets (subject) values (:subject)';
    $stmt = $this->db->prepare($sql);
    $result = $stmt->execute(['subject' => $subject]);
    if (!$result) {
        throw new \Exception('could not save the ticket');
    }

    // 保存が正常にできたら一覧ページへリダイレクトする
    return $response->withRedirect("/tickets");
});

コンテナに登録した PDO のオブジェクトは、 $this->db でアクセスできます。

$this->db->prepare() でプリペアドステートメントを用意し、 $stmt->execute() で INSERT 文を実行する、という流れになります。

エラーが起きた場合の対処は、いくつかやり方がありますが、今回は手間を惜しんで例外をスローするようにしました。

再度新規作成フォームから適当に件名を入力し、作成ボタンをクリックしてください。

tickets テーブルにレコードが生成されていたら成功です。

次回は、一覧表示と1件表示を実装していきます。

私家版 Slim Framework チュートリアル (3) 〜 表示編 - Qiita

nunulk
PHP, Laravel, オブジェクト指向プログラミング, デザインパターン, リファクタリング, 関数プログラミング, etc.
http://nunulk.hatenablog.com
phper-oop
ペチオブはオブジェクト指向ワーキンググループです。様々なエンジニアの方に参加頂いております。
https://phper-oop.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away