Laravelでサブシステム用のディレクトリを分離する | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

標準のLaravelのディレクトリ構成でも特に問題なくアプリケーションの構築は行えるわけですが、このフレームワーク上で多数のシステムを動かすとなった場合、ディレクトリの構成をサブシステムごとに分離できたほうがよい場合があります。

例えば、システム数が多くなるとコントローラの数が増えてくるので(設定ファイルやViewファイルなども同様ですが)どのコントローラが何の処理をしているのかわかりづらくなってきたりで、あるシステムで構成するファイル群がまとまっていた方がターゲットが明確になったり、システムを削除する際にもそれ以下をごっそり消せばいいといったことができたりとかでメリットがあったりもします。


Laravelではディレクトリ構成をある程度自由にカスタマイズできるのでこういったことも簡単にできたりします。

ここでは、Laravel4.2を対象にしています。



アプリケーション用のディレクトリを分離する


今回は、下記のようなディレクトリ構成にしたいと思います。


laravel
  + app
     + Sys
        + Subsys
           + controllers
           + config
           + lang
           + models
           + services
           + views
           + routes.php
  + controllers
  + config
  + lang
  + models
  + views
  + routes.php

Sysディレクトリ以下が新しく作ったディレクトリ構成で、Subsysディレクトリ下はapp直下にあるcontrollersやconfigなどオリジナルのディレクトリ構成と合わせています(サービスプロバイダ用ファイルを登録するservicesディレクトリは追加してます)。

サブシステムを追加したければSubsysディレクトリをさらにコピーしてあげれば幾つでも追加していけます。


$ cd /path/to/laravel/app
$ mkdir -p Sys/Subsys
$ cd Sys/Subsys/
$ mkdir config controllers lang models services views

ここで作ったディレクトリはLaravelの基本セットです。

後述する設定によってどのファイルがどのディレクトリにあるのかを対応付けさせればよいので、名前などは自由に決めれますし例えばライブラリファイルとしてオリジナルのlibディレクトリを追加するといったこともできます。


次に、Laravelでアプリを作る際の基本となるcontollerファイルとviewファイルを作ります。

この作業はLaravelでアプリを作る際の作業と同じです。

コントローラーファイルは、Sys/Subsys/controllersディレクトリに配置します。


<?php

class BarController extends Controller
{
    public function anyIndex()
    {
        // viewを生成
        return View::make('subsys::bar');
    }
}

ビューファイルは、Sys/Subsys/viewsディレクトリに配置します。


<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>hello world</title>
</head>
<body>
hello world
</body>
</html>

次は、ルーティングの設定です。

URLで/barにアクセスしたら先ほどのBarControllerを呼び出すようにしてみます。

routes.phpファイルはSubsysディレクトリ直下に配置します。


<?php

// barシステム用
Route::any('bar', 'BarController@anyIndex');

次は、サービスプロバイダーファイルの作成です。

ここでは新しく追加したディレクトリを定義したり、プレフィックスを定義することでコントローラ内から簡易的な呼び出し方ができるようにセットしておきます。

サービスプロバイダーファイルはservicesディレクトリに配置します。


<?php
namespace Sys\Subsys\services; 

use Illuminate\Support\ServiceProvider;

class BarServiceProvider extends ServiceProvider
{
    public function register()
    {
    // IoCコンテナ登録のみ行うことが推奨されています
    }

    public function boot()
    {
    // Laravel用クラスローダーの登録
    \ClassLoader::addDirectories( array(
    // 独自で設定したフォルダを記載
        __DIR__.'/../controllers',
        __DIR__.'/../models',
    ));

    // ビュー、言語、設定の名前空間(プレフィックス)設定
    // 独自で設定したフォルダを記載
    \View::addNamespace( 'subsys', __DIR__.'/../views' );
    \Lang::addNamespace( 'subsys', __DIR__.'/../lang' );
    \Config::addNamespace( 'subsys', __DIR__.'/../config' );

    // ルート定義の読み込み
    require __DIR__.'/../routes.php';
   }
}

addDirectories()によって、独自のcontollersやmodelsディレクトリを使うように宣言したり、subsysプレフィックスを追加することで、先ほどのBarController.php内での


return View::make('subsys::bar');

という呼び出し方が可能なように定義しています。

subsysプレフィックスを付けるとviews、lang、configディレクトリからファイルを探してくれます。

設定ファイルも


$const = Config::get('subsys::foo.bar');

のような呼び出し方ができたりします。

次にこのサービスプロバイダをLaravel本体に認識させます。

これは、laravel/app/config/app.phpの中にprovidersという設定項目があるのでその中に追加します。


    'providers' => array(
        'Illuminate\Foundation\Providers\ArtisanServiceProvider',
        'Illuminate\Auth\AuthServiceProvider',
        'Illuminate\Cache\CacheServiceProvider',
        'Illuminate\Session\CommandsServiceProvider',
        'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider',
        'Illuminate\Routing\ControllerServiceProvider',
        'Illuminate\Cookie\CookieServiceProvider',
        'Illuminate\Database\DatabaseServiceProvider',
        'Illuminate\Encryption\EncryptionServiceProvider',
        'Illuminate\Filesystem\FilesystemServiceProvider',
        'Illuminate\Hashing\HashServiceProvider',
        'Illuminate\Html\HtmlServiceProvider',
        'Illuminate\Log\LogServiceProvider',
        'Illuminate\Mail\MailServiceProvider',
        'Illuminate\Database\MigrationServiceProvider',
        'Illuminate\Pagination\PaginationServiceProvider',
        'Illuminate\Queue\QueueServiceProvider',
        'Illuminate\Redis\RedisServiceProvider',
        'Illuminate\Remote\RemoteServiceProvider',
        'Illuminate\Auth\Reminders\ReminderServiceProvider',
        'Illuminate\Database\SeedServiceProvider',
        'Illuminate\Session\SessionServiceProvider',
        'Illuminate\Translation\TranslationServiceProvider',
        'Illuminate\Validation\ValidationServiceProvider',
        'Illuminate\View\ViewServiceProvider',
        'Illuminate\Workbench\WorkbenchServiceProvider',
        'Sys\Subsys\services\BarServiceProvider',
    ),

最後に、追加したディレクトリをcomposerに認識させ、オートロードできるようにします。

laravel/composer.jsonに下記のpsr-0の項目を追加します(classmapはLaravelインストール時のデフォルトの設定です)。


    "autoload": {
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php"
        ],
        "psr-0": {
            "Sys": "app/"
        }
    },

修正が終わったら


$ composer dump-autoload

を実行します。


初期設定は多少面倒ではありますが、これでサブディレクトリ内で幾つものLaravelのアプリを動かすことができます。

色々な設定をしていますが、app.php内のサービスプロバイダの中からサブシステム用のサービスプロバイダ(BarServiceProvider.php)が呼び出され(呼び出す際にはcomposerによりオートロード)、サービスプロバイダからルーティングファイルやコントローラやビューファイルの場所をLaravelに認識させているといった流れです。

ここで書いたのは例ですのでうまくサービスプロバイダの中身を書き換えればディレクトリ構成はもっと自由に定義できたりします。


新しいサブシステムを追加したい場合は、


・ Sysディレクトリ以下にサブシステム用ディレクトリを新たに作る

・ サービスプロバイダファイルを作成する

・ laravel/app/config/app.phpに追加したサービスプロバイダを追加する


という対応だけでどんどん増やしていくことができます。