Skip to content

Commit

Permalink
tweak stringable implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ibrasho committed Jun 4, 2021
1 parent d13db93 commit 2b9301d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 40 deletions.
24 changes: 0 additions & 24 deletions src/Illuminate/View/Compilers/BladeCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Illuminate\View\Compilers;

use Closure;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\ReflectsClosures;
Expand Down Expand Up @@ -102,13 +101,6 @@ class BladeCompiler extends Compiler implements CompilerInterface
*/
protected $echoFormat = 'e(%s)';

/**
* Custom rendering callbacks for stringable objects.
*
* @var array
*/
public $echoHandlers = [];

/**
* Array of footer lines to be added to the template.
*
Expand Down Expand Up @@ -711,22 +703,6 @@ public function getCustomDirectives()
return $this->customDirectives;
}

/**
* Add a handler to be executed before echoing a given class.
*
* @param string|callable $class
* @param callable|null $handler
* @return void
*/
public function stringable($class, $handler = null)
{
if ($class instanceof Closure) {
[$class, $handler] = [$this->firstClosureParameterType($class), $class];
}

$this->echoHandlers[$class] = $handler;
}

/**
* Register a new precompiler.
*
Expand Down
52 changes: 45 additions & 7 deletions src/Illuminate/View/Compilers/Concerns/CompilesEchos.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,33 @@

namespace Illuminate\View\Compilers\Concerns;

use Closure;

trait CompilesEchos
{
/**
* Custom rendering callbacks for stringable objects.
*
* @var array
*/
protected $echoHandlers = [];

/**
* Add a handler to be executed before echoing a given class.
*
* @param string|callable $class
* @param callable|null $handler
* @return void
*/
public function stringable($class, $handler = null)
{
if ($class instanceof Closure) {
[$class, $handler] = [$this->firstClosureParameterType($class), $class];
}

$this->echoHandlers[$class] = $handler;
}

/**
* Compile Blade echos into valid PHP.
*
Expand Down Expand Up @@ -48,7 +73,7 @@ protected function compileRawEchos($value)

return $matches[1]
? substr($matches[0], 1)
: "<?php echo {$this->applyEchoHandlerFor($matches[2])}; ?>{$whitespace}";
: "<?php echo {$this->wrapInEchoHandler($matches[2])}; ?>{$whitespace}";
};

return preg_replace_callback($pattern, $callback, $value);
Expand All @@ -67,7 +92,7 @@ protected function compileRegularEchos($value)
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];

$wrapped = sprintf($this->echoFormat, $this->applyEchoHandlerFor($matches[2]));
$wrapped = sprintf($this->echoFormat, $this->wrapInEchoHandler($matches[2]));

return $matches[1] ? substr($matches[0], 1) : "<?php echo {$wrapped}; ?>{$whitespace}";
};
Expand All @@ -90,7 +115,7 @@ protected function compileEscapedEchos($value)

return $matches[1]
? $matches[0]
: "<?php echo e({$this->applyEchoHandlerFor($matches[2])}); ?>{$whitespace}";
: "<?php echo e({$this->wrapInEchoHandler($matches[2])}); ?>{$whitespace}";
};

return preg_replace_callback($pattern, $callback, $value);
Expand All @@ -102,10 +127,23 @@ protected function compileEscapedEchos($value)
* @param string $value
* @return string
*/
protected function applyEchoHandlerFor($value)
protected function wrapInEchoHandler($value)
{
return empty($this->echoHandlers)
? $value
: "is_object($value) && isset(app('blade.compiler')->echoHandlers[get_class($value)]) ? call_user_func_array(app('blade.compiler')->echoHandlers[get_class($value)], [$value]) : $value";
return empty($this->echoHandlers) ? $value : "app('blade.compiler')->applyEchoHandler({$value})";
}

/**
* Apply the echo handler for the value if it exists.
*
* @param $value string
* @return string
*/
public function applyEchoHandler($value)
{
if (is_object($value) && isset($this->echoHandlers[get_class($value)])) {
return call_user_func($this->echoHandlers[get_class($value)], $value);
}

return $value;
}
}
13 changes: 4 additions & 9 deletions tests/View/Blade/BladeEchoHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,34 @@ protected function setUp(): void
});
}

public function testBladeHandlersCanBeAddedForAGivenClass()
{
$this->assertSame('Hello World', $this->compiler->echoHandlers[Fluent::class](new Fluent()));
}

public function testBladeHandlerCanInterceptRegularEchos()
{
$this->assertSame(
"<?php echo e(is_object(\$exampleObject) && isset(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)]) ? call_user_func_array(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)], [\$exampleObject]) : \$exampleObject); ?>",
"<?php echo e(app('blade.compiler')->applyEchoHandler(\$exampleObject)); ?>",
$this->compiler->compileString('{{$exampleObject}}')
);
}

public function testBladeHandlerCanInterceptRawEchos()
{
$this->assertSame(
"<?php echo is_object(\$exampleObject) && isset(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)]) ? call_user_func_array(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)], [\$exampleObject]) : \$exampleObject; ?>",
"<?php echo app('blade.compiler')->applyEchoHandler(\$exampleObject); ?>",
$this->compiler->compileString('{!!$exampleObject!!}')
);
}

public function testBladeHandlerCanInterceptEscapedEchos()
{
$this->assertSame(
"<?php echo e(is_object(\$exampleObject) && isset(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)]) ? call_user_func_array(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)], [\$exampleObject]) : \$exampleObject); ?>",
"<?php echo e(app('blade.compiler')->applyEchoHandler(\$exampleObject)); ?>",
$this->compiler->compileString('{{{$exampleObject}}}')
);
}

public function testWhitespaceIsPreservedCorrectly()
{
$this->assertSame(
"<?php echo e(is_object(\$exampleObject) && isset(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)]) ? call_user_func_array(app('blade.compiler')->echoHandlers[get_class(\$exampleObject)], [\$exampleObject]) : \$exampleObject); ?>\n\n",
"<?php echo e(app('blade.compiler')->applyEchoHandler(\$exampleObject)); ?>\n\n",
$this->compiler->compileString("{{\$exampleObject}}\n")
);
}
Expand Down

0 comments on commit 2b9301d

Please sign in to comment.