43
48

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.

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

Last updated at Posted at 2015-03-29

Laravel5のインストール直後に設置されているビューを見たところ、もともとレスポンシブな感じではあるけど、PCとモバイルで表示要素が大きく違う画面はビューファイルが同じだとツライわ−ってことがあると思うんです。

なので、ミドルウェアを使ってビューファイルの探索パスを変更する方法を調べてみました。

パッケージのインストール

ググると、なんだか良さげなパッケージがあったのでこれを使いたいと思います。
https://github.com/jenssegers/Laravel-Agent

READMEに従ってcomposerでインストールした後、config/app.phpの'providers'と'aliases'に追記します。

$ composer require jenssegers/agent
config/app.php
	'providers' => [
		....
    
		'Jenssegers\Agent\AgentServiceProvider', // <= 追記
	],

	'aliases' => [
		....
		
		'Agent'     => 'Jenssegers\Agent\Facades\Agent',  // <= 追記
	],

ミドルウェアの作成

まずは config/view.phpにモバイル向けのビューディレクトリを追記しておきます。

config/view.php
    ....
    
    'compiled' => realpath(storage_path().'/framework/views'),
    'mobile_path' => realpath(base_path('resources/mobile_views')), // <= 追記

続いて、適当なミドルウェアを作成します。

$ php artisan make:middleware ViewSwitchMiddleware
app/Http/Middleware/ViewSwitchMiddleware.php
<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Routing\Middleware;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\View\FileViewFinder;
use Agent;

class ViewSwitchMiddleware implements Middleware {

	/**
	 * The view factory implementation.
	 *
	 * @var \Illuminate\Contracts\View\Factory
	 */
	protected $view;

	/**
	 * Create a new instance.
	 *
	 * @param  \Illuminate\Contracts\View\Factory  $view
	 * @return void
	 */
	public function __construct(ViewFactory $view)
	{
		$this->view = $view;
	}

	/**
	 * Handle an incoming request.
	 *
	 * @param  \Illuminate\Http\Request  $request
	 * @param  \Closure  $next
	 * @return mixed
	 */
	public function handle($request, Closure $next)
	{
		$ua = $request->server->get('HTTP_USER_AGENT');

		if (Agent::isMobile($ua)) {
			$app = app();
			$paths = $app['config']['view.paths'];
			array_unshift($paths, $app['config']['view.mobile_path']);

			$this->view->setFinder(new FileViewFinder($app['files'], $paths));
		}

		return $next($request);
	}
}

Agent::isMobile() が true の場合にFinderインスタンスをすげ替えることで、resources/mobile_views/, resources/views/ の順にビューファイルを探してくれるようになりました。

※ FileViewFinderの実装を見てみると、addLocation()は有るのに prependLocation()は無いらしい。
$this->view->getFinder()->prependLocation($mobile_path); みたいに書ければ良かったんですけどね。

ビューファイルの用意

上記で指定した resources/mobile_views/以下に適当なビューファイルを作成します。

$ mkdir -p resources/mobile_views/

$ cat <<EOF > resources/mobile_views/welcome.blade.php
これはモバイル向け画面ですよ。
<div>使ってるファイル: {{ \$this->getCompiler()->getPath() }}</div>
EOF

ミドルウェアの登録

app/Http/Kernel.phpにグローバルミドルウェアとして登録します。

app/Http/Kernel.php
    protected $middleware = [
        ....
        
        'App\Http\Middleware\ViewSwitchMiddleware', // <= 追記
    ];

そしたらWEBブラウザの開発者ツールなどでユーザーエージェントを変更して確認します。

ユニットテストを書く

最後に、テストがないと同僚がプルリクエストを受け付けてくれないのでユニットテストを書きます。

tests/Http/Middleware/ViewSwitchMiddlewareTest.php
<?php
use App\Http\Middleware\ViewSwitchMiddleware;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\ServerBag;

class ViewSwitchMiddlewareTest extends TestCase {

	public function setUp()
	{
		parent::setUp();
		$this->view = app('view');
		$this->middleware = new ViewSwitchMiddleware($this->view);
		$this->request = new Request();
	}

	public function handleDataProvider()
	{
		return [
			[
			'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36',
			'resources/views'
			],
			[
			'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25',
			'resources/mobile_views'
			],
			[
			'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03S) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19',
			'resources/mobile_views'
			],
		];
	}

	/**
	 * @dataProvider handleDataProvider
	 */
	public function testHandle($ua, $expected)
	{
		$this->request->server = new ServerBag(['HTTP_USER_AGENT' => $ua]);
		$this->middleware->handle($this->request, function($request){});

		$paths = $this->view->getFinder()->getPaths();
		$this->assertEquals(realpath(base_path($expected)), reset($paths));
	}
}

phpunitを実行してグリーンになればOKです。

$ phpunit tests/Http/Middleware/ViewSwitchMiddlewareTest.php
43
48
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
43
48

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?