Framework: [5.6] [Blade] Error using @json Blade helper

Created on 3 Jul 2018  Â·  10Comments  Â·  Source: laravel/framework

  • Laravel Version: 5.6.26
  • PHP Version: 7.2.7
  • Database Driver & Version: -

Description:

@json blade helper breaks json on template:

Steps To Reproduce:

It works:

<canvas data-chart-datasets="{{ json_encode([
    [
        'label' => 'Value',
        'data' => $list->pluck('sum')->toJson()
    ],
    [
        'label' => 'Quantity',
        'data' => $list->pluck('count')->toJson()
    ]
]) }}"></canvas>

It works:

<canvas data-chart-datasets="@json([
    [
        'label' => 'Value',
        'data' => $list->pluck('sum')->toJson()
    ],
    [
        'label' => 'Quantity'
    ]
])"></canvas>

Generated compiled view:

<canvas data-chart-datasets="<?php echo json_encode([
    [
        'label' => 'Value', 'data' => $list->pluck('sum')->toJson()
    ], [
        'label' => 'Quantity'
    ]
]) ?>"></canvas>

It fails:

<canvas data-chart-datasets="@json([
    [
        'label' => 'Value',
        'data' => $list->pluck('sum')->toJson()
    ],
    [
        'label' => 'Quantity',
        'data' => $list->pluck('count')->toJson()
    ]
])"></canvas>

Generated compiled view:

<canvas data-chart-datasets="<?php echo json_encode([
    [
        'label' => 'Value', 'data' => $list->pluck('sum')->toJson()
    ], [
        'label' => 'Quantity') ?>"></canvas>

Regards!

All 10 comments

This comment on PR #23655, may be relevant.

@devcircus these comment is about to parse json_encode additional parameters.

I think that if @json helper method can only parse some PHP code, should be on docs https://laravel.com/docs/5.6/blade

Thanks anyway.

Care to update update the @json regex? That's quite complicated if you will do it, and the last characters ] and ) were the hardest one to capture.

If you will check the sample from the docs itself, it is simply a variable passed in, but if you will build your own array inside the json directive, then you should just use raw json in the first place or pass in the array into a variable before under the directive, you should also read back how blade directive works, specially @include that has some drawback when using open parentheses ( and there is no close parentheses ).

@include('partials.breaker', [
    'sampleString' => 'My string with open parentheses ( and without close parentheses will break this shit',
])

Alternative Solution:

@php
$arr = [
    [
        'label' => 'Value',
        'data' => $list->pluck('sum')->toJson(),
    ],
    [
        'label' => 'Quantity',
        'data' => $list->pluck('count')->toJson(),
    ],
];
@endphp

<canvas data-chart-datasets="@json($arr)"></canvas>

Move your data construction into your controller or responses.

@tillkruss I'm actually doing. I only was reporting a bug.

Thanks anyway.

Based on the link I posted earlier and many other discussions over the past several years, regarding other blade helpers, this is a known limitation of blade. Fortunately there's a simple workaround.

Yes @devcircus, it's not a problem about the blade helpers limitations.

It's only a comment about if should be documented on docs to avoid to use complex code on it.

untitled

Anyway, closed case :P

In that case, the docs are open source as well. I'll see about sending a PR, or if you know how you'd like to word it, go ahead and send one.

Since this bug won't get fixed anytime soon, the workaround for those interested is to overwrite the @json blade directive. Here is a quick implementation you can put in your AppServiceProvider if you plan to use the same json_encode() arguments globally:

Blade::directive('json', function($expression){
  return "<?php echo json_encode($expression, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>";
});

Here is an alternative fix:
In helpers:
php <?php function split_arguments($expression){ $tokens = token_get_all("<?php $expression"); array_shift($tokens); $arguments = ['']; $p = [ '()' => 0, '[]' => 0, '{}' => 0, '``' => 0, ]; foreach ($tokens as $token){ switch ($token){ case '(': $p['()']++; break; case ')': $p['()']--; break; case '[': $p['[]']++; break; case ']': $p['[]']--; break; case '{': $p['{}']++; break; case '}': $p['{}']--; break; case '`': $p['``'] = !$p['``']; break; case ',': if(!array_sum($p)){ array_unshift($arguments, ''); $token = ''; } break; } if(is_string($token)){ $arguments[0] .= $token; } else { $arguments[0] .= $token[1]; } } return array_reverse($arguments); }
In service provider:
php <?php Blade::directive('json', function ($expression){ $args = split_arguments($expression); if(count($args) < 2){ $args[]= '15'; } if (count($args) < 3){ $args[]= '512'; } return "<?php echo json_encode($args[0], $args[1], $args[2]) ;?>"; });
Result:
````
Psy Shell v0.9.9 (PHP 7.1.23 — cli) by Justin Hileman

Blade::compileString('@json([1, 2, 3, 4, 5])');
=> ""
````
of course, this solution will reduce the performance, but only for compile time.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

itsgoingd picture itsgoingd  Â·  81Comments

mianshargeel picture mianshargeel  Â·  59Comments

robjbrain picture robjbrain  Â·  64Comments

mstnorris picture mstnorris  Â·  87Comments

nkeena picture nkeena  Â·  75Comments