web-dev-qa-db-ja.com

複数のパラメータをブレードディレクティブに渡す

検索クエリから返されるいくつかの単語を強調表示するために、bladeディレクティブを作成しようとしています。

これは私のブレードディレクティブです:

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()
    {
    }
}

そして、私はこのようにブレードを呼び出します:

@highlight('ho', 'house')

しかし、このエラーは私をフォローしています:

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

それを解決する方法は?

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

    // Great coding stuff here
});

およびブレードテンプレート内:

@custom('param1', 'param2', 'param3')
8
Agung Darmanto

連想配列の場合、eval()が最も簡単な場合があります。しかし、それはあなたが穴を開けるようなものであり、コード実行のための針であるため、その使用は危険であると宣伝されています。同時にeval()は実行時に実行されます、まあそれは実行されるコードをデータベースに保存します(キャッシュ[コンパイルされたバイトコードをキャッシュすることを意味します])。これは追加のオーバーヘッドであるため、パフォーマンスがヒットします。これは、このトピックに関する素晴らしい論文です[詳細を読んだり、詳しく説明したりしませんでした]) https://link.springer.com/chapter/10.1007%2F978-981-10-3935-5_12

ここで私はあなたを手に入れました!、ビューはキャッシュされ、変更した場合にのみ生成されるため、サーバーサービスのパフォーマンスにパフォーマンスの違いはありません。ディレクティブはphpコードに変換され、別のプロセスでキャッシュされます。 (生成されたビューはstorage/framework/viewsにあります)

enter image description here だから

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

    // do something with $myarray
    return "<?php echo ..";
});
_

大丈夫です。 eval()とパフォーマンスについて話すことは何もありません(それは行われ、キャッシュされ、生成されたphpコードは何度も実行されるものです(ディレクティブによって返されたphpコードがeval()を保持していないことを確認してください) 、理由がない限り)eval()を直接使用すると(さまざまなリクエストに何度も使用されます)、パフォーマンスに影響します(eval()について話したかったのですが、これらは役立つ情報だと思います)

そのまま配列形式を解析できます["sometin" => "i should be sting"、 "" => ""、...]。

_eval("\$array = $expression;");
// then we can do what we want with $array 
_

ただし、変数を渡すことはできません。例:@directive(["s" => $var])eval$ varディレクティブ関数スコープでは未定義になります。 (ディレクティブはtempalteを美しく生成する方法であり、醜い(実際には醜くない)phpコードをそのようなディレクティブに変換することを忘れないでください。実際には逆です。美しいディレクティブを次のphpコードに変換しています。最後に実行されます。ここで行うのは、最終的なphpページまたはファイルを形成する式を生成、構築、作成することだけです。)

代わりにできることは、この方法で変数を渡すことです["s" => "$ var"]、それでそれはevalを通過します。そして、returnステートメントで次の例を使用します。

_return "<?php echo ".$array['s'].";?>";
_

テンプレートが生成されるとき、これは_<?php echo $var;?>_になります。

evalを使用する場合は、返された文字列内で使用しないでください。または、場合によってはそうしたいこともあります。

別の解決策

(これはeasy)提案された解析ソリューションに沿って、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()
    {
    }
}
_

これが私がそうする必要があった例です:目標はこれを自動化することです

_@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 ...
_

だから私はこの指令を書いた:

_ 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;
        });
    }
_

私たちはそれを次のように使用します:

_@varSet({
    "logo": "logo",
    "width": 78,
    "height": 22
})// hi my cool directive. that's slick.
_

なぜこのフォームが機能するのですか?このような文字列テンプレートとして渡されます

_"""
{\n
    "logo": "logo",\n
    "width": 78,\n
    "height": 22\n
}
"""
_

テンプレート変数で使用するには、evalで行ったのと同じように、「$ var」のような文字列としてそれらを渡します。

["" => ""から解析する場合、..]形式はeval()が最良の選択である可能性があります。これはテンプレートの生成時に行われ、後でキャッシュされ、再度変更を加えるまで更新されないことに注意してください。また、return内でeval()を使用しないことを忘れないでください。指令命令。 (アプリケーションでそれが必要な場合のみ)

複数の引数だけで、配列ではありません:そのような関数は次の仕事をします:

_ public static function parseMultipleArgs($expression)
{
    return collect(explode(',', $expression))->map(function ($item) {
        return trim($item);
    });
}
_

または

_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;
    }
_

そして、str_replaceを使用して()... etc [のようなものを削除して、好きなようにそれらを微調整することができます。正規表現が役立つ場合があります。そして、私たちが達成したいことに依存します。

上記はすべて、エントリを解析し、テンプレートの生成に使用する変数にそれらを分離する方法です。そして、あなたのreturnステートメントを作るために。

あなたが望むすべての場合ISあなたの指令にビュースコープからの変数を含む配列を取得させるには:

@section('', ["var" => $varValue])のように

ここでは特に、複数の引数の解析を使用してから、["" => ..]式を個別に復元します(ここでは重要ではありません)。

重要なのは、コード(ビュースコープ)で使用する配列を渡すときです。そのまま使用します。 (混乱する可能性があります)。

例:

_Blade::directive("do", function ($expr) {
    return "<?php someFunctionFromMyGlobalOrViewScopThatTakeArrayAsParameter($expr); ?>
});
_

これはに評価されます

_<?php someFunctionFromMyGlobalOrViewScopThatTakeArrayAsParameter(["name" => $user->name, .......]); ?>
_

そして、すべてがうまくいくでしょう。関数を使用する例を取り上げました。すべてのロジックを配置できます。ディレクティブは、ビューをより美しい方法で記述するための単なる方法です。また、プレビューの処理と生成も可能です。静かなニース。

6
Mohamed Allal

私はこの正確な解決策を探していましたが、すべてを読んだ後、別のことを試してみることにし、あなたと私が探していた解決策を思いついたのです。

JSONの回避策、展開、連想配列などは、後でもっと複雑なものにその機能が必要な場合を除いて、必要ありません。

Bladeは後で解釈されるPHPコードを書き出しているだけなので、@ highlightディレクティブに配置したものはすべて正確なPHP文字列形式のコードです。後で解釈されます。

何をすべきか:

アプリケーション全体で呼び出すことができるヘルパー関数を作成して登録します。次に、ブレードディレクティブでヘルパー関数を使用します。

ヘルパー定義:

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('highlight', function ($passedDirectiveString){
        return "<?php echo highlight($passedDirectiveString);?>";
    });

使用法(例):

<div>
    @highlight('ho', 'house')
</div>

理解:

これは、書き出すのと同じです。

<div>
    {! highlight('ho', 'house') !}
</div>
3
Everett

渡すことができるパラメータは1つだけだと思います。きれいではありませんが、次のようにパラメータを配列として渡すことができます。

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

だからあなたの指令は

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()
    {
    }
}

ここで見つけました: https://laracasts.com/discuss/channels/laravel/how-to-do-this-blade-directive

ブレードディレクティブ内のビュー変数にアクセスするための代替アプローチを見つけました。

特定の文字列が、ビュースコープでアクセス可能な変数の配列キーとして表示されるかどうかを確認したかったのです。

ブレードディレクティブは後で評価されるPHPを返すので、変数名を分割して解析を試みないようにすることで、ディレクティブを「だます」ことができます。

例えば:

    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];
            }
        ?>";
    }); 

この例では、$ elementData変数名を分割して、BladeDirectiveがそれをばねのように扱うようにしました。連結された文字列がブレードに返されると、変数として評価されます。

0
Malcolm Wax

カスタムブレードディレクティブ内で変数を参照する場合は、それらをディレクティブに直接渡す必要がない場合があります。ブレードコンポーネント内からブレードディレクティブを呼び出すことで、この問題を解決しました。ブレードコンポーネントにはローカル変数スコープがあるため、呼び出し内で必要なすべての変数をブレードコンポーネントに渡すことができます(ビュースコープを汚染することはありません)。実際に変数を変更したり、ディレクティブの制御ロジックに使用したりする必要がない限り、これで十分です。

//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};?>
});
0
Trent Crawford

ブレードディレクティブ関数で受け取った値はstingであるため、値を取得するには解析する必要があります。

[〜#〜]ブレード[〜#〜]

@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) ?>";
});
0
Heddie Franco
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}\"; ?>";
    });