LoginSignup
20
29

More than 5 years have passed since last update.

LaravelでViewCreatorを使ってPC/SPのビューを切り替える

Last updated at Posted at 2017-08-25

概要

レスポンシブ対応できない状況があるが、同じURLでPC/SPのビューを切り替えたいといった場合の対応方法をメモしておきます。

環境

Laravel 5.4
※ 5.3以下では動作確認していないのでエラーが出る場合は適時修正が必要かも?

やり方の検討

  1. 各ビューを呼び出す部分で調整するような仕組みを作る
  2. ミドルウェアでビューの検索もとのパスを切り替える
  3. 各ビュー作成時に対応する

1. 各ビューを呼び出す部分で調整するような仕組みを作る

やり方を変えたい場合に、呼び出し方法自体が変わった時には
全てのコントロールのViewの呼び出し箇所の修正が必要になりそうなので却下。

2. ミドルウェアでビューの検索対象フォルダのパスを切り替える

viewsフォルダが一番上の階層からきっちり別れる。
明確にPS/SPのビューが一番上の階層から別れていて見やすい
フォルダのパスは複数定義でき、優先順位の設定が可能なので、
スマホになければPCと行ったようにスマホのテンプレートが無くてもエラーにならない。
ただし、フォルダが完全に別なのでSPのビューを作り忘れが発生しやすい。

3. 各ビュー作成時に対応する

各ビューを作成時(includeなどのビューも含む)に実行されるので
実行回数が多くなることが気になる

ただし、以下のような細かな調整ができそう。

・フォルダごと階層を分けず、ファイル名で分ける (例: pc -> index.blade.php, sp -> index_sp.blade.php)
・レスポンシブ対応ページの混在(スマホのビューを作らない場合、PCが読み込む)
・スマホのビュー作成を強制させるよう500番エラーにすることも可能
・PCのみのページを作る場合は、スマホは404 not foundにすることも可能

以上のことから③のやり方でやってみる。

構築方法

Laravelのビューには、composerとcreatorという機能があるようです。

実行タイミングが違うようですね。

  • creator: viewインスタンスが作成されるとき
  • composer: viewインスタンスからviewがコンパイル、結合されて文字列に変換されるとき

ビュー自体を切り替えるのでcreatorの方が良さそうです。

ということで、creatorで作ります。

エージェントの判定

スマホかどうかの判定が必要なので、下記ライブラリを導入する。

$ composer require jenssegers/agent

Laravel 5.4のため、下記の設置ではproviderの方がエラーとなった。
※ 原因 : share()メソッドが5.4ではなくなっているみたい・・・

config/app.php
    'providers' => [
        'Jenssegers\Agent\AgentServiceProvider', // <= 追記
    ],
    'aliases' => [
        'Agent' => 'Jenssegers\Agent\Facades\Agent',  // <= 追記
    ],

そのため、providerについてはこちらで上書きする。

app/Providers/AgentServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider,
    Jenssegers\Agent\Agent;

class AgentServiceProvider extends ServiceProvider
{
    /**
     * プロバイダのローディングを遅延させるかどうか
     *
     * @var bool
     */
    protected $defer = false;

    /**
     * 全アプリケーションサービスの初期起動処理
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * コンテナへの結合登録
     *
     * @return  void
     */
    public function register()
    {
        $this->app->singleton('agent', function ($app) {
            return new Agent($app['request']->server->all());
        });
    }
}

動作確認

app/Http/Controllers/TopController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Agent;

class TopController extends Controller
{
    /**
     * TOPページ
     *
     * URI : GET /
     *
     * @access  public
     * @return  string
     */
    public function index()
    {
        // サービスプロバイダ経由
        $agent = app('agent');
        var_dump($agent->isMobile());

        // ファサード経由
        var_dump(Agent::isMobile());
    }
}

ViewCreator作成

「app/Http/ViewCreators/」フォルダを作って下記クラスを配置する。

app/Http/ViewCreators/ViewSwitchCreator.php
<?php

namespace App\Http\ViewCreators;

use Illuminate\View\View,
    Illuminate\Support\Facades\View as V,
    Illuminate\View\ViewName,
    Illuminate\View\FileViewFinder,
    Agent;

/**
 * スマホのビューに自動で切り替える
 *
 * @package App\Http\ViewCreators
 */
class ViewSwitchCreator
{
    /**
     * ビュー差し替え対象外とするフォルダ
     *
     * @var array
     */
    private $excluded_folder = ['layouts', 'shared'];

    /**
     * ビュー名の接尾語
     *
     * @var string
     */
    private $view_name_suffix = '_sp';

    /**
     * 新しいプロフィールコンポーザの生成
     */
    public function __construct()
    {
        //
    }

    /**
     * データをビューと結合
     *
     * @param  View  $view
     * @return void
     */
    public function create(View $view)
    {
        // スマホではない場合はスキップ
        if (Agent::isMobile() !== true) {
            return;
        }

        // スマホ向けのビューの場合はスキップ
        $name = $view->getName();
        if ($name && preg_match('|'.$this->view_name_suffix.'$|', $name) !== 0) {
            return;
        }

        // 除外フォルダの場合はスキップ
        list($dir) = explode('.', $name);
        if (in_array($dir, $this->excluded_folder)) {
            return;
        }

        // ビューを変更する
        $name = $name.$this->view_name_suffix;

        // ビューの存在チェック
        // ※ レスポンシブ対応ページも作れるように500エラーにはしない
        if (v::exists($name)) {
            $finder = v::getFinder();
            $view->setPath(
                $finder->find(
                    ViewName::normalize($name)
                )
            );
        }
    }
}

ViewCreator登録

サービスプロバイダを使ってViewCreatorを全てのビューに適用されるよう登録する。

app/Providers/ViewCreatorServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\View,
    Illuminate\Support\ServiceProvider,
    App\Http\ViewCreators as V;

class ViewCreatorServiceProvider extends ServiceProvider
{
    /**
     * 全アプリケーションサービスの初期起動処理
     *
     * @return void
     */
    public function boot()
    {
        View::creator('*', V\ViewSwitchCreator::class);
    }

    /**
     * コンテナ結合の登録
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

app.phpにプロバイダを登録する。

config/app.php
    'providers' => [
        App\Providers\ViewCreatorServiceProvider::class, // <= 追記
    ],

ビューファイル作成

resources/views/フォルダ配下にファイルをそれぞれVIEWファイルを作成する。

┗ resources
   ┣ assets
   ┣ lang
   ┗ views
      ┣ errors
      ┣ layouts                             // このフォルダは差し替え対象外 (レイアウト)
      ┃  ┣ app.blade.php
      ┃  ┗ app_sp.blade.php
      ┣ shared                               // このフォルダは差し替え対象外 (各共有パーツ)
      ┃  ┣ header.blade.php
      ┃  ┣ header_sp.blade.php
      ┃  ┣ footer.blade.php
      ┃  ┗ footer_sp.blade.php
      ┗ top
         ┣ index.blade.php
         ┗ index_sp.blade.php

動作確認してみる。

app/Http/Controllers/TopController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Agent;

class TopController extends Controller
{
    /**
     * TOPページ
     *
     * URI : GET /
     *
     * @access  public
     * @return  string
     */
    public function index()
    {
        return view('top.index');
    }
}

※ スマホ向けのビューを作らなければ、自動的にPC向けのビューが表示される (レスポンシブ対応ページのため)

以上です。

参考サイト

20
29
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
20
29