Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Slim Framework 3 MVC Skeleton Application

はじめに

過去にSlim 1やSlim 2を使っていて、いくつかのサイトに用いて実戦投入しましたが、最近は主にCakePHPなどに代表されるフルスタックなフレームワークを使っていました。ただフロントエンドがReactやVueなどを用いることが多くなって、バックエンド側もAPIサーバで十分という場合も多く、フルスタックフレームワークはスペックオーバーに感じる今日この頃。
そこでシンプルなWEBサイトやAPIサーバ用にマイクロフレームワークのSlim 3を用いてMVCぽい感じでアプリケーションを作成できる雛形を作ってみました。

ちなみにSlimの名前はテンプレートエンジンのSlimと被っていて、あちらの方がメジャーなのでググラビリティが低いですね。

使用コンポーネント

  • Eloquent ORM (モデル)
  • PHP-View (ビュー)
  • Pimple (DIコンテナ)
  • Monolog (ログ)
  • PHPUnit (テスト)

インストール

新規にプロジェクトを作るのはComposerを使います。

composer create-project m92o/slim-mvc-skeleton [my-app-name]

サンプルコードも含まれているのすぐに動きます。
テストを動かす場合は、[my-app-name]ディレクトリに移動して

composer test

ビルトインサーバでアプリを動かす場合は

composer start

で、 http://localhost:8080/ にアクセスしてみてください。

ディレクトリ構成

├── app
│   ├── configs
│   │   ├── dependencies.php
│   │   ├── middleware.php
│   │   ├── routes.php
│   │   └── settings.php
│   ├── controllers
│   │   ├── AppController.php
│   │   └── HomeController.php
│   ├── libs
│   │   ├── Facade.php
│   │   └── Log.php
│   ├── models
│   │   ├── AppModel.php
│   │   └── User.php
│   ├── views
│   │   └── home.phtml
│   ├── bootstrap.php
│   └── environment.php
├── containers
├── db
├── logs
├── public
│   └── index.php
├── tests
│   └── Functional
│       ├── BaseTestCase.php
│       └── HomepageTest.php
├── vendor
├── composer.json
├── docker-compose.yml
└── phpunit.xml

Slim公式のslim-skeletonを使ったことある人には見覚えのあるファイルもありますね。/app/configsにあるファイルは、ほぼslim-skeletonのままです。MVCに合わせて models / controllers / views のディレクトリが用意されています。それ以外は libs に入れる感じ。

/containersはDockerコンテナの設定などです。

使い方

サンプルコードが含まれているので、それを見ながら説明します。

設定

環境設定

DB等の設定は/app/configs/settings.phpに書きます。
環境変数SLIM_ENVの値により使用する設定を切り替えるようになっています。SLIM_ENVが未設定の場合はdevelopmentが使用されます。

settings.php
environments = [
    'production' => [
        'db' => [
            'driver' => 'mysql',
            'host' => 'localhost',
            'database' => 'database',
            'username' => 'user',
            'password' => 'password',
            'charset'   => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix'    => ''
        ]
    ]
];

ルーティング

ルーティングの設定は/app/configs/routes.phpです。

routes.php
<?php
use Controllers\HomeController;

// Routes
$app->get('/', HomeController::class . ':index');

/ にGETメソッドでアクセスが来たら、HomeControllerクラスのindexメソッドを呼び出すという設定になります。ルーティング設定は全て自分で書く必要があります。

ルーティングの詳細はSlimのドキュメントを参照してください。
https://www.slimframework.com/docs/v3/objects/router.html#container-resolution

コントローラ

コントローラは、AppControllerを継承して書いていきます。routes.phpで設定したメソッドを実装します。

HomeController.php
<?php
namespace Controllers;

use Slim\Http\Request;
use Slim\Http\Response;
use Controllers\AppController;
use Models\User;
use Libs\Log;

class HomeController extends AppController {
    public function index(Request $request, Response $response, array $args) {
        $user = User::find(1);
        //Log::info('User', ['fullName' => $user->fullName]);
        return $this->view->render($response, 'home.phtml', ['user_name' => $user->fullName]);
    }
}

Userはモデルです。ログはLog::info()のようにスタティックメソッドとして呼び出し可能です。(LaravelのFacadeを真似てある)

ログの使い方はMonologのドキュメントを参照にしてください。
https://github.com/Seldaek/monolog

$this->view->render()でビューを呼び出します。

モデル

モデルはAppModelを継承して書いていきます。AppModelはEloquent ORMを継承したものです。

User.php
<?php
namespace Models;

use Models\AppModel;

class User extends AppModel {
}

今回は中身が空ですが、ここにビジネスロジックを書く形です。
クラス名(単数形)の複数形がテーブル名になっている必要があります。レールを外れる場合は protected $table = 'table_name';のようにクラス変数に記述します。

詳しくはLaravelのドキュメントを参照してください。
https://laravel.com/docs/5.7/eloquent

ビュー

テンプレートエンジンにはPHP-Viewを使用していますので、ただのPHPファイルです。HTMLにPHPのコードを埋め込みます。

home.phteml
Hello, <?= $user_name ?>!

コントローラで呼び出した$this->view->render()の第3引数の連想配列が、ビューに渡された変数になります。(連想配列のuser_nameキーの値が、$user_nameで取り出せる)

テスト

テストはBaseTestCaseを継承して書いていきます。PHPUnitです。

HomepageTest.php
<?php
namespace Tests\Functional;

class HomepageTest extends BaseTestCase {
    /**
     * Test that the index route with optional name argument returns a rendered greeting
     */
    public function testGetHomepageWithGreeting() {
        $response = $this->runApp('GET', '/');

        $this->assertEquals(200, $response->getStatusCode());
        $this->assertEquals('Hello, John Smith!', $response->getBody());
    }
}

$this->runApp()でURLにアクセスして、戻ってきたレスポンスの中身を確認します。

まとめ

以上、ざっくりとした説明でした。

マイクロフレームワークを用いて、単純なMVCフレームワークを作ってみました。フルスタックフレームワークの便利さはありませんが、RESTでJSONを返す程度のAPIサーバならこの程度で十分そうです。

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
6
Help us understand the problem. What are the problem?