2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Laravel5.5】ビューディレクトリを分割するよ

Posted at

まえがき

マルチログインで作っている際、コントローラを別々に作っていると、
合わせてビューも別ディレクトリに分けて作りたいな、と思った次第。
とりあえず出来たので残しておきます。

前提

ツールのバージョン

  • XAMPP v3.2.4
    • PHP 7.3.8
      • Laravel 5.5.45

すでにやってるルーティング

routes/web.php
<?php
// user
Route::prefix('user')->name('user.')->group(function () {
    // ユーザー画面
    Route::get('/', 'User\TopController@index')->name('top');
});

// admin
Route::prefix('admin')->name('admin.')->group(function () {
    // 管理者画面
    Route::get('/', 'Admin\TopController@index')->name('top');
});

URLとルーティング名にプレフィックスを使ってます。
なので、ユーザー側のトップのURLは http://localhost/user/
管理側のトップURLは http://localhost/admin/になります。
同様に、ユーザー側トップのルーティング名は user.top、管理側は admin.topとなります。

コントローラはマルチログインごとにディレクトリをきっているので、
コントローラアクションの呼び出しにも含めています。

ただ、このまま素直に作ってしまうと、ビューが同じテンプレート名になってしまうので、
それが嫌だった、というわけです。
まぁ、トップくらいなら top/user.blade.php とかで分ければいいだけだけど。。

設定

呼び出しやすいように設定ファイルにパスを追加しておきます。

config/view.php
<?php
return [
    /**
     * 各権限ごとのビューテンプレートパス
     */
    'user_path' => resource_path('views/user'),
    'admin_path' => resource_path('views/admin'),
];

で、以下のミドルウェアを用意。

app/Http/Middleware/ViewSwitchMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\View\FileViewFinder;

/**
 * 権限により参照するビューディレクトリを変更する
 */
class ViewSwitchMiddleware
{
    /**
     * ビュー
     * @var Illuminate\Contracts\View\Factory
     */
    protected $view;

    public function __construct(ViewFactory $view)
    {
        $this->view = $view;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     * @see https://qiita.com/sogawa@github/items/644710df8d58d54f2665
     */
    public function handle($request, Closure $next)
    {
        $add_path = $this->getViewPath($request);
        if (!empty($add_path)) {
            $this->resettingView($add_path);
        }

        return $next($request);
    }

    /**
     * ビューディレクトリパスを取得
     * ルーティングのプレフィックスにより見分ける
     *
     * @access private
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    private function getViewPath($request)
    {
        // プレフィックスで分岐
        $uri_prefix = $request->route()->getPrefix();
        if ($uri_prefix == '/admin') {
            // 管理
            return \Config::get('view.admin_path');
        } else {
            // ユーザー
            return \Config::get('view.user_path');
        }

        // // 権限で分岐
        // $middlewares = $request->route()->middleware();
        // // ルーティング名で分岐
        // $route_name = $request->route()->getName();
    }

    /**
     * ビューの再設定
     *
     * @access private
     * @param  string  $add_path
     * @return void
     */
    private function resettingView($add_path)
    {
        // 権限ごとのディレクトリを先に検索させるため、パス情報の先頭へ
        $paths = \Config::get('view.paths');
        array_unshift($paths, $add_path);

        // パスを変更するためFileViewFinderを生成
        // ただし、そのまま新しいFileViewFinderをセットするとすでにセットされたhint情報が消えてしまうので
        // すでに設定済みのFileViewFinderのhintをコピーしてからセットする
        // (ページャーや通知でhint情報をいれている)
        $finder = new FileViewFinder(app()['files'], $paths);
        $old_finder = $this->view->getFinder();
        foreach ($old_finder->getHints() as $namespace => $hint) {
            $finder->addNamespace($namespace, $hint);
        }

        $this->view->setFinder($finder);
    }
}

ちょうどよくルーティングでプレフィックスを使っているので、
それでもってテンプレートのパス分岐も判定します。

パスが取得できたら、テンプレートの設置先パスの先頭に追加。
viewのFinderを差し替えるわけだけど、
この際にそのまま新しいFinderを入れてしまうと、
元のFinderに入っていたhintがなくなりそもそも表示でコケることになるので、
ここだけ新しいFinderに入れ直してから再セットします。

その後、このMiddlewareを読み込ませて設定終わり。

app/Http/Kernel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    //
    // 省略
    //  

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\ViewChangeMiddleware::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    //
    // 省略
    //  
}

これにより、ビューはそれぞれで分割できるようになります。

+---resources
    \---views
        +---admin
        |   \---top
        \---user
            \---top

こんな感じ。

あとがき

やってる途中で、たんにディレクトリ分けて、ビューを呼び出すパス変えてやればいいだけだな、とは思ってた(´・ω・`)
まぁ、もう作ってたところ書き換えて回るのもメンドいし、いいかな、と。

参考

ミドルウェアを使ってビューの探索パスを変更する

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?