1

祝大家有美好的一天。

正如问题标题所说,我确实在 s3 中存储了带有 Laravel 标签的 HTML 模板代码,可以说:

<html>
<head>
    <title>{{ $landing->title }}</title>
</head>
<body>
@foreach($landing->products as $product)
    <p>{{ $product->title }}</p>
@endforeach
</body>
</html>

然后我想将其渲染为后处理的 html,并替换 Laravel 标签,就好像它是一个普通的刀片模板一样。

在我的控制器中,我确实有这个:

print_r( view('render', compact('template', 'landing'))->render() );

(我不想在其中显示浏览器,只需获取 html 代码)

render.blade.php我有:

{!! html_entity_decode($template->html()) !!}

但这将向我显示带有 Laravel 标签的代码,而无需正确替换。

这个有灯吗?任何帮助将不胜感激。

4

1 回答 1

1

我看到了这个问题的两种可能的解决方案。

  1. 自己编译刀片(不是最佳 IMO)

给定一个字符串,您可以创建一个帮助函数来为您编译刀片。(来源

helpers.php (或任何你想找到函数的地方)

function compile_blade($markup, $data = []) {
    $fs = new \Illuminate\Filesystem\Filesystem;
    $b = new \Illuminate\View\Compilers\BladeCompiler($fs, __DIR__);
    $src = $b->compileString($markup);

    $isPhp = false;
    if (substr( $src, 0, 5 ) === "<?php")
    {
        $isPhp = true;
        $src = substr($src, 5);
    }
    
    $tempFileName = tempnam("/tmp", "blade-compile");
    file_put_contents($tempFileName, $src);

    ob_start();

    extract($data);

    include $tempFileName;
    $out = ob_get_clean();
    if ($isPhp)
    {
        $out = '<?php'.$out;
    }
    
    return $out;
}

然后在您的控制器中,您将预处理 s3 刀片以便在您的 render.blade.php 文件中使用,例如:

    return view('render', [
        'template' => compile_blade($template, $landing),
        'landing' => $landing,
    ));

我认为这不是最佳解决方案,因为无论如何您最终都会创建文件。

  1. 为来自 s3 的刀片/html 创建一个新的命名空间。

首先,您需要在项目中创建一个文件夹,例如./storage/local/blade. 然后,您需要为该文件夹中的视图添加命名空间,如下所示:

AppServiceProvider.php

public function boot()
{
    ...

    view()->addNamespace('s3', storage_path('/local/views');
    ...
}

现在要处理从 s3(在您的控制器或其他地方)检索标记,您可以执行以下操作:

    // Lets say the file on s3 is markup.blade.php
    $contents = Storage::disk('s3')->get('path/to/markup.blade.php')
    Storage::disk('local')->put(storage_path('local/views/markup.blade.php'), $contents);

现在,如果您的 render.blade.php 仅用于在 s3 上呈现标记,您应该只使用新的命名空间视图。您可以在控制器中使用它,例如:

    return view('s3::markup', compact('landing'));

如果您想在其他刀片文件之一中使用 s3 标记,这会变得有点棘手。但可以通过扩展刀片来完成,如本文所述

Blade::extend(function($view, $compiler)
{
    $pattern = $compiler->createMatcher('includeNamespaced');

    $viewPath = realpath($compiler->getPath());
    $parts = explode(DIRECTORY_SEPARATOR, $viewPath);
    $viewsDirectoryIndex = array_search('views', $parts);
    $namespace = $parts[$viewsDirectoryIndex + 1];

    $php = '$1<?php ';
    $php .= 'if($__env->exists(\''.$namespace.'.\'.$2)){';
    $php .= 'echo $__env->make(\''.$namespace.'.\'.$2)->render();';
    $php .= '}';
    $php .= 'else {';
    $php .= 'echo $__env->make($2)->render();';
    $php .= '}';
    $php .= '?>';

    return preg_replace($pattern, $php, $view);
});

现在您可以在刀片文件中 @include 命名空间视图,例如:

    @includeNamespaced('s3/markup')

我更喜欢解决方案 2 的另一个原因是,如果您在从 s3 下载之前查看文件是否已存在于本地/视图中,您可以获得一些“缓存”效果。然后,您可以创建一个计划作业,删除存储/本地/视图中超过某个时间限制的文件。

于 2020-07-11T07:57:23.377 回答