라라벨 BladeCompiler

1 개요[ | ]

라라벨 BladeCompiler
PHP
Copy
<?php
namespace Illuminate\View\Compilers;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class BladeCompiler extends Compiler implements CompilerInterface
{
    protected $extensions = [];
    protected $customDirectives = [];
    protected $path;
    protected $compilers = [
        'Extensions',
        'Statements',
        'Comments',
        'Echos',
    ];
    protected $rawTags = ['{!!', '!!}'];
    protected $contentTags = ['{{', '}}'];
    protected $escapedTags = ['{{{', '}}}'];
    protected $echoFormat = 'e(%s)';
    protected $footer = [];
    protected $verbatimPlaceholder = '@__verbatim__@';
    protected $verbatimBlocks = [];
    protected $forelseCounter = 0;
    public function compile($path = null)
    {
        if ($path) {
            $this->setPath($path);
        }
        if (! is_null($this->cachePath)) {
            $contents = $this->compileString($this->files->get($this->getPath()));
            $this->files->put($this->getCompiledPath($this->getPath()), $contents);
        }
    }
    public function getPath()
    {
        return $this->path;
    }
    public function setPath($path)
    {
        $this->path = $path;
    }
    public function compileString($value)
    {
        $result = '';
        if (strpos($value, '@verbatim') !== false) {
            $value = $this->storeVerbatimBlocks($value);
        }
        $this->footer = [];
        foreach (token_get_all($value) as $token) {
            $result .= is_array($token) ? $this->parseToken($token) : $token;
        }
        if (! empty($this->verbatimBlocks)) {
            $result = $this->restoreVerbatimBlocks($result);
        }
        if (count($this->footer) > 0) {
        $result = ltrim($result, PHP_EOL)
            .PHP_EOL.implode(PHP_EOL, array_reverse($this->footer));
        }
        return $result;
    }
    protected function storeVerbatimBlocks($value)
    {
        return preg_replace_callback('/(?<!@)@verbatim(.*?)@endverbatim/s', function ($matches) {
            $this->verbatimBlocks[] = $matches[1];
            return $this->verbatimPlaceholder;
        }, $value);
    }
    protected function restoreVerbatimBlocks($result)
    {
        $result = preg_replace_callback('/'.preg_quote($this->verbatimPlaceholder).'/', function () {
            return array_shift($this->verbatimBlocks);
        }, $result);
        $this->verbatimBlocks = [];
        return $result;
    }
    protected function parseToken($token)
    {
        list($id, $content) = $token;
        if ($id == T_INLINE_HTML) {
            foreach ($this->compilers as $type) {
                $content = $this->{"compile{$type}"}($content);
            }
        }
        return $content;
    }
    protected function compileExtensions($value)
    {
        foreach ($this->extensions as $compiler) {
            $value = call_user_func($compiler, $value, $this);
        }
        return $value;
    }
    protected function compileComments($value)
    {
        $pattern = sprintf('/%s--(.*?)--%s/s', $this->contentTags[0], $this->contentTags[1]);
        return preg_replace($pattern, '<?php /*$1*/ ?>', $value);
    }
    protected function compileEchos($value)
    {
        foreach ($this->getEchoMethods() as $method => $length) {
            $value = $this->$method($value);
        }
        return $value;
    }
    protected function getEchoMethods()
    {
        $methods = [
            'compileRawEchos' => strlen(stripcslashes($this->rawTags[0])),
            'compileEscapedEchos' => strlen(stripcslashes($this->escapedTags[0])),
            'compileRegularEchos' => strlen(stripcslashes($this->contentTags[0])),
        ];
        uksort($methods, function ($method1, $method2) use ($methods) {
                        if ($methods[$method1] > $methods[$method2]) {
                return -1;
            }
            if ($methods[$method1] < $methods[$method2]) {
                return 1;
            }
                        if ($method1 === 'compileRawEchos') {
                return -1;
            }
            if ($method2 === 'compileRawEchos') {
                return 1;
            }
            if ($method1 === 'compileEscapedEchos') {
                return -1;
            }
            if ($method2 === 'compileEscapedEchos') {
                return 1;
            }
        });
        return $methods;
    }
    protected function compileStatements($value)
    {
        $callback = function ($match) {
            if (Str::contains($match[1], '@')) {
                $match[0] = isset($match[3]) ? $match[1].$match[3] : $match[1];
            } elseif (isset($this->customDirectives[$match[1]])) {
                $match[0] = call_user_func($this->customDirectives[$match[1]], Arr::get($match, 3));
            } elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) {
                $match[0] = $this->$method(Arr::get($match, 3));
            }
            return isset($match[3]) ? $match[0] : $match[0].$match[2];
        };
        return preg_replace_callback('/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', $callback, $value);
    }
    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->compileEchoDefaults($matches[2]).'; ?>'.$whitespace;
        };
        return preg_replace_callback($pattern, $callback, $value);
    }
    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->compileEchoDefaults($matches[2]));
            return $matches[1] ? substr($matches[0], 1) : '<?php echo '.$wrapped.'; ?>'.$whitespace;
        };
        return preg_replace_callback($pattern, $callback, $value);
    }
    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->compileEchoDefaults($matches[2]).'); ?>'.$whitespace;
        };
        return preg_replace_callback($pattern, $callback, $value);
    }
    public function compileEchoDefaults($value)
    {
        return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/s', 'isset($1) ? $1 : $2', $value);
    }
    protected function compileEach($expression)
    {
        return "<?php echo \$__env->renderEach{$expression}; ?>";
    }
    protected function compileInject($expression)
    {
        $segments = explode(',', preg_replace("/[\(\)\\\"\']/", '', $expression));
        return '<?php $'.trim($segments[0])." = app('".trim($segments[1])."'); ?>";
    }
    protected function compileYield($expression)
    {
        return "<?php echo \$__env->yieldContent{$expression}; ?>";
    }
    protected function compileShow($expression)
    {
        return '<?php echo $__env->yieldSection(); ?>';
    }
    protected function compileSection($expression)
    {
        return "<?php \$__env->startSection{$expression}; ?>";
    }
    protected function compileAppend($expression)
    {
        return '<?php $__env->appendSection(); ?>';
    }
    protected function compileEndsection($expression)
    {
        return '<?php $__env->stopSection(); ?>';
    }
    protected function compileStop($expression)
    {
        return '<?php $__env->stopSection(); ?>';
    }
    protected function compileOverwrite($expression)
    {
        return '<?php $__env->stopSection(true); ?>';
    }
    protected function compileUnless($expression)
    {
        return "<?php if ( ! $expression): ?>";
    }
    protected function compileEndunless($expression)
    {
        return '<?php endif; ?>';
    }
    protected function compileLang($expression)
    {
        return "<?php echo app('translator')->get$expression; ?>";
    }
    protected function compileChoice($expression)
    {
        return "<?php echo app('translator')->choice$expression; ?>";
    }
    protected function compileElse($expression)
    {
        return '<?php else: ?>';
    }
    protected function compileFor($expression)
    {
        return "<?php for{$expression}: ?>";
    }
    protected function compileForeach($expression)
    {
        return "<?php foreach{$expression}: ?>";
    }
    protected function compileBreak($expression)
    {
        return $expression ? "<?php if{$expression} break; ?>" : '<?php break; ?>';
    }
    protected function compileContinue($expression)
    {
        return $expression ? "<?php if{$expression} continue; ?>" : '<?php continue; ?>';
    }
    protected function compileForelse($expression)
    {
        $empty = '$__empty_'.++$this->forelseCounter;
        return "<?php {$empty} = true; foreach{$expression}: {$empty} = false; ?>";
    }
    protected function compileCan($expression)
    {
        return "<?php if (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->check{$expression}): ?>";
    }
    protected function compileElsecan($expression)
    {
        return "<?php elseif (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->check{$expression}): ?>";
    }
    protected function compileCannot($expression)
    {
        return "<?php if (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->denies{$expression}): ?>";
    }
    protected function compileElsecannot($expression)
    {
        return "<?php elseif (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->denies{$expression}): ?>";
    }
    protected function compileIf($expression)
    {
        return "<?php if{$expression}: ?>";
    }
    protected function compileElseif($expression)
    {
        return "<?php elseif{$expression}: ?>";
    }
    protected function compileEmpty($expression)
    {
        $empty = '$__empty_'.$this->forelseCounter--;
        return "<?php endforeach; if ({$empty}): ?>";
    }
    protected function compileHasSection($expression)
    {
        return "<?php if (! empty(trim(\$__env->yieldContent{$expression}))): ?>";
    }
    protected function compileWhile($expression)
    {
        return "<?php while{$expression}: ?>";
    }
    protected function compileEndwhile($expression)
    {
        return '<?php endwhile; ?>';
    }
    protected function compileEndfor($expression)
    {
        return '<?php endfor; ?>';
    }
    protected function compileEndforeach($expression)
    {
        return '<?php endforeach; ?>';
    }
    protected function compileEndcan($expression)
    {
        return '<?php endif; ?>';
    }
    protected function compileEndcannot($expression)
    {
        return '<?php endif; ?>';
    }
    protected function compileEndif($expression)
    {
        return '<?php endif; ?>';
    }
    protected function compileEndforelse($expression)
    {
        return '<?php endif; ?>';
    }
    protected function compilePhp($expression)
    {
        return $expression ? "<?php {$expression}; ?>" : '<?php ';
    }
    protected function compileEndphp($expression)
    {
        return ' ?>';
    }
    protected function compileUnset($expression)
    {
        return "<?php unset{$expression}; ?>";
    }
    protected function compileExtends($expression)
    {
        $expression = $this->stripParentheses($expression);
        $data = "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
        $this->footer[] = $data;
        return '';
    }
    protected function compileInclude($expression)
    {
        $expression = $this->stripParentheses($expression);
        return "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
    }
    protected function compileIncludeIf($expression)
    {
        $expression = $this->stripParentheses($expression);
        return "<?php if (\$__env->exists($expression)) echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
    }
    protected function compileStack($expression)
    {
        return "<?php echo \$__env->yieldPushContent{$expression}; ?>";
    }
    protected function compilePush($expression)
    {
        return "<?php \$__env->startPush{$expression}; ?>";
    }
    protected function compileEndpush($expression)
    {
        return '<?php $__env->stopPush(); ?>';
    }
    protected function stripParentheses($expression)
    {
        if (Str::startsWith($expression, '(')) {
            $expression = substr($expression, 1, -1);
        }
        return $expression;
    }
    public function getExtensions()
    {
        return $this->extensions;
    }
    public function extend(callable $compiler)
    {
        $this->extensions[] = $compiler;
    }
    public function directive($name, callable $handler)
    {
        $this->customDirectives[$name] = $handler;
    }
    public function getCustomDirectives()
    {
        return $this->customDirectives;
    }
    public function getRawTags()
    {
        return $this->rawTags;
    }
    public function setRawTags($openTag, $closeTag)
    {
        $this->rawTags = [preg_quote($openTag), preg_quote($closeTag)];
    }
    public function setContentTags($openTag, $closeTag, $escaped = false)
    {
        $property = ($escaped === true) ? 'escapedTags' : 'contentTags';
        $this->{$property} = [preg_quote($openTag), preg_quote($closeTag)];
    }
    public function setEscapedContentTags($openTag, $closeTag)
    {
        $this->setContentTags($openTag, $closeTag, true);
    }
    public function getContentTags()
    {
        return $this->getTags();
    }
    public function getEscapedContentTags()
    {
        return $this->getTags(true);
    }
    protected function getTags($escaped = false)
    {
        $tags = $escaped ? $this->escapedTags : $this->contentTags;
        return array_map('stripcslashes', $tags);
    }
    public function setEchoFormat($format)
    {
        $this->echoFormat = $format;
    }
}

2 같이 보기[ | ]