master

laravel/framework

Last updated at: 29/12/2023 09:25

CompilesEchos.php

TLDR

The file CompilesEchos.php in the Illuminate\View\Compilers\Concerns namespace contains a trait that provides methods for compiling Blade echos into valid PHP. It also includes helper methods for adding handlers for custom rendering of stringable objects.

Methods

stringable

Adds a handler to be executed before echoing a given class. This method takes two parameters:

  • $class: The class for which the handler will be executed.
  • $handler: (Optional) A callable function that will be executed before echoing the class.

compileEchos

Compiles Blade echos in a given string into valid PHP code. This method takes one parameter:

  • $value: The string containing Blade echos to be compiled.

getEchoMethods

Returns an array with the names of the methods used to compile Blade echos. The order of the methods is important for compilation.

compileRawEchos

Compiles "raw" echo statements in a given string into valid PHP code. This method takes one parameter:

  • $value: The string containing "raw" echo statements to be compiled.

compileRegularEchos

Compiles "regular" echo statements in a given string into valid PHP code. This method takes one parameter:

  • $value: The string containing "regular" echo statements to be compiled.

compileEscapedEchos

Compiles escaped echo statements in a given string into valid PHP code. This method takes one parameter:

  • $value: The string containing escaped echo statements to be compiled.

addBladeCompilerVariable

Adds an instance of the blade echo handler to the start of the compiled string. This method takes one parameter:

  • $result: The compiled string to which the blade echo handler instance will be added.

wrapInEchoHandler

Wraps an echoable value in an echo handler if applicable. This method takes one parameter:

  • $value: The value to be wrapped in an echo handler.

applyEchoHandler

Applies the echo handler for a given value if it exists. This method takes one parameter:

  • $value: The value to which the echo handler will be applied.

Classes

None

<?php

namespace Illuminate\View\Compilers\Concerns;

use Closure;
use Illuminate\Support\Str;

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.
     *
     * @param  string  $value
     * @return string
     */
    public function compileEchos($value)
    {
        foreach ($this->getEchoMethods() as $method) {
            $value = $this->$method($value);
        }

        return $value;
    }

    /**
     * Get the echo methods in the proper order for compilation.
     *
     * @return array
     */
    protected function getEchoMethods()
    {
        return [
            'compileRawEchos',
            'compileEscapedEchos',
            'compileRegularEchos',
        ];
    }

    /**
     * Compile the "raw" echo statements.
     *
     * @param  string  $value
     * @return string
     */
    protected function compileRawEchos($value)
    {
        $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->rawTags[0], $this->rawTags[1]);

        $callback = function ($matches) {
            $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];

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

        return preg_replace_callback($pattern, $callback, $value);
    }

    /**
     * Compile the "regular" echo statements.
     *
     * @param  string  $value
     * @return string
     */
    protected function compileRegularEchos($value)
    {
        $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->contentTags[0], $this->contentTags[1]);

        $callback = function ($matches) {
            $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];

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

            return $matches[1] ? substr($matches[0], 1) : "<?php echo {$wrapped}; ?>{$whitespace}";
        };

        return preg_replace_callback($pattern, $callback, $value);
    }

    /**
     * Compile the escaped echo statements.
     *
     * @param  string  $value
     * @return string
     */
    protected function compileEscapedEchos($value)
    {
        $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->escapedTags[0], $this->escapedTags[1]);

        $callback = function ($matches) {
            $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];

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

        return preg_replace_callback($pattern, $callback, $value);
    }

    /**
     * Add an instance of the blade echo handler to the start of the compiled string.
     *
     * @param  string  $result
     * @return string
     */
    protected function addBladeCompilerVariable($result)
    {
        return "<?php \$__bladeCompiler = app('blade.compiler'); ?>".$result;
    }

    /**
     * Wrap the echoable value in an echo handler if applicable.
     *
     * @param  string  $value
     * @return string
     */
    protected function wrapInEchoHandler($value)
    {
        $value = Str::of($value)
            ->trim()
            ->when(str_ends_with($value, ';'), function ($str) {
                return $str->beforeLast(';');
            });

        return empty($this->echoHandlers) ? $value : '$__bladeCompiler->applyEchoHandler('.$value.')';
    }

    /**
     * Apply the echo handler for the value if it exists.
     *
     * @param  string  $value
     * @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;
    }
}