Simon Simon - 1 month ago 16
PHP Question

Laravel Blade Directives not executing when template loaded from string

EDIT: The code snippet below, where

view
takes an array
['template' => 'my template']
as the first argument is a feature of
wpb/string-blade-compiler
which is overriding the native laravel functionality.

I have a directive registered in
AppServiceProvider::boot
:

public function boot()
{
Blade::directive('hello', function($expression) {
return "<?php echo 'Hello world'; ?>";
});
}


It works perfectly when I use file based templates saved as
resources/views/something.blade.php
and used
return view('something', $data)
in my
Controller::action
.

However when I try:

try {
return view(['template' => $template], $data)->render();
} catch(\ErrorException $ex) {
preg_match('/Undefined variable: (.+?)\s/', $ex->getMessage(), $matches);
if ($matches) {
return sprintf('Template: variable {{ $%s }} is invalid', $matches[1]);
}
return sprintf('%s: %s', $attribute, $ex->getMessage());
}


And try and use templates from a string, the directive isn't loaded. No errors, no nothing.

Does anyone with an intimate knowledge of laraval know the difference with these two contexts? I would have thought they'd yield the same result but do not. I'm struggling to understand the laravel architecture to unravel this one. Thanks.

composer.json:

"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"laravelcollective/html": "^5.2",
"maatwebsite/excel": "^2.1",
"sofa/eloquence": "^5.2",
"wpb/string-blade-compiler": "^3.2",
"doctrine/dbal": "^2.5",
"davejamesmiller/laravel-breadcrumbs": "^3.0"
}


PHP 5.6

Answer

So, I did a little testing on my own server and came up with a solution:

My condensed code in a singe route:

Route::get('/test', function () {

    $template = Blade::compileString('@hello(derek) !');

    ob_start();

    try {

        eval('?>' . $template);

    } catch (\Exception $e) {

        ob_get_clean(); throw $e;

    }

    $content = ob_get_clean();

    return $content;

});

And the directive, if you care to see it:

public function boot()
    {
        //
        Blade::directive('hello', function($d) {

            return "<?php echo \"Hello {$d}\"; ?>";
        });
    }

There is like little to no documentation on this, so debugging could be a hassle, but I do know if you would like to pass in more variables to the string, it would look like this:

Route::get('/test2', function () {

    $args = ['name' => 'derek'];

    $template = Blade::compileString('@hello($name) !');

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

    try {

        eval('?>' . $template);

    } catch (\Exception $e) {

        ob_get_clean(); throw $e;

    }

    $content = ob_get_clean();

    return $content;

});

Finally, a simple function you can place in your controller:

// way to call:

$this->strView('@hello($name)', ['name' => 'Tom Riddle']);

public function strView($view, $args) {
    $template = Blade::compileString($view);

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

    try {

        eval('?>' . $template);

    } catch (\Exception $e) {

        ob_get_clean(); throw $e;

    }

    $content = ob_get_clean();

    return $content;
}

Let me know if you have any questions!

Comments