Render Blade from string instead of File

淺唱寂寞╮ 提交于 2019-12-31 17:11:48

问题


How can I render an string which contains blade syntax?

View::make('directory.file-name')->with('var', $var);  // Usual usage

View::render('{{$var}}')->with('var', $var); // Like this for Example

I use wrote an script that produces blade syntax and I want to give it's output directly to blade engine if possible.

Thanks


回答1:


Hope this helps,

https://github.com/TerrePorter/StringBladeCompiler

This is a fork of the next link that removes the db model requirement and replaces it with a array that requires three required keys ('template', 'cache_key', 'updated_at') instead of the full Eloquent model.

https://github.com/Flynsarmy/laravel-db-blade-compiler

This uses a Eloquent model to get the template.




回答2:


I don't recommend to use 'Blade::compileString' as it won't fully render PHP as View does.

This is a working version of my actual Blade string renderer. You may use it for database content or any string you want to render as you would with a .blade.php file. Tested with Laravel 4. Fully commented and explained.

Do not forget to create the 'cache' folder inside views

This function generates the fileview

public function generateViewFile($html, $url, $updated_at)
{
    // Get the Laravel Views path
    $path = \Config::get('view.paths.0');

    // Here we use the date for unique filename - This is the filename for the View
    $viewfilename = $url."-".hash('sha1', $updated_at);

    // Full path with filename
    $fullfilename = $path."/cache/".$viewfilename.".blade.php";

    // Write the string into a file
    if (!file_exists($fullfilename))
    {
        file_put_contents($fullfilename, $html);
    }

    // Return the view filename - This could be directly used in View::make
    return $viewfilename;
}

This is the ContentController route renderer

public function getIndex($uri = false)
{
    // In my real ContentController I get the page from the DB here
    //
    // $page = Page::findByUrl($uri);
    // $content = $page->content;
    // $updated_at = $page->updated_at;
    // $url = $page->url;

    $content = '<h1>This is the page to render</h1>';
    $updated_at = '2015-07-15 02:40:55';
    $url = '/blog/new-article';

    // Will write the file when needed and return the view filename
    $filename = $this->generateViewFile($content, $url, $updated_at);

    // Fully render and output the content
    return View::make('cache/'.$filename);
}

Handler at the end of the routes.php. Even if this is not required, this is to present a fully testeable solution.

Route::get('{all}', 'ContentController@getIndex')->where('all', '.*');



回答3:


I just made it for Laravel 4.2 as Linux-only version (which uses shm to create temporary files). It should work in another OS but through usual temporary files (a bit slower).

<?php

class FilesDeletionQueue {

    protected $files = [];

    public function add($filename) {
        $this->files[] = $filename;
    }

    public function flush() {
        $result = true;
        foreach ($this->files as $filename) {
            if (@unlink($filename) === false) {
                $result = false;
            }
        }
        return $result;
    }

}

class Helpers {

    static public function viewFromStr($tplName, $pageContent, array $data) {
        global $app;

        // Try to create temporary blade template file in shm memory,
        // if fails, create as usual temporary file.
        $tempname = tempnam('/run/shm/', 'laravel_blade');
        if (@file_put_contents($tempname, $pageContent) === false) {
            $tempname = tempnam(storage_path(), 'laravel_blade');
            if (@file_put_contents($tempname, $pageContent) === false) {
                throw new \Exception("Cannot create {$tempname} in " . __METHOD__);
            }
        }

        // Create template from shm memory file.
        $resolver = $app['view.engine.resolver'];
        $finder = $app['view.finder'];
        $env = new \Illuminate\View\Factory($resolver, $finder, $app['events']);
        $env->setContainer($app);
        $pageView = new \Illuminate\View\View(
            $env,
            $env->getEngineResolver()->resolve('blade'),
            $tplName,
            $tempname,
            $data
        );
        $env->callCreator($pageView);

        try {
            $fdq = App::make('files_deletion_queue');
        } catch (\Exception $e) {
            App::singleton('files_deletion_queue', function() {
                return new FilesDeletionQueue();
            });
            $fdq = App::make('files_deletion_queue');
            App::shutdown(function() {
                App::make('files_deletion_queue')->flush();
            });
        }
        // Add tempname to list of files to be deleted when application ends.
        $fdq->add($tempname);

        return $pageView;
    }

}

Then you can use it like this:

    $pageView = Helpers::viewFromStr('content', $pageContent, $this->data);
    $this->layout->with('content', $pageView)
        ->with('menus', $this->menus )
        ->with('page',$this->data);

instead of:

    /*
    $this->layout->nest('content',"pages.template.{$row->filename}",$this->data)
        ->with('menus', $this->menus )
        ->with('page',$this->data);
     * 
     */

It's really sad that recommended methods cannot load blade files from arbitrary OS pathes and there's no ready out of box support for compiling from RAM (I heard it's much easier for twig).



来源:https://stackoverflow.com/questions/21556981/render-blade-from-string-instead-of-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!