テンプレートエンジンのBladeをFuelPHPで使う方法

こんにちは、コバヤシです。

弊社が採用しているPHPフレームワークはLaravelです。とても多機能で扱いやすいので手放せない存在となっていますが、 クライアントが用意した環境がLaravelのインストール要件(PHP7.2以上)を満たしておらず利用できない時もあります。 そんな時は以前使用していたフレームワーク、FuelPHPの出番となります。FuelPHPは5.4以上で動くので古めの環境でも大丈夫です。

そう、大丈夫なのですが、、、Laravelに慣れてしまったのでなんとなく扱いにくい。。
Laravelだったら、こうなのに。。とう思うことが多々。
あーFuelPHPでLaravelを使いたい!(ちょっと何言ってるか分からない)

と、言うわけでテンプレートエンジンくらいはBladeを使えないか?と思いチャレンジしてみることにしました。

Bladeとは

BladeはLaravelで使用されているテンプレートエンジンです。公式では以下のように書かれています。

BladeはシンプルながらパワフルなLaravelのテンプレートエンジンです。他の人気のあるPHPテンプレートエンジンとは異なり、ビューの中にPHPを直接記述することを許しています。全BladeビューはPHPへコンパイルされ、変更があるまでキャッシュされます。

readouble.com

まずはComposerでインストール

いくつかBladeのライブラリはあるのですが、今回は EFTEC / BladeOne を使用したいと思います。

github.com

composer require eftec/bladeone

composerからインストールします。

parserを有効にする

fuel/app/config/config.php

<?php

'always_load' => array(
    'packages' => array(
        'orm',
        'parser' // 追加
    ),
)

Blade用の設定を追加する

fuel/app/config/parser.php

<?php

    'extensions' => array(
        'php'      => 'View',
        'twig'     => 'View_Twig',
        'mthaml'   =>  array('class' => 'View_HamlTwig', 'extension' => 'haml'),
        'mustache' => 'View_Mustache',
        'md'       => 'View_Markdown',
        'dwoo'     => array('class' => 'View_Dwoo', 'extension' => 'tpl'),
        'jade'     => 'View_Jade',
        'haml'     => 'View_Haml',
        'smarty'   => 'View_Smarty',
        'phptal'   => 'View_Phptal',
        'lex'      => 'View_Lex',
        'blade.php' => 'View_Blade', // 追加
    ),

Blade用のParserを作成する

fuel/app/classes/parser/blade.php

<?php
  
namespace Parser;
  
Use eftec\bladeone\BladeOne;
  
class View_Blade extends View
{
    protected static $_parser;
  
    /**
     * 出力
     * @param bool $file_override
     * @return string
     * @throws \Exception
     */
    protected function process_file($file_override = false)
    {
        $file = $file_override ?: $this->file_name;
        $path_info = pathinfo($file);
        $view = str_replace('/','.', str_replace(APPPATH.'views', '', rtrim($path_info['dirname'], '/')).'/'.str_replace('.blade.php', '', $path_info['basename']));

        try
        {
            $parser = static::parser();
            $result = $parser->run($view, $this->get_data());
        }
        catch (\Exception $e)
        {
            ob_end_clean();
            throw $e;
        }

        return $result;
    }
  
    public $extension = 'blade.php';
  
    /**
    * Parserを返却
    *
    * @return  BladeOne
    */
    public static function parser()
    {

        if ( ! empty(static::$_parser))
        {
            return static::$_parser;
        }

        static::$_parser = new BladeOne(APPPATH.'views', APPPATH.'cache'.DS.'blade',BladeOne::MODE_AUTO);
        
        return static::$_parser;
    }
}

$this->file_nameにはテンプレートファイルへのフルパスが入ってきますが、parserに渡すのはviewsファイル以下のパスなので str_replaceで削除します。又、拡張子(.blade.php)も不要なので削除。さらに「/(スラッシュ)」を「.(ドット)」に変換します。

それから、このBladeのParserが読み込まれるように、Bootstrapへ記述します。

fuel/app/bootstrap.php

<?php
\Autoloader::add_classes(array(
    'Parser\\View_Blade'  => APPPATH.'classes/parser/blade.php', // 追加
));

これでBladeを使用する準備は整いました。

使用してみる

fuel/app/classes/controller/index.php

<?php
class Controller_Index extends Controller
{

    public function action_index()
    { 
        return Response::forge(\View_Blade::forge('index', ['hoge' => 'ほげほげ']));
    }
}

viewはView_Bladeを使用します。
後はLaravelと同じようにbladeが使えます。

fuel/app/views/app.blade.php

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>テスト</title>
</head>
<body>

@yield('content')

</body>
</html>

fuel/app/views/index.blade.php

@extends('app')
  
@section('content')
  
{{ $hoge }}
  
@endsection

エスケープ処理を変更する

エスケープ処理はviewのforgeで第3引数をfalseにすることで無効にできますが、

<?php
\View_Blade::forge('index', ['hoge' => 'ほげほげ']);

これをLaravelと同じように{!! !!}で処理させるようにします。

fuel/app/config/parser.php

<?php
   // 以下を追加します
    'Parser\View_Blade' => array(
        'auto_encode' => false,
    )

まとめ

比較的簡単にFuelPHPでBladeで使えるようになりました。
ただBladeOneはPHP5.6以上が必要です。FuelPHPが使える5.4以上ではないので注意が必要です。

あれ?今度の案件はPHP5.4だった。。