Pass multiple parameters to a blade directive

by Caio Kawasaki   Last Updated November 09, 2018 01:26 AM

I'm trying to create a blade directive to highlight some words that will return from my search query.

This is my blade directive:

class AppServiceProvider extends ServiceProvider

{
    public function boot()
    {
        Blade::directive('highlight', function($expression, $string){

            $expressionValues = preg_split('/\s+/', $expression);

            foreach ($expressionValues as $value) {
                $string = str_replace($value, "<b>".$value."</b>", $string);
            }

            return "<?php echo {$string}; ?>";
        });
    }

    public function register()
    {
    }
}

And I call in blade like this:

@highlight('ho', 'house')

But, this erros is following me:

Missing argument 2 for App\Providers\AppServiceProvider::App\Providers\{closure}()

How to solve it?



Answers 4


I think you can only pass one parameter. It's not pretty but you could pass your parameters as an array like so:

@highlight(['expression' => 'ho', 'string' => 'house'])

So your directive could be

class AppServiceProvider extends ServiceProvider

{
    public function boot()
    {
        Blade::directive('highlight', function($array){

            $expressionValues = preg_split('/\s+/', $array['expression']);

            foreach ($expressionValues as $value) {
                $array['string'] = str_replace($value, "<b>".$value."</b>", $array['string']);
            }

            return "<?php echo {$array['string']}; ?>";
        });
    }

    public function register()
    {
    }
}

Found it here: https://laracasts.com/discuss/channels/laravel/how-to-do-this-blade-directive

Santiago Mendoza Ramirez
Santiago Mendoza Ramirez
December 06, 2016 21:07 PM

Blade::directive('highlight', function($arguments){

        list($arg1, $arg2) = explode(',',str_replace(['(',')',' ', "'"], '', $arguments));

        $expressionValues = preg_split('/\s+/', $arg1);

        $output = "";

        foreach ($expressionValues as $value) {
            $output .= str_replace($value, "<b>".$value."</b>", $arg2);
        }

        return "<?php echo \"{$output}\"; ?>";
    });
Filipe Cesar Paladino
Filipe Cesar Paladino
December 06, 2016 21:45 PM

Blade::directive('custom', function ($expression) {
    eval("\$params = [$expression];");
    list($param1, $param2, $param3) = $params;

    // Great coding stuff here
});

and in blade template:

@custom('param1', 'param2', 'param3')
Agung Darmanto
Agung Darmanto
April 17, 2018 13:02 PM

For associative arrays, eval() may be the easiest. But it's use is both adverted as dangerous, because it's like your opening a hole an needle for code execution. In same time eval() execute at runtime, well it store the code to be executed in database (caching [well it mean it cache compiled byte code]). That's an overhead, and it give the performance a hit. Here a nice paper claiming that [didn't read or get into the details]) https://link.springer.com/chapter/10.1007%2F978-981-10-3935-5_12.

Well here i may have got you!, there is no performance difference at server serving performance, because the view are cached, and generated only when you change them. The directive are translated to php code and that in another process, and they are cached. So for

Blade::directive('custom', function ($expression) {
    eval("\$myarray = [$expression];");

    // do something with $myarray
});

it's just ok. There is nothing to talk about for eval() and performance, (it's done and cached, and the generated php code is the one that will run over and over (just make sure the returned php code by the directive doesn't hold eval(), unless there is a reason). Using eval() directly (which will be used for different request over and over), hit performance. (I wanted to talk about eval(), i think those are useful info)

Remember if you decide to use eval. Never use it within the returned string!!!

Parsing is a more of a secure flow.

Another solution (which is easy) along to the proposed parsing solutions, is to use a json format to passe data to your directive, and just use json_decode. (it just came to me)

class AppServiceProvider extends ServiceProvider

{
    public function boot()
    {
        Blade::directive('highlight', function($json_expression){

            $myArray = json_decode($json_expression)

            // do something with the array
        });
    }

    public function register()
    {
    }
}

Here an example where i needed to do so: the goal is to automate this

@php
    $logo = !empty($logo) ? $logo : 'logo';
    $width = !empty($width) ? $width : 'logo';
    //...    // wait i will not always keep doing that ! h h
@endphp // imaging we do that for all different number of view components ...

and so i wrote this directive:

 public function boot()
    {
        Blade::directive('varSet', function ($expr) {
            $array = json_decode($expr);

            $p = '<?php ';
            foreach ($array as $key => $val) {
                $p += "\$$key = !empty(\$$key) ? \$$key : '$val'; ";
            }
            $p += '?>';

            return $p;
        });
    }

We use it like this:

@setVar('{
    "logo": "logo",
    "width": 78,
    "height": 22
}')// hi my cool directive. that's slick.
Mohamed Allal
Mohamed Allal
November 09, 2018 01:25 AM

Related Questions



How to calculated grade then pass to blade template

Updated September 19, 2018 08:26 AM


Using a foreach variable in a Laravel view

Updated December 16, 2017 11:26 AM