laravel 将多个参数传递给刀片指令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41003733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pass multiple parameters to a blade directive
提问by Caio Kawasaki
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?
如何解决?
回答by Agung Darmanto
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')
回答by Mohamed Allal
For associative arrays, eval()may be the easiest. But its use is adverted as dangerous, because it's like your opening a hole, a 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 additional overhead, so performance will take a hit. Here's a nice paper on the topic [didn't read or get into the details]) https://link.springer.com/chapter/10.1007%2F978-981-10-3935-5_12.
对于关联数组,eval()可能是最简单的。但它的使用被宣传为危险的,因为它就像你打开一个洞,一根针执行代码。同时eval() 在运行时执行,它将要执行的代码存储在数据库中(缓存 [这意味着它缓存编译的字节码])。这是额外的开销,因此性能会受到影响。这是关于该主题的一篇不错的论文 [没有阅读或详细介绍])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 views are cached, and generated only when you change them. Directives are translated to php code and in another process they are cached. (you can find the generated view in storage/framework/views)
好吧,我可能已经找到了你!,服务器服务性能没有性能差异,因为视图是缓存的,只有在您更改它们时才会生成。指令被翻译成 php 代码,并在另一个进程中被缓存。(您可以在storage/framework/views 中找到生成的视图)
Blade::directive('custom', function ($expression) {
eval("$myarray = [$expression];");
// do something with $myarray
return "<?php echo ..";
});
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) will impact performance. (I wanted to talk about eval(), I think those are useful info)
没关系。eval() 和性能没有什么可谈的(它已完成并缓存,生成的 php 代码将一遍又一遍地运行(只需确保指令返回的 php 代码不包含 eval() , 除非有原因。直接使用 eval() (会反复用于不同的请求)会影响性能。(我想谈谈 eval(),我认为这些是有用的信息)
as it is we can parse array form ["sometin" => "i should be sting", "" => "", ...].
因为我们可以解析数组形式 ["sometin" => "i should be sting", "" => "", ...]。
eval("$array = $expression;");
// then we can do what we want with $array
However we can't pass variables. ex: @directive(["s" => $var])
if we use eval, $varwill be undefined in the directive function scope. (don't forget that directive are just a way to generate tempalte beautifully, and turning the ugly (not really ugly) php code into such directive. In fact it's the inverse, we are turning the beautiful directive to the php code that will be executed at the end. And all you are doing here is generating, building, writing the expression that will form the final php pages or files.)
但是我们不能传递变量。例如: @directive(["s" => $var])
如果我们使用eval,$var将在指令函数范围内未定义。(不要忘记该指令只是一种漂亮地生成模板的方式,并将丑陋(不是真的丑)的 php 代码变成这样的指令。实际上它是相反的,我们正在将漂亮的指令转换为将要生成的 php 代码最后执行。您在这里所做的就是生成、构建、编写将形成最终 php 页面或文件的表达式。)
What you can do instead is to pass the variable in this way ["s" => "$var"] , so it will pass through eval. And then in your return statement, use it example:
您可以做的是以这种方式传递变量 ["s" => "$var"] ,因此它将通过 eval。然后在你的 return 语句中,使用它的例子:
return "<?php echo ".$array['s'].";?>";
when the template will be generated this will be <?php echo $var;?>
;
当模板生成时,这将是<?php echo $var;?>
;
Remember, if you decide to use eval, never use it within the returned string! or maybe you want to in some cases.
请记住,如果您决定使用 eval,切勿在返回的字符串中使用它!或者也许你想在某些情况下。
Another solution
另一种解决方案
(which is easy) along to the proposed parsing solutions, is to use a json formatto passe data to your directive, and just use json_decode. (it just came to me)
(这很容易)与建议的解析解决方案一起,是使用json 格式将数据传递给您的指令,只需使用json_decode。(它刚刚来到我身边)
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, true);
$p = '<?php ';
foreach ($array as $key => $val) {
if (is_string($val)) {
$p .= "$$key = isset($$key) && !empty($$key) ? $$key : '$val'; ";
} else {
$p .= "$$key = isset($$key) && !empty($$key) ? $$key : $val; ";
}
}
$p .= '?>';
return $p;
});
}
We use it like this:
我们像这样使用它:
@varSet({
"logo": "logo",
"width": 78,
"height": 22
})// hi my cool directive. that's slick.
Why this form work? it get passed as a string template like this
为什么这个表格有效?它作为这样的字符串模板传递
"""
{\n
"logo": "logo",\n
"width": 78,\n
"height": 22\n
}
"""
For using in template variable pass them as string like that "$var", same as what we did with eval.
对于在模板变量中使用,将它们作为像“$var”这样的字符串传递,与我们对 eval 所做的相同。
For parsing from ["" => "", ..] format may be eval() is the best choice. Remember that this is done at template generation which are cached later, and not updated, until we make change again. And remember to not use eval() within the return ; directive instruction. (only if your application need that)
对于从 ["" => "", ..] 格式解析可能是 eval() 是最好的选择。请记住,这是在模板生成时完成的,模板会在稍后缓存,并且不会更新,直到我们再次进行更改。并记住不要在 return 中使用 eval() ;指示性指令。(仅当您的应用程序需要时)
for just multi arguments, and so not an array:A function like that will do the job:
仅用于多参数,而不是数组:这样的函数可以完成这项工作:
public static function parseMultipleArgs($expression)
{
return collect(explode(',', $expression))->map(function ($item) {
return trim($item);
});
}
or
或者
public static function parseMultipleArgs($expression)
{
$ar = explode(',', $expression);
$l = len($ar);
if($l == 1) return $ar[0];
for($i = 0; $i < $l; $i++){$ar[$i] = trim($ar[$i])}
return $ar;
}
and you can tweak them as you like, using str_replace to remove things like () ...etc [in short we workout our own parsing. RegEx can be helpful. And depend on what we want to achieve.
并且您可以根据需要调整它们,使用 str_replace 删除诸如 () ...等内容[简而言之,我们自己进行解析。正则表达式可能会有所帮助。并取决于我们想要实现的目标。
All the above are way to parse entries and separate them into variables you use for generating the template. And so for making your return statement.
以上都是解析条目并将它们分成用于生成模板的变量的方法。所以为了制作你的退货声明。
WHAT IF ALL YOU WANT IS TO HAVE YOUR DIRECTIVE TAKE AN ARRAY WITH VARIABLES FROM THE VIEW SCOPE:
如果您想要的只是让您的指令从 VIEW 范围内获取一个带有变量的数组:
like in @section('', ["var" => $varValue])
像 @section('', ["var" => $varValue])
Well here particulary we use the multi arguments parsing, then we recover ["" => ..] expression separately (and here is not the point).
那么这里特别是我们使用多参数解析,然后我们分别恢复 ["" => ..] 表达式(这不是重点)。
The point is when you want to pass an array to be used in your code (view scope). You just use it as it is. (it can be confusing).
关键是当您想要传递要在代码中使用的数组(视图范围)时。您只需按原样使用它。(这可能会令人困惑)。
ex:
前任:
Blade::directive("do", function ($expr) {
return "<?php someFunctionFromMyGlobalOrViewScopThatTakeArrayAsParameter($expr); ?>
});
This will evaluate to
这将评估为
<?php someFunctionFromMyGlobalOrViewScopThatTakeArrayAsParameter(["name" => $user->name, .......]); ?>
And so all will work all right. I took an example where we use a function, you can put all a logic. Directives are just a way to write view in a more beautiful way. Also it allow for pre-view processing and generation. Quiet nice.
所以一切都会好起来的。我举了一个例子,我们使用一个函数,你可以把所有的逻辑。指令只是一种以更漂亮的方式编写视图的方式。它还允许预览处理和生成。安静不错。
回答by Everett
I was searching for this exact solution, then decided to try something different after reading everything and ended up coming up with the solution you and I were both looking for.
我正在寻找这个确切的解决方案,然后决定在阅读所有内容后尝试不同的方法,最终想出了您和我都在寻找的解决方案。
No need for JSON workarounds, explodes, associative arrays, etc... unless you want that functionality for something more complex later.
不需要 JSON 变通方法、分解、关联数组等......除非你以后想要更复杂的功能。
Because Blade is just writing out PHP code to be interpreted later, whatever you've placed into your @highlight directive is the exact PHP code in string format that will be interpreted later.
因为 Blade 只是写出 PHP 代码以供稍后解释,所以您在 @highlight 指令中放置的任何内容都是稍后将被解释的字符串格式的确切 PHP 代码。
What to Do:
该怎么办:
Make and register a helper function that you can call throughout your application. Then use the helper function in your blade directive.
制作并注册一个可以在整个应用程序中调用的辅助函数。然后在您的刀片指令中使用辅助函数。
Helper Definition:
帮手定义:
if(!function_exists('highlight')){
function highlight($expression, $string){
$expressionValues = preg_split('/\s+/', $expression);
foreach ($expressionValues as $value) {
$string = str_replace($value, "<b>".$value."</b>", $string);
}
return $string;
}
}
Blade Directive:
刀片指令:
Blade::directive('highlight', function ($passedDirectiveString){
return "<?php echo highlight($passedDirectiveString);?>";
});
Usage (Example):
用法(示例):
<div>
@highlight('ho', 'house')
</div>
Understanding:
理解:
This is equivalent to writing out:
这相当于写出:
<div>
{! highlight('ho', 'house') !}
</div>
回答by Santiago Mendoza Ramirez
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
在这里找到:https: //laracasts.com/discuss/channels/laravel/how-to-do-this-blade-directive
回答by Filipe Cesar Paladino
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}\"; ?>";
});
回答by Heddie Franco
The value received on blade directive function is a sting, so, you must parse to get the values:
在刀片指令函数上收到的值是一个刺痛,因此,您必须解析以获取值:
BLADE
刀刃
@date($date, 'd-M-Y')
@date($date, 'd-M-Y')
AppServiceProvider
应用服务提供者
Blade::directive('date', function ($str) {
// $str = "$date, 'd-M-Y'";
$data = explode(',',str_replace(' ', '', $str));
//$data = ["$date", "'d-M-Y'"]
$date = $data[0];
$format = $data[1];
return "<?= date_format(date_create($date), $format) ?>";
});
回答by Trent Crawford
If you want to reference variables within a custom blade directive you may not need to pass them directly to the directive. I solved this problem by calling the blade directive from within a blade component. Blade components have local variable scope and so you can simply pass all the variables you need within the call to the blade component (without polluting your view scope). This is sufficient so long as you don't actually need to modify the variables or use them for control logic in your directive.
如果您想在自定义刀片指令中引用变量,您可能不需要将它们直接传递给指令。我通过从刀片组件中调用刀片指令解决了这个问题。Blade 组件具有局部变量范围,因此您可以简单地将调用中所需的所有变量传递给 Blade 组件(不会污染您的视图范围)。只要您实际上不需要修改变量或将它们用于指令中的控制逻辑,这就足够了。
//view.blade.php
@component('my-component',['myVar1'=> $something, 'myVar2'=>$somethingElse])
@endcomponent
//my-component.blade.php
@myBladeDirective('Two variables accessible')
//Boot method of relevant service provider
Blade::directive('myBladeDirective', function ($someVar) {
return "<?php echo $someVar : {$myVar1} and {$myVar2};?>
});
回答by Malcolm Wax
I found an alternative approach to accessing View variables within a Blade Directive.
我找到了一种在 Blade 指令中访问 View 变量的替代方法。
I wanted to check whether a given string appeared as an array key in a variable accessible in the view scope.
我想检查给定的字符串是否在视图范围内可访问的变量中作为数组键出现。
As the Blade Directive returns PHP which is evaluated later, it is possible to 'trick' the Directive by breaking up a variable name so that it doesn't try to parse it.
由于 Blade 指令返回稍后评估的 PHP,因此可以通过分解变量名称来“欺骗”指令,使其不会尝试解析它。
For example:
例如:
Blade::directive('getElementProps', function ($elementID) {
return "<?php
// Reference the $elementData variable
// by splitting its name so it's not parsed here
if (array_key_exists($elementID, $" . "elementData)) {
echo $" . "elementData[$elementID];
}
?>";
});
In this example we have split the $elementData variable name so the Blade Directive treats it like a spring. When the concatenated string is returned to the blade it will be evaluated as the variable.
在此示例中,我们拆分了 $elementData 变量名称,因此 Blade 指令将其视为弹簧。当连接的字符串返回到刀片时,它将被评估为变量。
回答by Casper Wilkes
The best way to accomplish this task is exactly as @Everrett suggested.
完成此任务的最佳方法正是@Everrett 建议的那样。
I checked through the blade code, and this is exactly how the laravel team has to do it as well.
我检查了blade代码,这正是laravel团队必须这样做的。
If you look through vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php
, at the compileDd
function, you'll notice that they use $arguments
instead of $expression
like they do in all of the other compile functions found in vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/
如果您仔细查看vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php
该compileDd
函数,您会注意到它们使用$arguments
而不是$expression
像在 中的所有其他编译函数中那样使用vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/
// CompilesHelpers.php
protected function compileDd($arguments)
{
return "<?php dd{$arguments}; ?>";
}
//CompilesConditionals.php
protected function compileIf($expression)
{
return "<?php if{$expression}: ?>";
}
And if you look at vendor/symfony/var-dumper/Resources/functions/dump.php
you'll see that Laravel handles variable arguments with ...
splat notation in the dd
function.
如果你看一下,vendor/symfony/var-dumper/Resources/functions/dump.php
你会看到 Laravel...
在dd
函数中使用splat 符号处理变量参数。
if (!function_exists('dd')) {
function dd(...$vars)
{
}}
So you could do a directive like: (I put my custom function in app\helpers)If you do the same, you need to make sure to escape the backslashes.
因此,您可以执行如下指令:(我将自定义函数放在 app\helpers 中)如果您也这样做,则需要确保转义反斜杠。
Blade::directive('customFunc', function ($expression) {
return "<?php \App\Helpers\customFunc({$arguments}); ?>";
});
and a custom function like:
和一个自定义函数,如:
/**
* Custom function to demonstrate usage
* @param mixed ...$args
* @return void
*/
function customFunc(...$args): void {
// Extract variables //
// Use pad to get expected args, and set unset to null //
list($arg1, $arg2, $arg3) = array_pad($args, 3, null);
// Echo out args //
echo "arg1: ${arg1} | arg2: ${arg2} | arg3: {$arg3}";
}
run php artisan view:clear
跑 php artisan view:clear
And then use the directive:
然后使用指令:
<div>
@customFunc('hello','wonderful', 'world')
</div>
// Returns:
arg1: hello | arg2: wonderful | arg3: world
// Using
<div>
@customFunc('hello', 'world')
</div>
// Returns:
arg1: hello | arg2: world | arg3:
The best reason to do it this way is so that if your function evolves or changes, you only need to modify the underlining function. You wont have to clear views every time you change the code.
这样做的最佳理由是,如果您的函数发生变化或变化,您只需要修改下划线函数。每次更改代码时都不必清除视图。