有没有办法从字符串编译刀片模板?

时间:2013-06-03 06:51:08

标签: php laravel laravel-blade

如何从字符串而不是视图文件编译刀片模板,如下面的代码:

<?php
$string = '<h2>{{ $name }}</h2>';
echo Blade::compile($string, array('name' => 'John Doe')); 
?>

http://paste.laravel.com/ujL

5 个答案:

答案 0 :(得分:16)

我通过扩展BladeCompiler找到了解决方案。

<?php namespace Laravel\Enhanced;

use Illuminate\View\Compilers\BladeCompiler as LaravelBladeCompiler;

class BladeCompiler extends LaravelBladeCompiler {

    /**
     * Compile blade template with passing arguments.
     *
     * @param string $value HTML-code including blade
     * @param array $args Array of values used in blade
     * @return string
     */
    public function compileWiths($value, array $args = array())
    {
        $generated = parent::compileString($value);

        ob_start() and extract($args, EXTR_SKIP);

        // We'll include the view contents for parsing within a catcher
        // so we can avoid any WSOD errors. If an exception occurs we
        // will throw it out to the exception handler.
        try
        {
            eval('?>'.$generated);
        }

        // If we caught an exception, we'll silently flush the output
        // buffer so that no partially rendered views get thrown out
        // to the client and confuse the user with junk.
        catch (\Exception $e)
        {
            ob_get_clean(); throw $e;
        }

        $content = ob_get_clean();

        return $content;
    }

}

答案 1 :(得分:4)

我没有以这种方式使用刀片,但我认为compile方法只接受视图作为参数。

也许你正在寻找:

Blade::compileString()

答案 2 :(得分:2)

我偶然发现了相同的要求!对我来说,我必须获取存储在数据库中的刀片模板并渲染它以发送电子邮件通知。

我在laravel 5.8中通过扩展\Illuminate\View\View来做到这一点。因此,基本上,我创建了下面的类并将其命名为StringBlade(我找不到更好的名称atm:/)

<?php

namespace App\Central\Libraries\Blade;

use Illuminate\Filesystem\Filesystem;

class StringBlade implements StringBladeContract
{
    /**
     * @var Filesystem
    */
    protected $file;

    /**
     * @var \Illuminate\View\View|\Illuminate\Contracts\View\Factory
    */
    protected $viewer;

    /**
     * StringBlade constructor.
     *
     * @param Filesystem $file
     */
    public function __construct(Filesystem $file)
    {
        $this->file = $file;
        $this->viewer = view();
    }

    /**
     * Get Blade File path.
     *
     * @param $bladeString
     * @return bool|string
     */
    protected function getBlade($bladeString)
    {
        $bladePath = $this->generateBladePath();

        $content = \Blade::compileString($bladeString);

        return $this->file->put($bladePath, $content)
            ? $bladePath
            : false;
    }

    /**
     * Get the rendered HTML.
     *
     * @param $bladeString
     * @param array $data
     * @return bool|string
     */
    public function render($bladeString, $data = [])
    {
        // Put the php version of blade String to *.php temp file & returns the temp file path
        $bladePath = $this->getBlade($bladeString);

        if (!$bladePath) {
            return false;
        }

        // Render the php temp file & return the HTML content
        $content = $this->viewer->file($bladePath, $data)->render();

        // Delete the php temp file.
        $this->file->delete($bladePath);

        return $content;
    }

    /**
     * Generate a blade file path.
     *
     * @return string
     */
    protected function generateBladePath()
    {
        $cachePath = rtrim(config('cache.stores.file.path'), '/');
        $tempFileName = sha1('string-blade' . microtime());
        $directory = "{$cachePath}/string-blades";

        if (!is_dir($directory)) {
            mkdir($directory, 0777);
        }

        return "{$directory}/{$tempFileName}.php";
    }
}

从上面已经可以看到,下面是执行的步骤:

  1. 首先使用\Blade::compileString($bladeString)将刀片字符串转换为等价的php。
  2. 现在我们必须将其存储到 physical 文件中。对于此存储,使用框架缓存目录-storage/framework/cache/data/string-blades/
  3. 现在,我们可以要求\Illuminate\View\Factory本机方法'file()'编译并呈现此文件。
  4. 立即删除临时文件(对于我而言,我不需要保留php等效文件,也许对您也一样)

最后,我在作曲家自动加载的文件中创建了一个 facade ,以方便使用,如下所示:

<?php

if (! function_exists('string_blade')) {

    /**
     * Get StringBlade Instance or returns the HTML after rendering the blade string with the given data.
     *
     * @param string $html
     * @param array $data
     * @return StringBladeContract|bool|string
     */
    function string_blade(string $html, $data = [])
    {
        return !empty($html)
            ? app(StringBladeContract::class)->render($html, $data)
            : app(StringBladeContract::class);
    }
}

现在我可以从下面的任何地方调用它:

<?php

$html = string_blade('<span>My Name is {{ $name }}</span>', ['name' => 'Nikhil']);

// Outputs HTML
// <span>My Name is Nikhil</span>

希望这可以帮助某人或至少可以激发某人以更好的方式进行重写。

干杯!

答案 3 :(得分:2)

我知道它的线程很老,但是今天的要求也一样。

以下是我在Laravel 5.7上解决此问题的方式(但此方法适用于大于版本5的任何laravel版本),我使用了从该线程和其他几个线程获得的知识来进行此工作(将保留指向最后的所有线程(如果这也有助于投票)

我将此添加到了helper.php中(我曾使用this technique将helper添加到我的项目中,但是您也可以直接使用此功能)

if (! function_exists('inline_view')) {
    /**
     * Get the evaluated view contents for the given blade string.
     *
     * @param  string  $view
     * @param  array   $data
     * @param  array   $mergeData
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
     */
    function inline_view($view = null, $data = [], $mergeData = [])
    {
        /* Create a file with name as hash of the passed string */
        $filename = hash('sha1', $view);

        /* Putting it in storage/framework/views so that these files get cleared on `php artisan view:clear*/
        $file_location = storage_path('framework/views/');
        $filepath = storage_path('framework/views/'.$filename.'.blade.php');

        /* Create file only if it doesn't exist */
        if (!file_exists($filepath)) {
            file_put_contents($filepath, $view);
        }
        
        /* Add storage/framework/views as a location from where view files can be picked, used in make function below */
        view()->addLocation($file_location);

        /* call the usual view helper to render the blade file created above */
        return view($filename, $data, $mergeData);
    }
} 

用法与laravel的view()帮助器完全相同,只是现在第一个参数是刀片字符串

            $view_string = '@if(strlen($name_html)>6)
                                <strong>{{ $name_html }}</strong>
                            @else 
                                {{$name_html}} 
                            @endif';
            return inline_view($view_string)->with('name_html', $user->name);
            return inline_view($view_string, ['name_html' => $user->name]);

参考:

  1. https://stackoverflow.com/a/31435824/4249775
  2. https://stackoverflow.com/a/33594452/4249775

答案 4 :(得分:1)

这是一个老问题。但我找到了一个让工作更容易的包。

Laravel Blade String Compiler从字符串值中呈现刀片模板。查看有关如何安装软件包的文档。

以下是一个例子:

$template = '<h1>{{ $name }}</h1>';  // string blade template

return view (['template' => $template], ['name' => 'John Doe']);

注意:此软件包与Laravel 5.7不兼容