-
Notifications
You must be signed in to change notification settings - Fork 11.7k
Fix @JSON Blade directive parsing with nested structures #58075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 12.x
Are you sure you want to change the base?
Conversation
Replaces `explode()` with tokenizer-based parser that respects nested arrays, closures, and function calls. Only splits on commas at the top level, preserving commas inside nested structure. Example of previously broken case: @JSON([$items->map(fn($x) => ['a' => $x, 'b' => $x]), 'key' => 'value']) This fix is backwards compatible - all existing @JSON usage continues to work as before. The change only fixes previously broken cases with complex nested structures. Fixes laravel#56331
| $parts = $this->parseArguments($this->stripParentheses($expression)); | ||
|
|
||
| $options = isset($parts[1]) ? trim($parts[1]) : $this->encodingOptions; | ||
|
|
||
| $depth = isset($parts[2]) ? trim($parts[2]) : 512; | ||
|
|
||
| return "<?php echo json_encode($parts[0], $options, $depth) ?>"; | ||
| // Ensure we have at least one argument, default to null if empty | ||
| $data = $parts[0] ?? 'null'; | ||
|
|
||
| return "<?php echo json_encode($data, $options, $depth) ?>"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can shorten this to
| $parts = $this->parseArguments($this->stripParentheses($expression)); | |
| $options = isset($parts[1]) ? trim($parts[1]) : $this->encodingOptions; | |
| $depth = isset($parts[2]) ? trim($parts[2]) : 512; | |
| return "<?php echo json_encode($parts[0], $options, $depth) ?>"; | |
| // Ensure we have at least one argument, default to null if empty | |
| $data = $parts[0] ?? 'null'; | |
| return "<?php echo json_encode($data, $options, $depth) ?>"; | |
| [$data, $options, $depth] = $this->parseArguments($this->stripParentheses($expression)) + ['null', $this->encodingOptions, 512]; | |
| return '<?php echo json_encode(' . $data . ', ' . trim($options) . ', ' . trim($depth) .') ?>"; |
or
| $parts = $this->parseArguments($this->stripParentheses($expression)); | |
| $options = isset($parts[1]) ? trim($parts[1]) : $this->encodingOptions; | |
| $depth = isset($parts[2]) ? trim($parts[2]) : 512; | |
| return "<?php echo json_encode($parts[0], $options, $depth) ?>"; | |
| // Ensure we have at least one argument, default to null if empty | |
| $data = $parts[0] ?? 'null'; | |
| return "<?php echo json_encode($data, $options, $depth) ?>"; | |
| [$data, $options, $depth] = $this->parseArguments($this->stripParentheses($expression)) + ['null', $this->encodingOptions, 512]; | |
| return sprintf('<?php echo json_encode(%s, %d, %d); ?>', $data, trim($options), trim($depth)); |
if you want
| * and other nested structures by using PHP's tokenizer. | ||
| * | ||
| * @param string $expression | ||
| * @return array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can narrow this further down:
| * @return array | |
| * @return array{0?: string, 1?: string, 2?: string} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good call, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're welcome!
- simplifying `compileJson()` - adds more in depth docblock to `parseArguments()`'s return value
Description
Fixes
@jsonBlade directive incorrectly parsing complex expressions with nested structures. Replacesexplode()with tokenizer-based parser that respects nesting depth.Problem
The directive would split on commas inside nested arrays, closures, and method calls, causing parse errors.
Example (from original issue):
would incorrectly split on the comma inside the closure.
Solution
parseArguments()method using PHP's tokenizerdepth === 0)null)Fully backwards compatible - defaults to same behavior as before.
Fixes #56331