AnonymousComponent.php000064400000002215150145556460011143 0ustar00view = $view; $this->data = $data; } /** * Get the view / view contents that represent the component. * * @return string */ public function render() { return $this->view; } /** * Get the data that should be supplied to the view. * * @return array */ public function data() { $this->attributes = $this->attributes ?: $this->newAttributeBag(); return array_merge( ($this->data['attributes'] ?? null)?->getAttributes() ?: [], $this->attributes->getAttributes(), $this->data, ['attributes' => $this->attributes] ); } } AppendableAttributeValue.php000064400000001057150145556460012207 0ustar00value = $value; } /** * Get the string value. * * @return string */ public function __toString() { return (string) $this->value; } } Compilers/BladeCompiler.php000064400000065672150145556460011747 0ustar00setPath($path); } if (! is_null($this->cachePath)) { $contents = $this->compileString($this->files->get($this->getPath())); if (! empty($this->getPath())) { $contents = $this->appendFilePath($contents); } $this->ensureCompiledDirectoryExists( $compiledPath = $this->getCompiledPath($this->getPath()) ); $this->files->put($compiledPath, $contents); } } /** * Append the file path to the compiled string. * * @param string $contents * @return string */ protected function appendFilePath($contents) { $tokens = $this->getOpenAndClosingPhpTokens($contents); if ($tokens->isNotEmpty() && $tokens->last() !== T_CLOSE_TAG) { $contents .= ' ?>'; } return $contents."getPath()} ENDPATH**/ ?>"; } /** * Get the open and closing PHP tag tokens from the given string. * * @param string $contents * @return \Illuminate\Support\Collection */ protected function getOpenAndClosingPhpTokens($contents) { return (new Collection(token_get_all($contents))) ->pluck(0) ->filter(function ($token) { return in_array($token, [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG]); }); } /** * Get the path currently being compiled. * * @return string */ public function getPath() { return $this->path; } /** * Set the path currently being compiled. * * @param string $path * @return void */ public function setPath($path) { $this->path = $path; } /** * Compile the given Blade template contents. * * @param string $value * @return string */ public function compileString($value) { [$this->footer, $result] = [[], '']; foreach ($this->prepareStringsForCompilationUsing as $callback) { $value = $callback($value); } $value = $this->storeUncompiledBlocks($value); // First we will compile the Blade component tags. This is a precompile style // step which compiles the component Blade tags into @component directives // that may be used by Blade. Then we should call any other precompilers. $value = $this->compileComponentTags( $this->compileComments($value) ); foreach ($this->precompilers as $precompiler) { $value = $precompiler($value); } // Here we will loop through all of the tokens returned by the Zend lexer and // parse each one into the corresponding valid PHP. We will then have this // template as the correctly rendered PHP that can be rendered natively. foreach (token_get_all($value) as $token) { $result .= is_array($token) ? $this->parseToken($token) : $token; } if (! empty($this->rawBlocks)) { $result = $this->restoreRawContent($result); } // If there are any footer lines that need to get added to a template we will // add them here at the end of the template. This gets used mainly for the // template inheritance via the extends keyword that should be appended. if (count($this->footer) > 0) { $result = $this->addFooters($result); } if (! empty($this->echoHandlers)) { $result = $this->addBladeCompilerVariable($result); } return str_replace( ['##BEGIN-COMPONENT-CLASS##', '##END-COMPONENT-CLASS##'], '', $result); } /** * Evaluate and render a Blade string to HTML. * * @param string $string * @param array $data * @param bool $deleteCachedView * @return string */ public static function render($string, $data = [], $deleteCachedView = false) { $component = new class($string) extends Component { protected $template; public function __construct($template) { $this->template = $template; } public function render() { return $this->template; } }; $view = Container::getInstance() ->make(ViewFactory::class) ->make($component->resolveView(), $data); return tap($view->render(), function () use ($view, $deleteCachedView) { if ($deleteCachedView) { @unlink($view->getPath()); } }); } /** * Render a component instance to HTML. * * @param \Illuminate\View\Component $component * @return string */ public static function renderComponent(Component $component) { $data = $component->data(); $view = value($component->resolveView(), $data); if ($view instanceof View) { return $view->with($data)->render(); } elseif ($view instanceof Htmlable) { return $view->toHtml(); } else { return Container::getInstance() ->make(ViewFactory::class) ->make($view, $data) ->render(); } } /** * Store the blocks that do not receive compilation. * * @param string $value * @return string */ protected function storeUncompiledBlocks($value) { if (str_contains($value, '@verbatim')) { $value = $this->storeVerbatimBlocks($value); } if (str_contains($value, '@php')) { $value = $this->storePhpBlocks($value); } return $value; } /** * Store the verbatim blocks and replace them with a temporary placeholder. * * @param string $value * @return string */ protected function storeVerbatimBlocks($value) { return preg_replace_callback('/(?storeRawBlock($matches[2]); }, $value); } /** * Store the PHP blocks and replace them with a temporary placeholder. * * @param string $value * @return string */ protected function storePhpBlocks($value) { return preg_replace_callback('/(?storeRawBlock(""); }, $value); } /** * Store a raw block and return a unique raw placeholder. * * @param string $value * @return string */ protected function storeRawBlock($value) { return $this->getRawPlaceholder( array_push($this->rawBlocks, $value) - 1 ); } /** * Compile the component tags. * * @param string $value * @return string */ protected function compileComponentTags($value) { if (! $this->compilesComponentTags) { return $value; } return (new ComponentTagCompiler( $this->classComponentAliases, $this->classComponentNamespaces, $this ))->compile($value); } /** * Replace the raw placeholders with the original code stored in the raw blocks. * * @param string $result * @return string */ protected function restoreRawContent($result) { $result = preg_replace_callback('/'.$this->getRawPlaceholder('(\d+)').'/', function ($matches) { return $this->rawBlocks[$matches[1]]; }, $result); $this->rawBlocks = []; return $result; } /** * Get a placeholder to temporarily mark the position of raw blocks. * * @param int|string $replace * @return string */ protected function getRawPlaceholder($replace) { return str_replace('#', $replace, '@__raw_block_#__@'); } /** * Add the stored footers onto the given content. * * @param string $result * @return string */ protected function addFooters($result) { return ltrim($result, "\n") ."\n".implode("\n", array_reverse($this->footer)); } /** * Parse the tokens from the template. * * @param array $token * @return string */ protected function parseToken($token) { [$id, $content] = $token; if ($id == T_INLINE_HTML) { foreach ($this->compilers as $type) { $content = $this->{"compile{$type}"}($content); } } return $content; } /** * Execute the user defined extensions. * * @param string $value * @return string */ protected function compileExtensions($value) { foreach ($this->extensions as $compiler) { $value = $compiler($value, $this); } return $value; } /** * Compile Blade statements that start with "@". * * @param string $template * @return string */ protected function compileStatements($template) { preg_match_all('/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( [\S\s]*? ) \))?/x', $template, $matches); $offset = 0; for ($i = 0; isset($matches[0][$i]); $i++) { $match = [ $matches[0][$i], $matches[1][$i], $matches[2][$i], $matches[3][$i] ?: null, $matches[4][$i] ?: null, ]; // Here we check to see if we have properly found the closing parenthesis by // regex pattern or not, and will recursively continue on to the next ")" // then check again until the tokenizer confirms we find the right one. while (isset($match[4]) && Str::endsWith($match[0], ')') && ! $this->hasEvenNumberOfParentheses($match[0])) { if (($after = Str::after($template, $match[0])) === $template) { break; } $rest = Str::before($after, ')'); if (isset($matches[0][$i + 1]) && Str::contains($rest.')', $matches[0][$i + 1])) { unset($matches[0][$i + 1]); $i++; } $match[0] = $match[0].$rest.')'; $match[3] = $match[3].$rest.')'; $match[4] = $match[4].$rest; } [$template, $offset] = $this->replaceFirstStatement( $match[0], $this->compileStatement($match), $template, $offset ); } return $template; } /** * Replace the first match for a statement compilation operation. * * @param string $search * @param string $replace * @param string $subject * @param int $offset * @return array */ protected function replaceFirstStatement($search, $replace, $subject, $offset) { $search = (string) $search; if ($search === '') { return $subject; } $position = strpos($subject, $search, $offset); if ($position !== false) { return [ substr_replace($subject, $replace, $position, strlen($search)), $position + strlen($replace), ]; } return [$subject, 0]; } /** * Determine if the given expression has the same number of opening and closing parentheses. * * @param string $expression * @return bool */ protected function hasEvenNumberOfParentheses(string $expression) { $tokens = token_get_all('customDirectives[$match[1]])) { $match[0] = $this->callCustomDirective($match[1], Arr::get($match, 3)); } elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) { $match[0] = $this->$method(Arr::get($match, 3)); } else { return $match[0]; } return isset($match[3]) ? $match[0] : $match[0].$match[2]; } /** * Call the given directive with the given value. * * @param string $name * @param string|null $value * @return string */ protected function callCustomDirective($name, $value) { $value ??= ''; if (str_starts_with($value, '(') && str_ends_with($value, ')')) { $value = Str::substr($value, 1, -1); } return call_user_func($this->customDirectives[$name], trim($value)); } /** * Strip the parentheses from the given expression. * * @param string $expression * @return string */ public function stripParentheses($expression) { if (Str::startsWith($expression, '(')) { $expression = substr($expression, 1, -1); } return $expression; } /** * Register a custom Blade compiler. * * @param callable $compiler * @return void */ public function extend(callable $compiler) { $this->extensions[] = $compiler; } /** * Get the extensions used by the compiler. * * @return array */ public function getExtensions() { return $this->extensions; } /** * Register an "if" statement directive. * * @param string $name * @param callable $callback * @return void */ public function if($name, callable $callback) { $this->conditions[$name] = $callback; $this->directive($name, function ($expression) use ($name) { return $expression !== '' ? "" : ""; }); $this->directive('unless'.$name, function ($expression) use ($name) { return $expression !== '' ? "" : ""; }); $this->directive('else'.$name, function ($expression) use ($name) { return $expression !== '' ? "" : ""; }); $this->directive('end'.$name, function () { return ''; }); } /** * Check the result of a condition. * * @param string $name * @param mixed ...$parameters * @return bool */ public function check($name, ...$parameters) { return call_user_func($this->conditions[$name], ...$parameters); } /** * Register a class-based component alias directive. * * @param string $class * @param string|null $alias * @param string $prefix * @return void */ public function component($class, $alias = null, $prefix = '') { if (! is_null($alias) && str_contains($alias, '\\')) { [$class, $alias] = [$alias, $class]; } if (is_null($alias)) { $alias = str_contains($class, '\\View\\Components\\') ? (new Collection(explode('\\', Str::after($class, '\\View\\Components\\'))))->map(function ($segment) { return Str::kebab($segment); })->implode(':') : Str::kebab(class_basename($class)); } if (! empty($prefix)) { $alias = $prefix.'-'.$alias; } $this->classComponentAliases[$alias] = $class; } /** * Register an array of class-based components. * * @param array $components * @param string $prefix * @return void */ public function components(array $components, $prefix = '') { foreach ($components as $key => $value) { if (is_numeric($key)) { $this->component($value, null, $prefix); } else { $this->component($key, $value, $prefix); } } } /** * Get the registered class component aliases. * * @return array */ public function getClassComponentAliases() { return $this->classComponentAliases; } /** * Register a new anonymous component path. * * @param string $path * @param string|null $prefix * @return void */ public function anonymousComponentPath(string $path, ?string $prefix = null) { $prefixHash = md5($prefix ?: $path); $this->anonymousComponentPaths[] = [ 'path' => $path, 'prefix' => $prefix, 'prefixHash' => $prefixHash, ]; Container::getInstance() ->make(ViewFactory::class) ->addNamespace($prefixHash, $path); } /** * Register an anonymous component namespace. * * @param string $directory * @param string|null $prefix * @return void */ public function anonymousComponentNamespace(string $directory, ?string $prefix = null) { $prefix ??= $directory; $this->anonymousComponentNamespaces[$prefix] = Str::of($directory) ->replace('/', '.') ->trim('. ') ->toString(); } /** * Register a class-based component namespace. * * @param string $namespace * @param string $prefix * @return void */ public function componentNamespace($namespace, $prefix) { $this->classComponentNamespaces[$prefix] = $namespace; } /** * Get the registered anonymous component paths. * * @return array */ public function getAnonymousComponentPaths() { return $this->anonymousComponentPaths; } /** * Get the registered anonymous component namespaces. * * @return array */ public function getAnonymousComponentNamespaces() { return $this->anonymousComponentNamespaces; } /** * Get the registered class component namespaces. * * @return array */ public function getClassComponentNamespaces() { return $this->classComponentNamespaces; } /** * Register a component alias directive. * * @param string $path * @param string|null $alias * @return void */ public function aliasComponent($path, $alias = null) { $alias = $alias ?: Arr::last(explode('.', $path)); $this->directive($alias, function ($expression) use ($path) { return $expression ? "startComponent('{$path}', {$expression}); ?>" : "startComponent('{$path}'); ?>"; }); $this->directive('end'.$alias, function ($expression) { return 'renderComponent(); ?>'; }); } /** * Register an include alias directive. * * @param string $path * @param string|null $alias * @return void */ public function include($path, $alias = null) { $this->aliasInclude($path, $alias); } /** * Register an include alias directive. * * @param string $path * @param string|null $alias * @return void */ public function aliasInclude($path, $alias = null) { $alias = $alias ?: Arr::last(explode('.', $path)); $this->directive($alias, function ($expression) use ($path) { $expression = $this->stripParentheses($expression) ?: '[]'; return "make('{$path}', {$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; }); } /** * Register a handler for custom directives, binding the handler to the compiler. * * @param string $name * @param callable $handler * @return void * * @throws \InvalidArgumentException */ public function bindDirective($name, callable $handler) { $this->directive($name, $handler, bind: true); } /** * Register a handler for custom directives. * * @param string $name * @param callable $handler * @param bool $bind * @return void * * @throws \InvalidArgumentException */ public function directive($name, callable $handler, bool $bind = false) { if (! preg_match('/^\w+(?:::\w+)?$/x', $name)) { throw new InvalidArgumentException("The directive name [{$name}] is not valid. Directive names must only contain alphanumeric characters and underscores."); } $this->customDirectives[$name] = $bind ? $handler->bindTo($this, BladeCompiler::class) : $handler; } /** * Get the list of custom directives. * * @return array */ public function getCustomDirectives() { return $this->customDirectives; } /** * Indicate that the following callable should be used to prepare strings for compilation. * * @param callable $callback * @return $this */ public function prepareStringsForCompilationUsing(callable $callback) { $this->prepareStringsForCompilationUsing[] = $callback; return $this; } /** * Register a new precompiler. * * @param callable $precompiler * @return void */ public function precompiler(callable $precompiler) { $this->precompilers[] = $precompiler; } /** * Set the echo format to be used by the compiler. * * @param string $format * @return void */ public function setEchoFormat($format) { $this->echoFormat = $format; } /** * Set the "echo" format to double encode entities. * * @return void */ public function withDoubleEncoding() { $this->setEchoFormat('e(%s, true)'); } /** * Set the "echo" format to not double encode entities. * * @return void */ public function withoutDoubleEncoding() { $this->setEchoFormat('e(%s, false)'); } /** * Indicate that component tags should not be compiled. * * @return void */ public function withoutComponentTags() { $this->compilesComponentTags = false; } } Compilers/Compiler.php000075500000006343150145556460011010 0ustar00files = $files; $this->cachePath = $cachePath; $this->basePath = $basePath; $this->shouldCache = $shouldCache; $this->compiledExtension = $compiledExtension; } /** * Get the path to the compiled version of a view. * * @param string $path * @return string */ public function getCompiledPath($path) { return $this->cachePath.'/'.hash('xxh128', 'v2'.Str::after($path, $this->basePath)).'.'.$this->compiledExtension; } /** * Determine if the view at the given path is expired. * * @param string $path * @return bool * * @throws \ErrorException */ public function isExpired($path) { if (! $this->shouldCache) { return true; } $compiled = $this->getCompiledPath($path); // If the compiled file doesn't exist we will indicate that the view is expired // so that it can be re-compiled. Else, we will verify the last modification // of the views is less than the modification times of the compiled views. if (! $this->files->exists($compiled)) { return true; } try { return $this->files->lastModified($path) >= $this->files->lastModified($compiled); } catch (ErrorException $exception) { if (! $this->files->exists($compiled)) { return true; } throw $exception; } } /** * Create the compiled file directory if necessary. * * @param string $path * @return void */ protected function ensureCompiledDirectoryExists($path) { if (! $this->files->exists(dirname($path))) { $this->files->makeDirectory(dirname($path), 0777, true, true); } } } Compilers/CompilerInterface.php000075500000001060150145556460012620 0ustar00 * @author Taylor Otwell */ class ComponentTagCompiler { /** * The Blade compiler instance. * * @var \Illuminate\View\Compilers\BladeCompiler */ protected $blade; /** * The component class aliases. * * @var array */ protected $aliases = []; /** * The component class namespaces. * * @var array */ protected $namespaces = []; /** * The "bind:" attributes that have been compiled for the current component. * * @var array */ protected $boundAttributes = []; /** * Create a new component tag compiler. * * @param array $aliases * @param array $namespaces * @param \Illuminate\View\Compilers\BladeCompiler|null $blade * @return void */ public function __construct(array $aliases = [], array $namespaces = [], ?BladeCompiler $blade = null) { $this->aliases = $aliases; $this->namespaces = $namespaces; $this->blade = $blade ?: new BladeCompiler(new Filesystem, sys_get_temp_dir()); } /** * Compile the component and slot tags within the given string. * * @param string $value * @return string */ public function compile(string $value) { $value = $this->compileSlots($value); return $this->compileTags($value); } /** * Compile the tags within the given string. * * @param string $value * @return string * * @throws \InvalidArgumentException */ public function compileTags(string $value) { $value = $this->compileSelfClosingTags($value); $value = $this->compileOpeningTags($value); $value = $this->compileClosingTags($value); return $value; } /** * Compile the opening tags within the given string. * * @param string $value * @return string * * @throws \InvalidArgumentException */ protected function compileOpeningTags(string $value) { $pattern = "/ < \s* x[-\:]([\w\-\:\.]*) (? (?: \s+ (?: (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: @(?:style)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: \{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\} ) | (?: (\:\\\$)(\w+) ) | (?: [\w\-:.@%]+ ( = (?: \\\"[^\\\"]*\\\" | \'[^\']*\' | [^\'\\\"=<>]+ ) )? ) ) )* \s* ) (? /x"; return preg_replace_callback($pattern, function (array $matches) { $this->boundAttributes = []; $attributes = $this->getAttributesFromAttributeString($matches['attributes']); return $this->componentString($matches[1], $attributes); }, $value); } /** * Compile the self-closing tags within the given string. * * @param string $value * @return string * * @throws \InvalidArgumentException */ protected function compileSelfClosingTags(string $value) { $pattern = "/ < \s* x[-\:]([\w\-\:\.]*) \s* (? (?: \s+ (?: (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: @(?:style)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: \{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\} ) | (?: (\:\\\$)(\w+) ) | (?: [\w\-:.@%]+ ( = (?: \\\"[^\\\"]*\\\" | \'[^\']*\' | [^\'\\\"=<>]+ ) )? ) ) )* \s* ) \/> /x"; return preg_replace_callback($pattern, function (array $matches) { $this->boundAttributes = []; $attributes = $this->getAttributesFromAttributeString($matches['attributes']); return $this->componentString($matches[1], $attributes)."\n@endComponentClass##END-COMPONENT-CLASS##"; }, $value); } /** * Compile the Blade component string for the given component and attributes. * * @param string $component * @param array $attributes * @return string * * @throws \InvalidArgumentException */ protected function componentString(string $component, array $attributes) { $class = $this->componentClass($component); [$data, $attributes] = $this->partitionDataAndAttributes($class, $attributes); $data = $data->mapWithKeys(function ($value, $key) { return [Str::camel($key) => $value]; }); // If the component doesn't exist as a class, we'll assume it's a class-less // component and pass the component as a view parameter to the data so it // can be accessed within the component and we can render out the view. if (! class_exists($class)) { $view = Str::startsWith($component, 'mail::') ? "\$__env->getContainer()->make(Illuminate\\View\\Factory::class)->make('{$component}')" : "'$class'"; $parameters = [ 'view' => $view, 'data' => '['.$this->attributesToString($data->all(), $escapeBound = false).']', ]; $class = AnonymousComponent::class; } else { $parameters = $data->all(); } return "##BEGIN-COMPONENT-CLASS##@component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).']) except(\\'.$class.'::ignoredParameterNames()); ?> withAttributes(['.$this->attributesToString($attributes->all(), $escapeAttributes = $class !== DynamicComponent::class).']); ?>'; } /** * Get the component class for a given component alias. * * @param string $component * @return string * * @throws \InvalidArgumentException */ public function componentClass(string $component) { $viewFactory = Container::getInstance()->make(Factory::class); if (isset($this->aliases[$component])) { if (class_exists($alias = $this->aliases[$component])) { return $alias; } if ($viewFactory->exists($alias)) { return $alias; } throw new InvalidArgumentException( "Unable to locate class or view [{$alias}] for component [{$component}]." ); } if ($class = $this->findClassByComponent($component)) { return $class; } if (class_exists($class = $this->guessClassName($component))) { return $class; } if (class_exists($class = $class.'\\'.Str::afterLast($class, '\\'))) { return $class; } if (! is_null($guess = $this->guessAnonymousComponentUsingNamespaces($viewFactory, $component)) || ! is_null($guess = $this->guessAnonymousComponentUsingPaths($viewFactory, $component))) { return $guess; } if (Str::startsWith($component, 'mail::')) { return $component; } throw new InvalidArgumentException( "Unable to locate a class or view for component [{$component}]." ); } /** * Attempt to find an anonymous component using the registered anonymous component paths. * * @param \Illuminate\Contracts\View\Factory $viewFactory * @param string $component * @return string|null */ protected function guessAnonymousComponentUsingPaths(Factory $viewFactory, string $component) { $delimiter = ViewFinderInterface::HINT_PATH_DELIMITER; foreach ($this->blade->getAnonymousComponentPaths() as $path) { try { if (str_contains($component, $delimiter) && ! str_starts_with($component, $path['prefix'].$delimiter)) { continue; } $formattedComponent = str_starts_with($component, $path['prefix'].$delimiter) ? Str::after($component, $delimiter) : $component; if (! is_null($guess = match (true) { $viewFactory->exists($guess = $path['prefixHash'].$delimiter.$formattedComponent) => $guess, $viewFactory->exists($guess = $path['prefixHash'].$delimiter.$formattedComponent.'.index') => $guess, $viewFactory->exists($guess = $path['prefixHash'].$delimiter.$formattedComponent.'.'.Str::afterLast($formattedComponent, '.')) => $guess, default => null, })) { return $guess; } } catch (InvalidArgumentException) { // } } } /** * Attempt to find an anonymous component using the registered anonymous component namespaces. * * @param \Illuminate\Contracts\View\Factory $viewFactory * @param string $component * @return string|null */ protected function guessAnonymousComponentUsingNamespaces(Factory $viewFactory, string $component) { return (new Collection($this->blade->getAnonymousComponentNamespaces())) ->filter(function ($directory, $prefix) use ($component) { return Str::startsWith($component, $prefix.'::'); }) ->prepend('components', $component) ->reduce(function ($carry, $directory, $prefix) use ($component, $viewFactory) { if (! is_null($carry)) { return $carry; } $componentName = Str::after($component, $prefix.'::'); if ($viewFactory->exists($view = $this->guessViewName($componentName, $directory))) { return $view; } if ($viewFactory->exists($view = $this->guessViewName($componentName, $directory).'.index')) { return $view; } $lastViewSegment = Str::afterLast(Str::afterLast($componentName, '.'), ':'); if ($viewFactory->exists($view = $this->guessViewName($componentName, $directory).'.'.$lastViewSegment)) { return $view; } }); } /** * Find the class for the given component using the registered namespaces. * * @param string $component * @return string|null */ public function findClassByComponent(string $component) { $segments = explode('::', $component); $prefix = $segments[0]; if (! isset($this->namespaces[$prefix], $segments[1])) { return; } if (class_exists($class = $this->namespaces[$prefix].'\\'.$this->formatClassName($segments[1]))) { return $class; } } /** * Guess the class name for the given component. * * @param string $component * @return string */ public function guessClassName(string $component) { $namespace = Container::getInstance() ->make(Application::class) ->getNamespace(); $class = $this->formatClassName($component); return $namespace.'View\\Components\\'.$class; } /** * Format the class name for the given component. * * @param string $component * @return string */ public function formatClassName(string $component) { $componentPieces = array_map(function ($componentPiece) { return ucfirst(Str::camel($componentPiece)); }, explode('.', $component)); return implode('\\', $componentPieces); } /** * Guess the view name for the given component. * * @param string $name * @param string $prefix * @return string */ public function guessViewName($name, $prefix = 'components.') { if (! Str::endsWith($prefix, '.')) { $prefix .= '.'; } $delimiter = ViewFinderInterface::HINT_PATH_DELIMITER; if (str_contains($name, $delimiter)) { return Str::replaceFirst($delimiter, $delimiter.$prefix, $name); } return $prefix.$name; } /** * Partition the data and extra attributes from the given array of attributes. * * @param string $class * @param array $attributes * @return array */ public function partitionDataAndAttributes($class, array $attributes) { // If the class doesn't exist, we'll assume it is a class-less component and // return all of the attributes as both data and attributes since we have // now way to partition them. The user can exclude attributes manually. if (! class_exists($class)) { return [new Collection($attributes), new Collection($attributes)]; } $constructor = (new ReflectionClass($class))->getConstructor(); $parameterNames = $constructor ? (new Collection($constructor->getParameters()))->map->getName()->all() : []; return (new Collection($attributes))->partition(function ($value, $key) use ($parameterNames) { return in_array(Str::camel($key), $parameterNames); })->all(); } /** * Compile the closing tags within the given string. * * @param string $value * @return string */ protected function compileClosingTags(string $value) { return preg_replace("/<\/\s*x[-\:][\w\-\:\.]*\s*>/", ' @endComponentClass##END-COMPONENT-CLASS##', $value); } /** * Compile the slot tags within the given string. * * @param string $value * @return string */ public function compileSlots(string $value) { $pattern = "/ < \s* x[\-\:]slot (?:\:(?\w+(?:-\w+)*))? (?:\s+name=(?(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+)))? (?:\s+\:name=(?(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+)))? (? (?: \s+ (?: (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: @(?:style)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: \{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\} ) | (?: [\w\-:.@]+ ( = (?: \\\"[^\\\"]*\\\" | \'[^\']*\' | [^\'\\\"=<>]+ ) )? ) ) )* \s* ) (? /x"; $value = preg_replace_callback($pattern, function ($matches) { $name = $this->stripQuotes($matches['inlineName'] ?: $matches['name'] ?: $matches['boundName']); if (Str::contains($name, '-') && ! empty($matches['inlineName'])) { $name = Str::camel($name); } // If the name was given as a simple string, we will wrap it in quotes as if it was bound for convenience... if (! empty($matches['inlineName']) || ! empty($matches['name'])) { $name = "'{$name}'"; } $this->boundAttributes = []; $attributes = $this->getAttributesFromAttributeString($matches['attributes']); // If an inline name was provided and a name or bound name was *also* provided, we will assume the name should be an attribute... if (! empty($matches['inlineName']) && (! empty($matches['name']) || ! empty($matches['boundName']))) { $attributes = ! empty($matches['name']) ? array_merge($attributes, $this->getAttributesFromAttributeString('name='.$matches['name'])) : array_merge($attributes, $this->getAttributesFromAttributeString(':name='.$matches['boundName'])); } return " @slot({$name}, null, [".$this->attributesToString($attributes).']) '; }, $value); return preg_replace('/<\/\s*x[\-\:]slot[^>]*>/', ' @endslot', $value); } /** * Get an array of attributes from the given attribute string. * * @param string $attributeString * @return array */ protected function getAttributesFromAttributeString(string $attributeString) { $attributeString = $this->parseShortAttributeSyntax($attributeString); $attributeString = $this->parseAttributeBag($attributeString); $attributeString = $this->parseComponentTagClassStatements($attributeString); $attributeString = $this->parseComponentTagStyleStatements($attributeString); $attributeString = $this->parseBindAttributes($attributeString); $pattern = '/ (?[\w\-:.@%]+) ( = (? ( \"[^\"]+\" | \\\'[^\\\']+\\\' | [^\s>]+ ) ) )? /x'; if (! preg_match_all($pattern, $attributeString, $matches, PREG_SET_ORDER)) { return []; } return (new Collection($matches))->mapWithKeys(function ($match) { $attribute = $match['attribute']; $value = $match['value'] ?? null; if (is_null($value)) { $value = 'true'; $attribute = Str::start($attribute, 'bind:'); } $value = $this->stripQuotes($value); if (str_starts_with($attribute, 'bind:')) { $attribute = Str::after($attribute, 'bind:'); $this->boundAttributes[$attribute] = true; } else { $value = "'".$this->compileAttributeEchos($value)."'"; } if (str_starts_with($attribute, '::')) { $attribute = substr($attribute, 1); } return [$attribute => $value]; })->toArray(); } /** * Parses a short attribute syntax like :$foo into a fully-qualified syntax like :foo="$foo". * * @param string $value * @return string */ protected function parseShortAttributeSyntax(string $value) { $pattern = "/\s\:\\\$(\w+)/x"; return preg_replace_callback($pattern, function (array $matches) { return " :{$matches[1]}=\"\${$matches[1]}\""; }, $value); } /** * Parse the attribute bag in a given attribute string into its fully-qualified syntax. * * @param string $attributeString * @return string */ protected function parseAttributeBag(string $attributeString) { $pattern = "/ (?:^|\s+) # start of the string or whitespace between attributes \{\{\s*(\\\$attributes(?:[^}]+?(?[^()]+) | (?2) )* \))/x', function ($match) { if ($match[1] === 'class') { $match[2] = str_replace('"', "'", $match[2]); return ":class=\"\Illuminate\Support\Arr::toCssClasses{$match[2]}\""; } return $match[0]; }, $attributeString ); } /** * Parse @style statements in a given attribute string into their fully-qualified syntax. * * @param string $attributeString * @return string */ protected function parseComponentTagStyleStatements(string $attributeString) { return preg_replace_callback( '/@(style)(\( ( (?>[^()]+) | (?2) )* \))/x', function ($match) { if ($match[1] === 'style') { $match[2] = str_replace('"', "'", $match[2]); return ":style=\"\Illuminate\Support\Arr::toCssStyles{$match[2]}\""; } return $match[0]; }, $attributeString ); } /** * Parse the "bind" attributes in a given attribute string into their fully-qualified syntax. * * @param string $attributeString * @return string */ protected function parseBindAttributes(string $attributeString) { $pattern = "/ (?:^|\s+) # start of the string or whitespace between attributes :(?!:) # attribute needs to start with a single colon ([\w\-:.@]+) # match the actual attribute name = # only match attributes that have a value /xm"; return preg_replace($pattern, ' bind:$1=', $attributeString); } /** * Compile any Blade echo statements that are present in the attribute string. * * These echo statements need to be converted to string concatenation statements. * * @param string $attributeString * @return string */ protected function compileAttributeEchos(string $attributeString) { $value = $this->blade->compileEchos($attributeString); $value = $this->escapeSingleQuotesOutsideOfPhpBlocks($value); $value = str_replace('', '.\'', $value); return $value; } /** * Escape the single quotes in the given string that are outside of PHP blocks. * * @param string $value * @return string */ protected function escapeSingleQuotesOutsideOfPhpBlocks(string $value) { return (new Collection(token_get_all($value)))->map(function ($token) { if (! is_array($token)) { return $token; } return $token[0] === T_INLINE_HTML ? str_replace("'", "\\'", $token[1]) : $token[1]; })->implode(''); } /** * Convert an array of attributes to a string. * * @param array $attributes * @param bool $escapeBound * @return string */ protected function attributesToString(array $attributes, $escapeBound = true) { return (new Collection($attributes)) ->map(function (string $value, string $attribute) use ($escapeBound) { return $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value) ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})" : "'{$attribute}' => {$value}"; }) ->implode(','); } /** * Strip any quotes from the given string. * * @param string $value * @return string */ public function stripQuotes(string $value) { return Str::startsWith($value, ['"', '\'']) ? substr($value, 1, -1) : $value; } } Compilers/Concerns/CompilesAuthorizations.php000064400000004706150145556460015525 0ustar00check{$expression}): ?>"; } /** * Compile the cannot statements into valid PHP. * * @param string $expression * @return string */ protected function compileCannot($expression) { return "denies{$expression}): ?>"; } /** * Compile the canany statements into valid PHP. * * @param string $expression * @return string */ protected function compileCanany($expression) { return "any{$expression}): ?>"; } /** * Compile the else-can statements into valid PHP. * * @param string $expression * @return string */ protected function compileElsecan($expression) { return "check{$expression}): ?>"; } /** * Compile the else-cannot statements into valid PHP. * * @param string $expression * @return string */ protected function compileElsecannot($expression) { return "denies{$expression}): ?>"; } /** * Compile the else-canany statements into valid PHP. * * @param string $expression * @return string */ protected function compileElsecanany($expression) { return "any{$expression}): ?>"; } /** * Compile the end-can statements into valid PHP. * * @return string */ protected function compileEndcan() { return ''; } /** * Compile the end-cannot statements into valid PHP. * * @return string */ protected function compileEndcannot() { return ''; } /** * Compile the end-canany statements into valid PHP. * * @return string */ protected function compileEndcanany() { return ''; } } Compilers/Concerns/CompilesClasses.php000064400000000676150145556460014101 0ustar00\""; } } Compilers/Concerns/CompilesComments.php000064400000000635150145556460014264 0ustar00contentTags[0], $this->contentTags[1]); return preg_replace($pattern, '', $value); } } Compilers/Concerns/CompilesComponents.php000064400000014732150145556460014627 0ustar00startComponent{$expression}; ?>"; } /** * Get a new component hash for a component name. * * @param string $component * @return string */ public static function newComponentHash(string $component) { static::$componentHashStack[] = $hash = hash('xxh128', $component); return $hash; } /** * Compile a class component opening. * * @param string $component * @param string $alias * @param string $data * @param string $hash * @return string */ public static function compileClassComponentOpening(string $component, string $alias, string $data, string $hash) { return implode("\n", [ '', '', 'all() : [])); ?>', 'withName('.$alias.'); ?>', 'shouldRender()): ?>', 'startComponent($component->resolveView(), $component->data()); ?>', ]); } /** * Compile the end-component statements into valid PHP. * * @return string */ protected function compileEndComponent() { return 'renderComponent(); ?>'; } /** * Compile the end-component statements into valid PHP. * * @return string */ public function compileEndComponentClass() { $hash = array_pop(static::$componentHashStack); return $this->compileEndComponent()."\n".implode("\n", [ '', '', '', '', '', '', '', '', '', ]); } /** * Compile the slot statements into valid PHP. * * @param string $expression * @return string */ protected function compileSlot($expression) { return "slot{$expression}; ?>"; } /** * Compile the end-slot statements into valid PHP. * * @return string */ protected function compileEndSlot() { return 'endSlot(); ?>'; } /** * Compile the component-first statements into valid PHP. * * @param string $expression * @return string */ protected function compileComponentFirst($expression) { return "startComponentFirst{$expression}; ?>"; } /** * Compile the end-component-first statements into valid PHP. * * @return string */ protected function compileEndComponentFirst() { return $this->compileEndComponent(); } /** * Compile the prop statement into valid PHP. * * @param string $expression * @return string */ protected function compileProps($expression) { return "all() as \$__key => \$__value) { if (in_array(\$__key, \$__propNames)) { \$\$__key = \$\$__key ?? \$__value; } else { \$__newAttributes[\$__key] = \$__value; } } \$attributes = new \Illuminate\View\ComponentAttributeBag(\$__newAttributes); unset(\$__propNames); unset(\$__newAttributes); foreach (array_filter({$expression}, 'is_string', ARRAY_FILTER_USE_KEY) as \$__key => \$__value) { \$\$__key = \$\$__key ?? \$__value; } \$__defined_vars = get_defined_vars(); foreach (\$attributes->all() as \$__key => \$__value) { if (array_key_exists(\$__key, \$__defined_vars)) unset(\$\$__key); } unset(\$__defined_vars); ?>"; } /** * Compile the aware statement into valid PHP. * * @param string $expression * @return string */ protected function compileAware($expression) { return " \$__value) { \$__consumeVariable = is_string(\$__key) ? \$__key : \$__value; \$\$__consumeVariable = is_string(\$__key) ? \$__env->getConsumableComponentData(\$__key, \$__value) : \$__env->getConsumableComponentData(\$__value); } ?>"; } /** * Sanitize the given component attribute value. * * @param mixed $value * @return mixed */ public static function sanitizeComponentAttribute($value) { if ($value instanceof CanBeEscapedWhenCastToString) { return $value->escapeWhenCastingToString(); } return is_string($value) || (is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString')) ? e($value) : $value; } } Compilers/Concerns/CompilesConditionals.php000064400000022425150145556460015126 0ustar00guard{$guard}->check()): ?>"; } /** * Compile the else-auth statements into valid PHP. * * @param string|null $guard * @return string */ protected function compileElseAuth($guard = null) { $guard = is_null($guard) ? '()' : $guard; return "guard{$guard}->check()): ?>"; } /** * Compile the end-auth statements into valid PHP. * * @return string */ protected function compileEndAuth() { return ''; } /** * Compile the env statements into valid PHP. * * @param string $environments * @return string */ protected function compileEnv($environments) { return "environment{$environments}): ?>"; } /** * Compile the end-env statements into valid PHP. * * @return string */ protected function compileEndEnv() { return ''; } /** * Compile the production statements into valid PHP. * * @return string */ protected function compileProduction() { return "environment('production')): ?>"; } /** * Compile the end-production statements into valid PHP. * * @return string */ protected function compileEndProduction() { return ''; } /** * Compile the if-guest statements into valid PHP. * * @param string|null $guard * @return string */ protected function compileGuest($guard = null) { $guard = is_null($guard) ? '()' : $guard; return "guard{$guard}->guest()): ?>"; } /** * Compile the else-guest statements into valid PHP. * * @param string|null $guard * @return string */ protected function compileElseGuest($guard = null) { $guard = is_null($guard) ? '()' : $guard; return "guard{$guard}->guest()): ?>"; } /** * Compile the end-guest statements into valid PHP. * * @return string */ protected function compileEndGuest() { return ''; } /** * Compile the has-section statements into valid PHP. * * @param string $expression * @return string */ protected function compileHasSection($expression) { return "yieldContent{$expression}))): ?>"; } /** * Compile the section-missing statements into valid PHP. * * @param string $expression * @return string */ protected function compileSectionMissing($expression) { return "yieldContent{$expression}))): ?>"; } /** * Compile the if statements into valid PHP. * * @param string $expression * @return string */ protected function compileIf($expression) { return ""; } /** * Compile the unless statements into valid PHP. * * @param string $expression * @return string */ protected function compileUnless($expression) { return ""; } /** * Compile the else-if statements into valid PHP. * * @param string $expression * @return string */ protected function compileElseif($expression) { return ""; } /** * Compile the else statements into valid PHP. * * @return string */ protected function compileElse() { return ''; } /** * Compile the end-if statements into valid PHP. * * @return string */ protected function compileEndif() { return ''; } /** * Compile the end-unless statements into valid PHP. * * @return string */ protected function compileEndunless() { return ''; } /** * Compile the if-isset statements into valid PHP. * * @param string $expression * @return string */ protected function compileIsset($expression) { return ""; } /** * Compile the end-isset statements into valid PHP. * * @return string */ protected function compileEndIsset() { return ''; } /** * Compile the switch statements into valid PHP. * * @param string $expression * @return string */ protected function compileSwitch($expression) { $this->firstCaseInSwitch = true; return "firstCaseInSwitch) { $this->firstCaseInSwitch = false; return "case {$expression}: ?>"; } return ""; } /** * Compile the default statements in switch case into valid PHP. * * @return string */ protected function compileDefault() { return ''; } /** * Compile the end switch statements into valid PHP. * * @return string */ protected function compileEndSwitch() { return ''; } /** * Compile a once block into valid PHP. * * @param string|null $id * @return string */ protected function compileOnce($id = null) { $id = $id ? $this->stripParentheses($id) : "'".(string) Str::uuid()."'"; return 'hasRenderedOnce('.$id.')): $__env->markAsRenderedOnce('.$id.'); ?>'; } /** * Compile an end-once block into valid PHP. * * @return string */ public function compileEndOnce() { return ''; } /** * Compile a boolean value into a raw true / false value for embedding into HTML attributes or JavaScript. * * @param bool $condition * @return string */ protected function compileBool($condition) { return ""; } /** * Compile a checked block into valid PHP. * * @param string $condition * @return string */ protected function compileChecked($condition) { return ""; } /** * Compile a disabled block into valid PHP. * * @param string $condition * @return string */ protected function compileDisabled($condition) { return ""; } /** * Compile a required block into valid PHP. * * @param string $condition * @return string */ protected function compileRequired($condition) { return ""; } /** * Compile a readonly block into valid PHP. * * @param string $condition * @return string */ protected function compileReadonly($condition) { return ""; } /** * Compile a selected block into valid PHP. * * @param string $condition * @return string */ protected function compileSelected($condition) { return ""; } /** * Compile the push statements into valid PHP. * * @param string $expression * @return string */ protected function compilePushIf($expression) { $parts = explode(',', $this->stripParentheses($expression), 2); return "startPush({$parts[1]}); ?>"; } /** * Compile the else-if push statements into valid PHP. * * @param string $expression * @return string */ protected function compileElsePushIf($expression) { $parts = explode(',', $this->stripParentheses($expression), 2); return "stopPush(); elseif({$parts[0]}): \$__env->startPush({$parts[1]}); ?>"; } /** * Compile the else push statements into valid PHP. * * @param string $expression * @return string */ protected function compileElsePush($expression) { return "stopPush(); else: \$__env->startPush{$expression}; ?>"; } /** * Compile the end-push statements into valid PHP. * * @return string */ protected function compileEndPushIf() { return 'stopPush(); endif; ?>'; } } Compilers/Concerns/CompilesEchos.php000064400000011000150145556460013524 0ustar00firstClosureParameterType($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) : "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) : "{$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] : "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 "".$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); } if (is_iterable($value) && isset($this->echoHandlers['iterable'])) { return call_user_func($this->echoHandlers['iterable'], $value); } return $value; } } Compilers/Concerns/CompilesErrors.php000064400000001645150145556460013755 0ustar00stripParentheses($expression); return 'getBag($__errorArgs[1] ?? \'default\'); if ($__bag->has($__errorArgs[0])) : if (isset($message)) { $__messageOriginal = $message; } $message = $__bag->first($__errorArgs[0]); ?>'; } /** * Compile the enderror statements into valid PHP. * * @param string $expression * @return string */ protected function compileEnderror($expression) { return ''; } } Compilers/Concerns/CompilesFragments.php000064400000001331150145556460014417 0ustar00lastFragment = trim($expression, "()'\" "); return "startFragment{$expression}; ?>"; } /** * Compile the end-fragment statements into valid PHP. * * @return string */ protected function compileEndfragment() { return 'stopFragment(); ?>'; } } Compilers/Concerns/CompilesHelpers.php000064400000003076150145556460014103 0ustar00'; } /** * Compile the "dd" statements into valid PHP. * * @param string $arguments * @return string */ protected function compileDd($arguments) { return ""; } /** * Compile the "dump" statements into valid PHP. * * @param string $arguments * @return string */ protected function compileDump($arguments) { return ""; } /** * Compile the method statements into valid PHP. * * @param string $method * @return string */ protected function compileMethod($method) { return ""; } /** * Compile the "vite" statements into valid PHP. * * @param string|null $arguments * @return string */ protected function compileVite($arguments) { $arguments ??= '()'; $class = Vite::class; return ""; } /** * Compile the "viteReactRefresh" statements into valid PHP. * * @return string */ protected function compileViteReactRefresh() { $class = Vite::class; return "reactRefresh(); ?>"; } } Compilers/Concerns/CompilesIncludes.php000064400000004601150145556460014242 0ustar00renderEach{$expression}; ?>"; } /** * Compile the include statements into valid PHP. * * @param string $expression * @return string */ protected function compileInclude($expression) { $expression = $this->stripParentheses($expression); return "make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; } /** * Compile the include-if statements into valid PHP. * * @param string $expression * @return string */ protected function compileIncludeIf($expression) { $expression = $this->stripParentheses($expression); return "exists({$expression})) echo \$__env->make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; } /** * Compile the include-when statements into valid PHP. * * @param string $expression * @return string */ protected function compileIncludeWhen($expression) { $expression = $this->stripParentheses($expression); return "renderWhen($expression, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path'])); ?>"; } /** * Compile the include-unless statements into valid PHP. * * @param string $expression * @return string */ protected function compileIncludeUnless($expression) { $expression = $this->stripParentheses($expression); return "renderUnless($expression, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path'])); ?>"; } /** * Compile the include-first statements into valid PHP. * * @param string $expression * @return string */ protected function compileIncludeFirst($expression) { $expression = $this->stripParentheses($expression); return "first({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; } } Compilers/Concerns/CompilesInjections.php000064400000000771150145556460014605 0ustar00"; } } Compilers/Concerns/CompilesJs.php000064400000000677150145556460013061 0ustar00toHtml() ?>", Js::class, $this->stripParentheses($expression) ); } } Compilers/Concerns/CompilesJson.php000064400000001325150145556460013405 0ustar00stripParentheses($expression)); $options = isset($parts[1]) ? trim($parts[1]) : $this->encodingOptions; $depth = isset($parts[2]) ? trim($parts[2]) : 512; return ""; } } Compilers/Concerns/CompilesLayouts.php000064400000006013150145556460014133 0ustar00stripParentheses($expression); $echo = "make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; $this->footer[] = $echo; return ''; } /** * Compile the extends-first statements into valid PHP. * * @param string $expression * @return string */ protected function compileExtendsFirst($expression) { $expression = $this->stripParentheses($expression); $echo = "first({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>"; $this->footer[] = $echo; return ''; } /** * Compile the section statements into valid PHP. * * @param string $expression * @return string */ protected function compileSection($expression) { $this->lastSection = trim($expression, "()'\" "); return "startSection{$expression}; ?>"; } /** * Replace the @parent directive to a placeholder. * * @return string */ protected function compileParent() { $escapedLastSection = strtr($this->lastSection, ['\\' => '\\\\', "'" => "\\'"]); return ""; } /** * Compile the yield statements into valid PHP. * * @param string $expression * @return string */ protected function compileYield($expression) { return "yieldContent{$expression}; ?>"; } /** * Compile the show statements into valid PHP. * * @return string */ protected function compileShow() { return 'yieldSection(); ?>'; } /** * Compile the append statements into valid PHP. * * @return string */ protected function compileAppend() { return 'appendSection(); ?>'; } /** * Compile the overwrite statements into valid PHP. * * @return string */ protected function compileOverwrite() { return 'stopSection(true); ?>'; } /** * Compile the stop statements into valid PHP. * * @return string */ protected function compileStop() { return 'stopSection(); ?>'; } /** * Compile the end-section statements into valid PHP. * * @return string */ protected function compileEndsection() { return 'stopSection(); ?>'; } } Compilers/Concerns/CompilesLoops.php000064400000011503150145556460013567 0ustar00forElseCounter; preg_match('/\( *(.+) +as +(.+)\)$/is', $expression ?? '', $matches); if (count($matches) === 0) { throw new ViewCompilationException('Malformed @forelse statement.'); } $iteratee = trim($matches[1]); $iteration = trim($matches[2]); $initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);"; $iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();'; return ""; } /** * Compile the for-else-empty and empty statements into valid PHP. * * @param string $expression * @return string */ protected function compileEmpty($expression) { if ($expression) { return ""; } $empty = '$__empty_'.$this->forElseCounter--; return "popLoop(); \$loop = \$__env->getLastLoop(); if ({$empty}): ?>"; } /** * Compile the end-for-else statements into valid PHP. * * @return string */ protected function compileEndforelse() { return ''; } /** * Compile the end-empty statements into valid PHP. * * @return string */ protected function compileEndEmpty() { return ''; } /** * Compile the for statements into valid PHP. * * @param string $expression * @return string */ protected function compileFor($expression) { return ""; } /** * Compile the for-each statements into valid PHP. * * @param string|null $expression * @return string * * @throws \Illuminate\Contracts\View\ViewCompilationException */ protected function compileForeach($expression) { preg_match('/\( *(.+) +as +(.*)\)$/is', $expression ?? '', $matches); if (count($matches) === 0) { throw new ViewCompilationException('Malformed @foreach statement.'); } $iteratee = trim($matches[1]); $iteration = trim($matches[2]); $initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);"; $iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();'; return ""; } /** * Compile the break statements into valid PHP. * * @param string $expression * @return string */ protected function compileBreak($expression) { if ($expression) { preg_match('/\(\s*(-?\d+)\s*\)$/', $expression, $matches); return $matches ? '' : ""; } return ''; } /** * Compile the continue statements into valid PHP. * * @param string $expression * @return string */ protected function compileContinue($expression) { if ($expression) { preg_match('/\(\s*(-?\d+)\s*\)$/', $expression, $matches); return $matches ? '' : ""; } return ''; } /** * Compile the end-for statements into valid PHP. * * @return string */ protected function compileEndfor() { return ''; } /** * Compile the end-for-each statements into valid PHP. * * @return string */ protected function compileEndforeach() { return 'popLoop(); $loop = $__env->getLastLoop(); ?>'; } /** * Compile the while statements into valid PHP. * * @param string $expression * @return string */ protected function compileWhile($expression) { return ""; } /** * Compile the end-while statements into valid PHP. * * @return string */ protected function compileEndwhile() { return ''; } } Compilers/Concerns/CompilesRawPhp.php000064400000001154150145556460013675 0ustar00"; } return '@php'; } /** * Compile the unset statements into valid PHP. * * @param string $expression * @return string */ protected function compileUnset($expression) { return ""; } } Compilers/Concerns/CompilesSessions.php000064400000001765150145556460014312 0ustar00stripParentheses($expression); return 'has($__sessionArgs[0])) : if (isset($value)) { $__sessionPrevious[] = $value; } $value = session()->get($__sessionArgs[0]); ?>'; } /** * Compile the endsession statements into valid PHP. * * @param string $expression * @return string */ protected function compileEndsession($expression) { return ''; } } Compilers/Concerns/CompilesStacks.php000064400000005351150145556460013727 0ustar00yieldPushContent{$expression}; ?>"; } /** * Compile the push statements into valid PHP. * * @param string $expression * @return string */ protected function compilePush($expression) { return "startPush{$expression}; ?>"; } /** * Compile the push-once statements into valid PHP. * * @param string $expression * @return string */ protected function compilePushOnce($expression) { $parts = explode(',', $this->stripParentheses($expression), 2); [$stack, $id] = [$parts[0], $parts[1] ?? '']; $id = trim($id) ?: "'".(string) Str::uuid()."'"; return 'hasRenderedOnce('.$id.')): $__env->markAsRenderedOnce('.$id.'); $__env->startPush('.$stack.'); ?>'; } /** * Compile the end-push statements into valid PHP. * * @return string */ protected function compileEndpush() { return 'stopPush(); ?>'; } /** * Compile the end-push-once statements into valid PHP. * * @return string */ protected function compileEndpushOnce() { return 'stopPush(); endif; ?>'; } /** * Compile the prepend statements into valid PHP. * * @param string $expression * @return string */ protected function compilePrepend($expression) { return "startPrepend{$expression}; ?>"; } /** * Compile the prepend-once statements into valid PHP. * * @param string $expression * @return string */ protected function compilePrependOnce($expression) { $parts = explode(',', $this->stripParentheses($expression), 2); [$stack, $id] = [$parts[0], $parts[1] ?? '']; $id = trim($id) ?: "'".(string) Str::uuid()."'"; return 'hasRenderedOnce('.$id.')): $__env->markAsRenderedOnce('.$id.'); $__env->startPrepend('.$stack.'); ?>'; } /** * Compile the end-prepend statements into valid PHP. * * @return string */ protected function compileEndprepend() { return 'stopPrepend(); ?>'; } /** * Compile the end-prepend-once statements into valid PHP. * * @return string */ protected function compileEndprependOnce() { return 'stopPrepend(); endif; ?>'; } } Compilers/Concerns/CompilesStyles.php000064400000000673150145556460013764 0ustar00\""; } } Compilers/Concerns/CompilesTranslations.php000064400000002035150145556460015154 0ustar00startTranslation(); ?>'; } elseif ($expression[1] === '[') { return "startTranslation{$expression}; ?>"; } return "get{$expression}; ?>"; } /** * Compile the end-lang statements into valid PHP. * * @return string */ protected function compileEndlang() { return 'renderTranslation(); ?>'; } /** * Compile the choice statements into valid PHP. * * @param string $expression * @return string */ protected function compileChoice($expression) { return "choice{$expression}; ?>"; } } Compilers/Concerns/CompilesUseStatements.php000064400000001024150145556460015274 0ustar00"; } } Component.php000064400000031330150145556460007232 0ustar00 */ protected static $bladeViewCache = []; /** * The cache of public property names, keyed by class. * * @var array */ protected static $propertyCache = []; /** * The cache of public method names, keyed by class. * * @var array */ protected static $methodCache = []; /** * The cache of constructor parameters, keyed by class. * * @var array> */ protected static $constructorParametersCache = []; /** * The cache of ignored parameter names. * * @var array */ protected static $ignoredParameterNames = []; /** * Get the view / view contents that represent the component. * * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string */ abstract public function render(); /** * Resolve the component instance with the given data. * * @param array $data * @return static */ public static function resolve($data) { if (static::$componentsResolver) { return call_user_func(static::$componentsResolver, static::class, $data); } $parameters = static::extractConstructorParameters(); $dataKeys = array_keys($data); if (empty(array_diff($parameters, $dataKeys))) { return new static(...array_intersect_key($data, array_flip($parameters))); } return Container::getInstance()->make(static::class, $data); } /** * Extract the constructor parameters for the component. * * @return array */ protected static function extractConstructorParameters() { if (! isset(static::$constructorParametersCache[static::class])) { $class = new ReflectionClass(static::class); $constructor = $class->getConstructor(); static::$constructorParametersCache[static::class] = $constructor ? collect($constructor->getParameters())->map->getName()->all() : []; } return static::$constructorParametersCache[static::class]; } /** * Resolve the Blade view or view file that should be used when rendering the component. * * @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string */ public function resolveView() { $view = $this->render(); if ($view instanceof ViewContract) { return $view; } if ($view instanceof Htmlable) { return $view; } $resolver = function ($view) { if ($view instanceof ViewContract) { return $view; } return $this->extractBladeViewFromString($view); }; return $view instanceof Closure ? function (array $data = []) use ($view, $resolver) { return $resolver($view($data)); } : $resolver($view); } /** * Create a Blade view with the raw component string content. * * @param string $contents * @return string */ protected function extractBladeViewFromString($contents) { $key = sprintf('%s::%s', static::class, $contents); if (isset(static::$bladeViewCache[$key])) { return static::$bladeViewCache[$key]; } if ($this->factory()->exists($contents)) { return static::$bladeViewCache[$key] = $contents; } return static::$bladeViewCache[$key] = $this->createBladeViewFromString($this->factory(), $contents); } /** * Create a Blade view with the raw component string content. * * @param \Illuminate\Contracts\View\Factory $factory * @param string $contents * @return string */ protected function createBladeViewFromString($factory, $contents) { $factory->addNamespace( '__components', $directory = Container::getInstance()['config']->get('view.compiled') ); if (! is_file($viewFile = $directory.'/'.hash('xxh128', $contents).'.blade.php')) { if (! is_dir($directory)) { mkdir($directory, 0755, true); } file_put_contents($viewFile, $contents); } return '__components::'.basename($viewFile, '.blade.php'); } /** * Get the data that should be supplied to the view. * * @author Freek Van der Herten * @author Brent Roose * * @return array */ public function data() { $this->attributes = $this->attributes ?: $this->newAttributeBag(); return array_merge($this->extractPublicProperties(), $this->extractPublicMethods()); } /** * Extract the public properties for the component. * * @return array */ protected function extractPublicProperties() { $class = get_class($this); if (! isset(static::$propertyCache[$class])) { $reflection = new ReflectionClass($this); static::$propertyCache[$class] = collect($reflection->getProperties(ReflectionProperty::IS_PUBLIC)) ->reject(function (ReflectionProperty $property) { return $property->isStatic(); }) ->reject(function (ReflectionProperty $property) { return $this->shouldIgnore($property->getName()); }) ->map(function (ReflectionProperty $property) { return $property->getName(); })->all(); } $values = []; foreach (static::$propertyCache[$class] as $property) { $values[$property] = $this->{$property}; } return $values; } /** * Extract the public methods for the component. * * @return array */ protected function extractPublicMethods() { $class = get_class($this); if (! isset(static::$methodCache[$class])) { $reflection = new ReflectionClass($this); static::$methodCache[$class] = collect($reflection->getMethods(ReflectionMethod::IS_PUBLIC)) ->reject(function (ReflectionMethod $method) { return $this->shouldIgnore($method->getName()); }) ->map(function (ReflectionMethod $method) { return $method->getName(); }); } $values = []; foreach (static::$methodCache[$class] as $method) { $values[$method] = $this->createVariableFromMethod(new ReflectionMethod($this, $method)); } return $values; } /** * Create a callable variable from the given method. * * @param \ReflectionMethod $method * @return mixed */ protected function createVariableFromMethod(ReflectionMethod $method) { return $method->getNumberOfParameters() === 0 ? $this->createInvokableVariable($method->getName()) : Closure::fromCallable([$this, $method->getName()]); } /** * Create an invokable, toStringable variable for the given component method. * * @param string $method * @return \Illuminate\View\InvokableComponentVariable */ protected function createInvokableVariable(string $method) { return new InvokableComponentVariable(function () use ($method) { return $this->{$method}(); }); } /** * Determine if the given property / method should be ignored. * * @param string $name * @return bool */ protected function shouldIgnore($name) { return str_starts_with($name, '__') || in_array($name, $this->ignoredMethods()); } /** * Get the methods that should be ignored. * * @return array */ protected function ignoredMethods() { return array_merge([ 'data', 'render', 'resolve', 'resolveView', 'shouldRender', 'view', 'withName', 'withAttributes', 'flushCache', 'forgetFactory', 'forgetComponentsResolver', 'resolveComponentsUsing', ], $this->except); } /** * Set the component alias name. * * @param string $name * @return $this */ public function withName($name) { $this->componentName = $name; return $this; } /** * Set the extra attributes that the component should make available. * * @param array $attributes * @return $this */ public function withAttributes(array $attributes) { $this->attributes = $this->attributes ?: $this->newAttributeBag(); $this->attributes->setAttributes($attributes); return $this; } /** * Get a new attribute bag instance. * * @param array $attributes * @return \Illuminate\View\ComponentAttributeBag */ protected function newAttributeBag(array $attributes = []) { return new ComponentAttributeBag($attributes); } /** * Determine if the component should be rendered. * * @return bool */ public function shouldRender() { return true; } /** * Get the evaluated view contents for the given view. * * @param string|null $view * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View */ public function view($view, $data = [], $mergeData = []) { return $this->factory()->make($view, $data, $mergeData); } /** * Get the view factory instance. * * @return \Illuminate\Contracts\View\Factory */ protected function factory() { if (is_null(static::$factory)) { static::$factory = Container::getInstance()->make('view'); } return static::$factory; } /** * Get the cached set of anonymous component constructor parameter names to exclude. * * @return array */ public static function ignoredParameterNames() { if (! isset(static::$ignoredParameterNames[static::class])) { $constructor = (new ReflectionClass( static::class ))->getConstructor(); if (! $constructor) { return static::$ignoredParameterNames[static::class] = []; } static::$ignoredParameterNames[static::class] = collect($constructor->getParameters()) ->map->getName() ->all(); } return static::$ignoredParameterNames[static::class]; } /** * Flush the component's cached state. * * @return void */ public static function flushCache() { static::$bladeViewCache = []; static::$constructorParametersCache = []; static::$methodCache = []; static::$propertyCache = []; } /** * Forget the component's factory instance. * * @return void */ public static function forgetFactory() { static::$factory = null; } /** * Forget the component's resolver callback. * * @return void * * @internal */ public static function forgetComponentsResolver() { static::$componentsResolver = null; } /** * Set the callback that should be used to resolve components within views. * * @param \Closure(string $component, array $data): Component $resolver * @return void * * @internal */ public static function resolveComponentsUsing($resolver) { static::$componentsResolver = $resolver; } } ComponentAttributeBag.php000064400000030653150145556460011537 0ustar00setAttributes($attributes); } /** * Get all of the attribute values. * * @return array */ public function all() { return $this->attributes; } /** * Get the first attribute's value. * * @param mixed $default * @return mixed */ public function first($default = null) { return $this->getIterator()->current() ?? value($default); } /** * Get a given attribute from the attribute array. * * @param string $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { return $this->attributes[$key] ?? value($default); } /** * Determine if a given attribute exists in the attribute array. * * @param array|string $key * @return bool */ public function has($key) { $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $value) { if (! array_key_exists($value, $this->attributes)) { return false; } } return true; } /** * Determine if any of the keys exist in the attribute array. * * @param array|string $key * @return bool */ public function hasAny($key) { if (! count($this->attributes)) { return false; } $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $value) { if ($this->has($value)) { return true; } } return false; } /** * Determine if a given attribute is missing from the attribute array. * * @param string $key * @return bool */ public function missing($key) { return ! $this->has($key); } /** * Only include the given attribute from the attribute array. * * @param mixed $keys * @return static */ public function only($keys) { if (is_null($keys)) { $values = $this->attributes; } else { $keys = Arr::wrap($keys); $values = Arr::only($this->attributes, $keys); } return new static($values); } /** * Exclude the given attribute from the attribute array. * * @param mixed|array $keys * @return static */ public function except($keys) { if (is_null($keys)) { $values = $this->attributes; } else { $keys = Arr::wrap($keys); $values = Arr::except($this->attributes, $keys); } return new static($values); } /** * Filter the attributes, returning a bag of attributes that pass the filter. * * @param callable $callback * @return static */ public function filter($callback) { return new static((new Collection($this->attributes))->filter($callback)->all()); } /** * Return a bag of attributes that have keys starting with the given value / pattern. * * @param string|string[] $needles * @return static */ public function whereStartsWith($needles) { return $this->filter(function ($value, $key) use ($needles) { return Str::startsWith($key, $needles); }); } /** * Return a bag of attributes with keys that do not start with the given value / pattern. * * @param string|string[] $needles * @return static */ public function whereDoesntStartWith($needles) { return $this->filter(function ($value, $key) use ($needles) { return ! Str::startsWith($key, $needles); }); } /** * Return a bag of attributes that have keys starting with the given value / pattern. * * @param string|string[] $needles * @return static */ public function thatStartWith($needles) { return $this->whereStartsWith($needles); } /** * Only include the given attribute from the attribute array. * * @param mixed|array $keys * @return static */ public function onlyProps($keys) { return $this->only(static::extractPropNames($keys)); } /** * Exclude the given attribute from the attribute array. * * @param mixed|array $keys * @return static */ public function exceptProps($keys) { return $this->except(static::extractPropNames($keys)); } /** * Conditionally merge classes into the attribute bag. * * @param mixed|array $classList * @return static */ public function class($classList) { $classList = Arr::wrap($classList); return $this->merge(['class' => Arr::toCssClasses($classList)]); } /** * Conditionally merge styles into the attribute bag. * * @param mixed|array $styleList * @return static */ public function style($styleList) { $styleList = Arr::wrap($styleList); return $this->merge(['style' => Arr::toCssStyles($styleList)]); } /** * Merge additional attributes / values into the attribute bag. * * @param array $attributeDefaults * @param bool $escape * @return static */ public function merge(array $attributeDefaults = [], $escape = true) { $attributeDefaults = array_map(function ($value) use ($escape) { return $this->shouldEscapeAttributeValue($escape, $value) ? e($value) : $value; }, $attributeDefaults); [$appendableAttributes, $nonAppendableAttributes] = (new Collection($this->attributes)) ->partition(function ($value, $key) use ($attributeDefaults) { return $key === 'class' || $key === 'style' || ( isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue ); }); $attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) { $defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue ? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape) : ($attributeDefaults[$key] ?? ''); if ($key === 'style') { $value = Str::finish($value, ';'); } return [$key => implode(' ', array_unique(array_filter([$defaultsValue, $value])))]; })->merge($nonAppendableAttributes)->all(); return new static(array_merge($attributeDefaults, $attributes)); } /** * Determine if the specific attribute value should be escaped. * * @param bool $escape * @param mixed $value * @return bool */ protected function shouldEscapeAttributeValue($escape, $value) { if (! $escape) { return false; } return ! is_object($value) && ! is_null($value) && ! is_bool($value); } /** * Create a new appendable attribute value. * * @param mixed $value * @return \Illuminate\View\AppendableAttributeValue */ public function prepends($value) { return new AppendableAttributeValue($value); } /** * Resolve an appendable attribute value default value. * * @param array $attributeDefaults * @param string $key * @param bool $escape * @return mixed */ protected function resolveAppendableAttributeDefault($attributeDefaults, $key, $escape) { if ($this->shouldEscapeAttributeValue($escape, $value = $attributeDefaults[$key]->value)) { $value = e($value); } return $value; } /** * Determine if the attribute bag is empty. * * @return bool */ public function isEmpty() { return trim((string) $this) === ''; } /** * Determine if the attribute bag is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Get all of the raw attributes. * * @return array */ public function getAttributes() { return $this->attributes; } /** * Set the underlying attributes. * * @param array $attributes * @return void */ public function setAttributes(array $attributes) { if (isset($attributes['attributes']) && $attributes['attributes'] instanceof self) { $parentBag = $attributes['attributes']; unset($attributes['attributes']); $attributes = $parentBag->merge($attributes, $escape = false)->getAttributes(); } $this->attributes = $attributes; } /** * Extract "prop" names from given keys. * * @param array $keys * @return array */ public static function extractPropNames(array $keys) { $props = []; foreach ($keys as $key => $default) { $key = is_numeric($key) ? $default : $key; $props[] = $key; $props[] = Str::kebab($key); } return $props; } /** * Get content as a string of HTML. * * @return string */ public function toHtml() { return (string) $this; } /** * Merge additional attributes / values into the attribute bag. * * @param array $attributeDefaults * @return \Illuminate\Support\HtmlString */ public function __invoke(array $attributeDefaults = []) { return new HtmlString((string) $this->merge($attributeDefaults)); } /** * Determine if the given offset exists. * * @param string $offset * @return bool */ public function offsetExists($offset): bool { return isset($this->attributes[$offset]); } /** * Get the value at the given offset. * * @param string $offset * @return mixed */ public function offsetGet($offset): mixed { return $this->get($offset); } /** * Set the value at a given offset. * * @param string $offset * @param mixed $value * @return void */ public function offsetSet($offset, $value): void { $this->attributes[$offset] = $value; } /** * Remove the value at the given offset. * * @param string $offset * @return void */ public function offsetUnset($offset): void { unset($this->attributes[$offset]); } /** * Get an iterator for the items. * * @return \ArrayIterator */ public function getIterator(): Traversable { return new ArrayIterator($this->attributes); } /** * Convert the object into a JSON serializable form. * * @return mixed */ public function jsonSerialize(): mixed { return $this->attributes; } /** * Implode the attributes into a single HTML ready string. * * @return string */ public function __toString() { $string = ''; foreach ($this->attributes as $key => $value) { if ($value === false || is_null($value)) { continue; } if ($value === true) { $value = $key === 'x-data' || str_starts_with($key, 'wire:') ? '' : $key; } $string .= ' '.$key.'="'.str_replace('"', '\\"', trim($value)).'"'; } return trim($string); } } ComponentSlot.php000064400000004322150145556460010075 0ustar00contents = $contents; $this->withAttributes($attributes); } /** * Set the extra attributes that the slot should make available. * * @param array $attributes * @return $this */ public function withAttributes(array $attributes) { $this->attributes = new ComponentAttributeBag($attributes); return $this; } /** * Get the slot's HTML string. * * @return string */ public function toHtml() { return $this->contents; } /** * Determine if the slot is empty. * * @return bool */ public function isEmpty() { return $this->contents === ''; } /** * Determine if the slot is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Determine if the slot has non-comment content. * * @param callable|string|null $callable * @return bool */ public function hasActualContent(callable|string|null $callable = null) { if (is_string($callable) && ! function_exists($callable)) { throw new InvalidArgumentException('Callable does not exist.'); } return filter_var( $this->contents, FILTER_CALLBACK, ['options' => $callable ?? fn ($input) => trim(preg_replace("//", '', $input))] ) !== ''; } /** * Get the slot's HTML string. * * @return string */ public function __toString() { return $this->toHtml(); } } Concerns/ManagesComponents.php000064400000012523150145556460012466 0ustar00componentStack[] = $view; $this->componentData[$this->currentComponent()] = $data; $this->slots[$this->currentComponent()] = []; } } /** * Get the first view that actually exists from the given list, and start a component. * * @param array $names * @param array $data * @return void */ public function startComponentFirst(array $names, array $data = []) { $name = Arr::first($names, function ($item) { return $this->exists($item); }); $this->startComponent($name, $data); } /** * Render the current component. * * @return string */ public function renderComponent() { $view = array_pop($this->componentStack); $this->currentComponentData = array_merge( $previousComponentData = $this->currentComponentData, $data = $this->componentData() ); try { $view = value($view, $data); if ($view instanceof View) { return $view->with($data)->render(); } elseif ($view instanceof Htmlable) { return $view->toHtml(); } else { return $this->make($view, $data)->render(); } } finally { $this->currentComponentData = $previousComponentData; } } /** * Get the data for the given component. * * @return array */ protected function componentData() { $defaultSlot = new ComponentSlot(trim(ob_get_clean())); $slots = array_merge([ '__default' => $defaultSlot, ], $this->slots[count($this->componentStack)]); return array_merge( $this->componentData[count($this->componentStack)], ['slot' => $defaultSlot], $this->slots[count($this->componentStack)], ['__laravel_slots' => $slots] ); } /** * Get an item from the component data that exists above the current component. * * @param string $key * @param mixed $default * @return mixed|null */ public function getConsumableComponentData($key, $default = null) { if (array_key_exists($key, $this->currentComponentData)) { return $this->currentComponentData[$key]; } $currentComponent = count($this->componentStack); if ($currentComponent === 0) { return value($default); } for ($i = $currentComponent - 1; $i >= 0; $i--) { $data = $this->componentData[$i] ?? []; if (array_key_exists($key, $data)) { return $data[$key]; } } return value($default); } /** * Start the slot rendering process. * * @param string $name * @param string|null $content * @param array $attributes * @return void */ public function slot($name, $content = null, $attributes = []) { if (func_num_args() === 2 || $content !== null) { $this->slots[$this->currentComponent()][$name] = $content; } elseif (ob_start()) { $this->slots[$this->currentComponent()][$name] = ''; $this->slotStack[$this->currentComponent()][] = [$name, $attributes]; } } /** * Save the slot content for rendering. * * @return void */ public function endSlot() { last($this->componentStack); $currentSlot = array_pop( $this->slotStack[$this->currentComponent()] ); [$currentName, $currentAttributes] = $currentSlot; $this->slots[$this->currentComponent()][$currentName] = new ComponentSlot( trim(ob_get_clean()), $currentAttributes ); } /** * Get the index for the current component. * * @return int */ protected function currentComponent() { return count($this->componentStack) - 1; } /** * Flush all of the component state. * * @return void */ protected function flushComponents() { $this->componentStack = []; $this->componentData = []; $this->currentComponentData = []; } } Concerns/ManagesEvents.php000064400000011766150145556460011615 0ustar00addViewEvent($view, $callback, 'creating: '); } return $creators; } /** * Register multiple view composers via an array. * * @param array $composers * @return array */ public function composers(array $composers) { $registered = []; foreach ($composers as $callback => $views) { $registered = array_merge($registered, $this->composer($views, $callback)); } return $registered; } /** * Register a view composer event. * * @param array|string $views * @param \Closure|string $callback * @return array */ public function composer($views, $callback) { $composers = []; foreach ((array) $views as $view) { $composers[] = $this->addViewEvent($view, $callback); } return $composers; } /** * Add an event for a given view. * * @param string $view * @param \Closure|string $callback * @param string $prefix * @return \Closure|null */ protected function addViewEvent($view, $callback, $prefix = 'composing: ') { $view = $this->normalizeName($view); if ($callback instanceof Closure) { $this->addEventListener($prefix.$view, $callback); return $callback; } elseif (is_string($callback)) { return $this->addClassEvent($view, $callback, $prefix); } } /** * Register a class based view composer. * * @param string $view * @param string $class * @param string $prefix * @return \Closure */ protected function addClassEvent($view, $class, $prefix) { $name = $prefix.$view; // When registering a class based view "composer", we will simply resolve the // classes from the application IoC container then call the compose method // on the instance. This allows for convenient, testable view composers. $callback = $this->buildClassEventCallback( $class, $prefix ); $this->addEventListener($name, $callback); return $callback; } /** * Build a class based container callback Closure. * * @param string $class * @param string $prefix * @return \Closure */ protected function buildClassEventCallback($class, $prefix) { [$class, $method] = $this->parseClassEvent($class, $prefix); // Once we have the class and method name, we can build the Closure to resolve // the instance out of the IoC container and call the method on it with the // given arguments that are passed to the Closure as the composer's data. return function () use ($class, $method) { return $this->container->make($class)->{$method}(...func_get_args()); }; } /** * Parse a class based composer name. * * @param string $class * @param string $prefix * @return array */ protected function parseClassEvent($class, $prefix) { return Str::parseCallback($class, $this->classEventMethodForPrefix($prefix)); } /** * Determine the class event method based on the given prefix. * * @param string $prefix * @return string */ protected function classEventMethodForPrefix($prefix) { return str_contains($prefix, 'composing') ? 'compose' : 'create'; } /** * Add a listener to the event dispatcher. * * @param string $name * @param \Closure $callback * @return void */ protected function addEventListener($name, $callback) { if (str_contains($name, '*')) { $callback = function ($name, array $data) use ($callback) { return $callback($data[0]); }; } $this->events->listen($name, $callback); } /** * Call the composer for a given view. * * @param \Illuminate\Contracts\View\View $view * @return void */ public function callComposer(ViewContract $view) { if ($this->events->hasListeners($event = 'composing: '.$view->name())) { $this->events->dispatch($event, [$view]); } } /** * Call the creator for a given view. * * @param \Illuminate\Contracts\View\View $view * @return void */ public function callCreator(ViewContract $view) { if ($this->events->hasListeners($event = 'creating: '.$view->name())) { $this->events->dispatch($event, [$view]); } } } Concerns/ManagesFragments.php000064400000003320150145556460012262 0ustar00fragmentStack[] = $fragment; } } /** * Stop injecting content into a fragment. * * @return string * * @throws \InvalidArgumentException */ public function stopFragment() { if (empty($this->fragmentStack)) { throw new InvalidArgumentException('Cannot end a fragment without first starting one.'); } $last = array_pop($this->fragmentStack); $this->fragments[$last] = ob_get_clean(); return $this->fragments[$last]; } /** * Get the contents of a fragment. * * @param string $name * @param string|null $default * @return mixed */ public function getFragment($name, $default = null) { return $this->getFragments()[$name] ?? $default; } /** * Get the entire array of rendered fragments. * * @return array */ public function getFragments() { return $this->fragments; } /** * Flush all of the fragments. * * @return void */ public function flushFragments() { $this->fragments = []; $this->fragmentStack = []; } } Concerns/ManagesLayouts.php000064400000013435150145556460012004 0ustar00sectionStack[] = $section; } } else { $this->extendSection($section, $content instanceof View ? $content : e($content)); } } /** * Inject inline content into a section. * * @param string $section * @param string $content * @return void */ public function inject($section, $content) { $this->startSection($section, $content); } /** * Stop injecting content into a section and return its contents. * * @return string */ public function yieldSection() { if (empty($this->sectionStack)) { return ''; } return $this->yieldContent($this->stopSection()); } /** * Stop injecting content into a section. * * @param bool $overwrite * @return string * * @throws \InvalidArgumentException */ public function stopSection($overwrite = false) { if (empty($this->sectionStack)) { throw new InvalidArgumentException('Cannot end a section without first starting one.'); } $last = array_pop($this->sectionStack); if ($overwrite) { $this->sections[$last] = ob_get_clean(); } else { $this->extendSection($last, ob_get_clean()); } return $last; } /** * Stop injecting content into a section and append it. * * @return string * * @throws \InvalidArgumentException */ public function appendSection() { if (empty($this->sectionStack)) { throw new InvalidArgumentException('Cannot end a section without first starting one.'); } $last = array_pop($this->sectionStack); if (isset($this->sections[$last])) { $this->sections[$last] .= ob_get_clean(); } else { $this->sections[$last] = ob_get_clean(); } return $last; } /** * Append content to a given section. * * @param string $section * @param string $content * @return void */ protected function extendSection($section, $content) { if (isset($this->sections[$section])) { $content = str_replace(static::parentPlaceholder($section), $content, $this->sections[$section]); } $this->sections[$section] = $content; } /** * Get the string contents of a section. * * @param string $section * @param string $default * @return string */ public function yieldContent($section, $default = '') { $sectionContent = $default instanceof View ? $default : e($default); if (isset($this->sections[$section])) { $sectionContent = $this->sections[$section]; } $sectionContent = str_replace('@@parent', '--parent--holder--', $sectionContent); return str_replace( '--parent--holder--', '@parent', str_replace(static::parentPlaceholder($section), '', $sectionContent) ); } /** * Get the parent placeholder for the current request. * * @param string $section * @return string */ public static function parentPlaceholder($section = '') { if (! isset(static::$parentPlaceholder[$section])) { $salt = static::parentPlaceholderSalt(); static::$parentPlaceholder[$section] = '##parent-placeholder-'.hash('xxh128', $salt.$section).'##'; } return static::$parentPlaceholder[$section]; } /** * Get the parent placeholder salt. * * @return string */ protected static function parentPlaceholderSalt() { if (! static::$parentPlaceholderSalt) { return static::$parentPlaceholderSalt = Str::random(40); } return static::$parentPlaceholderSalt; } /** * Check if section exists. * * @param string $name * @return bool */ public function hasSection($name) { return array_key_exists($name, $this->sections); } /** * Check if section does not exist. * * @param string $name * @return bool */ public function sectionMissing($name) { return ! $this->hasSection($name); } /** * Get the contents of a section. * * @param string $name * @param string|null $default * @return mixed */ public function getSection($name, $default = null) { return $this->getSections()[$name] ?? $default; } /** * Get the entire array of sections. * * @return array */ public function getSections() { return $this->sections; } /** * Flush all of the sections. * * @return void */ public function flushSections() { $this->sections = []; $this->sectionStack = []; } } Concerns/ManagesLoops.php000064400000004433150145556460011436 0ustar00loopsStack); $this->loopsStack[] = [ 'iteration' => 0, 'index' => 0, 'remaining' => $length ?? null, 'count' => $length, 'first' => true, 'last' => isset($length) ? $length == 1 : null, 'odd' => false, 'even' => true, 'depth' => count($this->loopsStack) + 1, 'parent' => $parent ? (object) $parent : null, ]; } /** * Increment the top loop's indices. * * @return void */ public function incrementLoopIndices() { $loop = $this->loopsStack[$index = count($this->loopsStack) - 1]; $this->loopsStack[$index] = array_merge($this->loopsStack[$index], [ 'iteration' => $loop['iteration'] + 1, 'index' => $loop['iteration'], 'first' => $loop['iteration'] == 0, 'odd' => ! $loop['odd'], 'even' => ! $loop['even'], 'remaining' => isset($loop['count']) ? $loop['remaining'] - 1 : null, 'last' => isset($loop['count']) ? $loop['iteration'] == $loop['count'] - 1 : null, ]); } /** * Pop a loop from the top of the loop stack. * * @return void */ public function popLoop() { array_pop($this->loopsStack); } /** * Get an instance of the last loop in the stack. * * @return \stdClass|null */ public function getLastLoop() { if ($last = Arr::last($this->loopsStack)) { return (object) $last; } } /** * Get the entire loop stack. * * @return array */ public function getLoopStack() { return $this->loopsStack; } } Concerns/ManagesStacks.php000064400000010333150145556460011566 0ustar00pushStack[] = $section; } } else { $this->extendPush($section, $content); } } /** * Stop injecting content into a push section. * * @return string * * @throws \InvalidArgumentException */ public function stopPush() { if (empty($this->pushStack)) { throw new InvalidArgumentException('Cannot end a push stack without first starting one.'); } return tap(array_pop($this->pushStack), function ($last) { $this->extendPush($last, ob_get_clean()); }); } /** * Append content to a given push section. * * @param string $section * @param string $content * @return void */ protected function extendPush($section, $content) { if (! isset($this->pushes[$section])) { $this->pushes[$section] = []; } if (! isset($this->pushes[$section][$this->renderCount])) { $this->pushes[$section][$this->renderCount] = $content; } else { $this->pushes[$section][$this->renderCount] .= $content; } } /** * Start prepending content into a push section. * * @param string $section * @param string $content * @return void */ public function startPrepend($section, $content = '') { if ($content === '') { if (ob_start()) { $this->pushStack[] = $section; } } else { $this->extendPrepend($section, $content); } } /** * Stop prepending content into a push section. * * @return string * * @throws \InvalidArgumentException */ public function stopPrepend() { if (empty($this->pushStack)) { throw new InvalidArgumentException('Cannot end a prepend operation without first starting one.'); } return tap(array_pop($this->pushStack), function ($last) { $this->extendPrepend($last, ob_get_clean()); }); } /** * Prepend content to a given stack. * * @param string $section * @param string $content * @return void */ protected function extendPrepend($section, $content) { if (! isset($this->prepends[$section])) { $this->prepends[$section] = []; } if (! isset($this->prepends[$section][$this->renderCount])) { $this->prepends[$section][$this->renderCount] = $content; } else { $this->prepends[$section][$this->renderCount] = $content.$this->prepends[$section][$this->renderCount]; } } /** * Get the string contents of a push section. * * @param string $section * @param string $default * @return string */ public function yieldPushContent($section, $default = '') { if (! isset($this->pushes[$section]) && ! isset($this->prepends[$section])) { return $default; } $output = ''; if (isset($this->prepends[$section])) { $output .= implode(array_reverse($this->prepends[$section])); } if (isset($this->pushes[$section])) { $output .= implode($this->pushes[$section]); } return $output; } /** * Flush all of the stacks. * * @return void */ public function flushStacks() { $this->pushes = []; $this->prepends = []; $this->pushStack = []; } } Concerns/ManagesTranslations.php000064400000001373150145556460013023 0ustar00translationReplacements = $replacements; } /** * Render the current translation. * * @return string */ public function renderTranslation() { return $this->container->make('translator')->get( trim(ob_get_clean()), $this->translationReplacements ); } } DynamicComponent.php000064400000011240150145556460010535 0ustar00component = $component; } /** * Get the view / contents that represent the component. * * @return \Illuminate\Contracts\View\View|string */ public function render() { $template = <<<'EOF' getAttributes())->mapWithKeys(function ($value, $key) { return [Illuminate\Support\Str::camel(str_replace([':', '.'], ' ', $key)) => $value]; })->all(), EXTR_SKIP); ?> {{ props }} {{ slots }} {{ defaultSlot }} EOF; return function ($data) use ($template) { $bindings = $this->bindings($class = $this->classForComponent()); return str_replace( [ '{{ component }}', '{{ props }}', '{{ bindings }}', '{{ attributes }}', '{{ slots }}', '{{ defaultSlot }}', ], [ $this->component, $this->compileProps($bindings), $this->compileBindings($bindings), class_exists($class) ? '{{ $attributes }}' : '', $this->compileSlots($data['__laravel_slots']), '{{ $slot ?? "" }}', ], $template ); }; } /** * Compile the @props directive for the component. * * @param array $bindings * @return string */ protected function compileProps(array $bindings) { if (empty($bindings)) { return ''; } return '@props('.'[\''.implode('\',\'', collect($bindings)->map(function ($dataKey) { return Str::camel($dataKey); })->all()).'\']'.')'; } /** * Compile the bindings for the component. * * @param array $bindings * @return string */ protected function compileBindings(array $bindings) { return collect($bindings)->map(function ($key) { return ':'.$key.'="$'.Str::camel(str_replace([':', '.'], ' ', $key)).'"'; })->implode(' '); } /** * Compile the slots for the component. * * @param array $slots * @return string */ protected function compileSlots(array $slots) { return collect($slots)->map(function ($slot, $name) { return $name === '__default' ? null : 'attributes).'>{{ $'.$name.' }}'; })->filter()->implode(PHP_EOL); } /** * Get the class for the current component. * * @return string */ protected function classForComponent() { if (isset(static::$componentClasses[$this->component])) { return static::$componentClasses[$this->component]; } return static::$componentClasses[$this->component] = $this->compiler()->componentClass($this->component); } /** * Get the names of the variables that should be bound to the component. * * @param string $class * @return array */ protected function bindings(string $class) { [$data, $attributes] = $this->compiler()->partitionDataAndAttributes($class, $this->attributes->getAttributes()); return array_keys($data->all()); } /** * Get an instance of the Blade tag compiler. * * @return \Illuminate\View\Compilers\ComponentTagCompiler */ protected function compiler() { if (! static::$compiler) { static::$compiler = new ComponentTagCompiler( Container::getInstance()->make('blade.compiler')->getClassComponentAliases(), Container::getInstance()->make('blade.compiler')->getClassComponentNamespaces(), Container::getInstance()->make('blade.compiler') ); } return static::$compiler; } } Engines/CompilerEngine.php000075500000010173150145556460011565 0ustar00 */ protected $compiledOrNotExpired = []; /** * Create a new compiler engine instance. * * @param \Illuminate\View\Compilers\CompilerInterface $compiler * @param \Illuminate\Filesystem\Filesystem|null $files * @return void */ public function __construct(CompilerInterface $compiler, ?Filesystem $files = null) { parent::__construct($files ?: new Filesystem); $this->compiler = $compiler; } /** * Get the evaluated contents of the view. * * @param string $path * @param array $data * @return string */ public function get($path, array $data = []) { $this->lastCompiled[] = $path; // If this given view has expired, which means it has simply been edited since // it was last compiled, we will re-compile the views so we can evaluate a // fresh copy of the view. We'll pass the compiler the path of the view. if (! isset($this->compiledOrNotExpired[$path]) && $this->compiler->isExpired($path)) { $this->compiler->compile($path); } // Once we have the path to the compiled file, we will evaluate the paths with // typical PHP just like any other templates. We also keep a stack of views // which have been rendered for right exception messages to be generated. try { $results = $this->evaluatePath($this->compiler->getCompiledPath($path), $data); } catch (ViewException $e) { if (! str($e->getMessage())->contains(['No such file or directory', 'File does not exist at path'])) { throw $e; } if (! isset($this->compiledOrNotExpired[$path])) { throw $e; } $this->compiler->compile($path); $results = $this->evaluatePath($this->compiler->getCompiledPath($path), $data); } $this->compiledOrNotExpired[$path] = true; array_pop($this->lastCompiled); return $results; } /** * Handle a view exception. * * @param \Throwable $e * @param int $obLevel * @return void * * @throws \Throwable */ protected function handleViewException(Throwable $e, $obLevel) { if ($e instanceof HttpException || $e instanceof HttpResponseException || $e instanceof RecordNotFoundException || $e instanceof RecordsNotFoundException) { parent::handleViewException($e, $obLevel); } $e = new ViewException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e); parent::handleViewException($e, $obLevel); } /** * Get the exception message for an exception. * * @param \Throwable $e * @return string */ protected function getMessage(Throwable $e) { return $e->getMessage().' (View: '.realpath(last($this->lastCompiled)).')'; } /** * Get the compiler implementation. * * @return \Illuminate\View\Compilers\CompilerInterface */ public function getCompiler() { return $this->compiler; } /** * Clear the cache of views that were compiled or not expired. * * @return void */ public function forgetCompiledOrNotExpired() { $this->compiledOrNotExpired = []; } } Engines/Engine.php000075500000000552150145556460010072 0ustar00lastRendered; } } Engines/EngineResolver.php000075500000002702150145556460011613 0ustar00forget($engine); $this->resolvers[$engine] = $resolver; } /** * Resolve an engine instance by name. * * @param string $engine * @return \Illuminate\Contracts\View\Engine * * @throws \InvalidArgumentException */ public function resolve($engine) { if (isset($this->resolved[$engine])) { return $this->resolved[$engine]; } if (isset($this->resolvers[$engine])) { return $this->resolved[$engine] = call_user_func($this->resolvers[$engine]); } throw new InvalidArgumentException("Engine [{$engine}] not found."); } /** * Remove a resolved engine. * * @param string $engine * @return void */ public function forget($engine) { unset($this->resolved[$engine]); } } Engines/FileEngine.php000064400000001403150145556460010663 0ustar00files = $files; } /** * Get the evaluated contents of the view. * * @param string $path * @param array $data * @return string */ public function get($path, array $data = []) { return $this->files->get($path); } } Engines/PhpEngine.php000075500000003531150145556460010542 0ustar00files = $files; } /** * Get the evaluated contents of the view. * * @param string $path * @param array $data * @return string */ public function get($path, array $data = []) { return $this->evaluatePath($path, $data); } /** * Get the evaluated contents of the view at the given path. * * @param string $path * @param array $data * @return string */ protected function evaluatePath($path, $data) { $obLevel = ob_get_level(); ob_start(); // We'll evaluate the contents of the view inside a try/catch block so we can // flush out any stray output that might get out before an error occurs or // an exception is thrown. This prevents any partial views from leaking. try { $this->files->getRequire($path, $data); } catch (Throwable $e) { $this->handleViewException($e, $obLevel); } return ltrim(ob_get_clean()); } /** * Handle a view exception. * * @param \Throwable $e * @param int $obLevel * @return void * * @throws \Throwable */ protected function handleViewException(Throwable $e, $obLevel) { while (ob_get_level() > $obLevel) { ob_end_clean(); } throw $e; } } Factory.php000075500000036533150145556460006714 0ustar00 'blade', 'php' => 'php', 'css' => 'file', 'html' => 'file', ]; /** * The view composer events. * * @var array */ protected $composers = []; /** * The number of active rendering operations. * * @var int */ protected $renderCount = 0; /** * The "once" block IDs that have been rendered. * * @var array */ protected $renderedOnce = []; /** * The cached array of engines for paths. * * @var array */ protected $pathEngineCache = []; /** * The cache of normalized names for views. * * @var array */ protected $normalizedNameCache = []; /** * Create a new view factory instance. * * @param \Illuminate\View\Engines\EngineResolver $engines * @param \Illuminate\View\ViewFinderInterface $finder * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */ public function __construct(EngineResolver $engines, ViewFinderInterface $finder, Dispatcher $events) { $this->finder = $finder; $this->events = $events; $this->engines = $engines; $this->share('__env', $this); } /** * Get the evaluated view contents for the given view. * * @param string $path * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View */ public function file($path, $data = [], $mergeData = []) { $data = array_merge($mergeData, $this->parseData($data)); return tap($this->viewInstance($path, $path, $data), function ($view) { $this->callCreator($view); }); } /** * Get the evaluated view contents for the given view. * * @param string $view * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View */ public function make($view, $data = [], $mergeData = []) { $path = $this->finder->find( $view = $this->normalizeName($view) ); // Next, we will create the view instance and call the view creator for the view // which can set any data, etc. Then we will return the view instance back to // the caller for rendering or performing other view manipulations on this. $data = array_merge($mergeData, $this->parseData($data)); return tap($this->viewInstance($view, $path, $data), function ($view) { $this->callCreator($view); }); } /** * Get the first view that actually exists from the given list. * * @param array $views * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return \Illuminate\Contracts\View\View * * @throws \InvalidArgumentException */ public function first(array $views, $data = [], $mergeData = []) { $view = Arr::first($views, function ($view) { return $this->exists($view); }); if (! $view) { throw new InvalidArgumentException('None of the views in the given array exist.'); } return $this->make($view, $data, $mergeData); } /** * Get the rendered content of the view based on a given condition. * * @param bool $condition * @param string $view * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return string */ public function renderWhen($condition, $view, $data = [], $mergeData = []) { if (! $condition) { return ''; } return $this->make($view, $this->parseData($data), $mergeData)->render(); } /** * Get the rendered content of the view based on the negation of a given condition. * * @param bool $condition * @param string $view * @param \Illuminate\Contracts\Support\Arrayable|array $data * @param array $mergeData * @return string */ public function renderUnless($condition, $view, $data = [], $mergeData = []) { return $this->renderWhen(! $condition, $view, $data, $mergeData); } /** * Get the rendered contents of a partial from a loop. * * @param string $view * @param array $data * @param string $iterator * @param string $empty * @return string */ public function renderEach($view, $data, $iterator, $empty = 'raw|') { $result = ''; // If is actually data in the array, we will loop through the data and append // an instance of the partial view to the final result HTML passing in the // iterated value of this data array, allowing the views to access them. if (count($data) > 0) { foreach ($data as $key => $value) { $result .= $this->make( $view, ['key' => $key, $iterator => $value] )->render(); } } // If there is no data in the array, we will render the contents of the empty // view. Alternatively, the "empty view" could be a raw string that begins // with "raw|" for convenience and to let this know that it is a string. else { $result = str_starts_with($empty, 'raw|') ? substr($empty, 4) : $this->make($empty)->render(); } return $result; } /** * Normalize a view name. * * @param string $name * @return string */ protected function normalizeName($name) { return $this->normalizedNameCache[$name] ??= ViewName::normalize($name); } /** * Parse the given data into a raw array. * * @param mixed $data * @return array */ protected function parseData($data) { return $data instanceof Arrayable ? $data->toArray() : $data; } /** * Create a new view instance from the given arguments. * * @param string $view * @param string $path * @param \Illuminate\Contracts\Support\Arrayable|array $data * @return \Illuminate\Contracts\View\View */ protected function viewInstance($view, $path, $data) { return new View($this, $this->getEngineFromPath($path), $view, $path, $data); } /** * Determine if a given view exists. * * @param string $view * @return bool */ public function exists($view) { try { $this->finder->find($view); } catch (InvalidArgumentException) { return false; } return true; } /** * Get the appropriate view engine for the given path. * * @param string $path * @return \Illuminate\Contracts\View\Engine * * @throws \InvalidArgumentException */ public function getEngineFromPath($path) { if (isset($this->pathEngineCache[$path])) { return $this->engines->resolve($this->pathEngineCache[$path]); } if (! $extension = $this->getExtension($path)) { throw new InvalidArgumentException("Unrecognized extension in file: {$path}."); } return $this->engines->resolve( $this->pathEngineCache[$path] = $this->extensions[$extension] ); } /** * Get the extension used by the view file. * * @param string $path * @return string|null */ protected function getExtension($path) { $extensions = array_keys($this->extensions); return Arr::first($extensions, function ($value) use ($path) { return str_ends_with($path, '.'.$value); }); } /** * Add a piece of shared data to the environment. * * @param array|string $key * @param mixed|null $value * @return mixed */ public function share($key, $value = null) { $keys = is_array($key) ? $key : [$key => $value]; foreach ($keys as $key => $value) { $this->shared[$key] = $value; } return $value; } /** * Increment the rendering counter. * * @return void */ public function incrementRender() { $this->renderCount++; } /** * Decrement the rendering counter. * * @return void */ public function decrementRender() { $this->renderCount--; } /** * Check if there are no active render operations. * * @return bool */ public function doneRendering() { return $this->renderCount == 0; } /** * Determine if the given once token has been rendered. * * @param string $id * @return bool */ public function hasRenderedOnce(string $id) { return isset($this->renderedOnce[$id]); } /** * Mark the given once token as having been rendered. * * @param string $id * @return void */ public function markAsRenderedOnce(string $id) { $this->renderedOnce[$id] = true; } /** * Add a location to the array of view locations. * * @param string $location * @return void */ public function addLocation($location) { $this->finder->addLocation($location); } /** * Prepend a location to the array of view locations. * * @param string $location * @return void */ public function prependLocation($location) { $this->finder->prependLocation($location); } /** * Add a new namespace to the loader. * * @param string $namespace * @param string|array $hints * @return $this */ public function addNamespace($namespace, $hints) { $this->finder->addNamespace($namespace, $hints); return $this; } /** * Prepend a new namespace to the loader. * * @param string $namespace * @param string|array $hints * @return $this */ public function prependNamespace($namespace, $hints) { $this->finder->prependNamespace($namespace, $hints); return $this; } /** * Replace the namespace hints for the given namespace. * * @param string $namespace * @param string|array $hints * @return $this */ public function replaceNamespace($namespace, $hints) { $this->finder->replaceNamespace($namespace, $hints); return $this; } /** * Register a valid view extension and its engine. * * @param string $extension * @param string $engine * @param \Closure|null $resolver * @return void */ public function addExtension($extension, $engine, $resolver = null) { $this->finder->addExtension($extension); if (isset($resolver)) { $this->engines->register($engine, $resolver); } unset($this->extensions[$extension]); $this->extensions = array_merge([$extension => $engine], $this->extensions); $this->pathEngineCache = []; } /** * Flush all of the factory state like sections and stacks. * * @return void */ public function flushState() { $this->renderCount = 0; $this->renderedOnce = []; $this->flushSections(); $this->flushStacks(); $this->flushComponents(); $this->flushFragments(); } /** * Flush all of the section contents if done rendering. * * @return void */ public function flushStateIfDoneRendering() { if ($this->doneRendering()) { $this->flushState(); } } /** * Get the extension to engine bindings. * * @return array */ public function getExtensions() { return $this->extensions; } /** * Get the engine resolver instance. * * @return \Illuminate\View\Engines\EngineResolver */ public function getEngineResolver() { return $this->engines; } /** * Get the view finder instance. * * @return \Illuminate\View\ViewFinderInterface */ public function getFinder() { return $this->finder; } /** * Set the view finder instance. * * @param \Illuminate\View\ViewFinderInterface $finder * @return void */ public function setFinder(ViewFinderInterface $finder) { $this->finder = $finder; } /** * Flush the cache of views located by the finder. * * @return void */ public function flushFinderCache() { $this->getFinder()->flush(); } /** * Get the event dispatcher instance. * * @return \Illuminate\Contracts\Events\Dispatcher */ public function getDispatcher() { return $this->events; } /** * Set the event dispatcher instance. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */ public function setDispatcher(Dispatcher $events) { $this->events = $events; } /** * Get the IoC container instance. * * @return \Illuminate\Contracts\Container\Container */ public function getContainer() { return $this->container; } /** * Set the IoC container instance. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function setContainer(Container $container) { $this->container = $container; } /** * Get an item from the shared data. * * @param string $key * @param mixed $default * @return mixed */ public function shared($key, $default = null) { return Arr::get($this->shared, $key, $default); } /** * Get all of the shared data for the environment. * * @return array */ public function getShared() { return $this->shared; } } FileViewFinder.php000075500000016246150145556460010146 0ustar00files = $files; $this->paths = array_map([$this, 'resolvePath'], $paths); if (isset($extensions)) { $this->extensions = $extensions; } } /** * Get the fully qualified location of the view. * * @param string $name * @return string */ public function find($name) { if (isset($this->views[$name])) { return $this->views[$name]; } if ($this->hasHintInformation($name = trim($name))) { return $this->views[$name] = $this->findNamespacedView($name); } return $this->views[$name] = $this->findInPaths($name, $this->paths); } /** * Get the path to a template with a named path. * * @param string $name * @return string */ protected function findNamespacedView($name) { [$namespace, $view] = $this->parseNamespaceSegments($name); return $this->findInPaths($view, $this->hints[$namespace]); } /** * Get the segments of a template with a named path. * * @param string $name * @return array * * @throws \InvalidArgumentException */ protected function parseNamespaceSegments($name) { $segments = explode(static::HINT_PATH_DELIMITER, $name); if (count($segments) !== 2) { throw new InvalidArgumentException("View [{$name}] has an invalid name."); } if (! isset($this->hints[$segments[0]])) { throw new InvalidArgumentException("No hint path defined for [{$segments[0]}]."); } return $segments; } /** * Find the given view in the list of paths. * * @param string $name * @param array $paths * @return string * * @throws \InvalidArgumentException */ protected function findInPaths($name, $paths) { foreach ((array) $paths as $path) { foreach ($this->getPossibleViewFiles($name) as $file) { $viewPath = $path.'/'.$file; if (strlen($viewPath) < (PHP_MAXPATHLEN - 1) && $this->files->exists($viewPath)) { return $viewPath; } } } throw new InvalidArgumentException("View [{$name}] not found."); } /** * Get an array of possible view files. * * @param string $name * @return array */ protected function getPossibleViewFiles($name) { return array_map(fn ($extension) => str_replace('.', '/', $name).'.'.$extension, $this->extensions); } /** * Add a location to the finder. * * @param string $location * @return void */ public function addLocation($location) { $this->paths[] = $this->resolvePath($location); } /** * Prepend a location to the finder. * * @param string $location * @return void */ public function prependLocation($location) { array_unshift($this->paths, $this->resolvePath($location)); } /** * Resolve the path. * * @param string $path * @return string */ protected function resolvePath($path) { return realpath($path) ?: $path; } /** * Add a namespace hint to the finder. * * @param string $namespace * @param string|array $hints * @return void */ public function addNamespace($namespace, $hints) { $hints = (array) $hints; if (isset($this->hints[$namespace])) { $hints = array_merge($this->hints[$namespace], $hints); } $this->hints[$namespace] = $hints; } /** * Prepend a namespace hint to the finder. * * @param string $namespace * @param string|array $hints * @return void */ public function prependNamespace($namespace, $hints) { $hints = (array) $hints; if (isset($this->hints[$namespace])) { $hints = array_merge($hints, $this->hints[$namespace]); } $this->hints[$namespace] = $hints; } /** * Replace the namespace hints for the given namespace. * * @param string $namespace * @param string|array $hints * @return void */ public function replaceNamespace($namespace, $hints) { $this->hints[$namespace] = (array) $hints; } /** * Register an extension with the view finder. * * @param string $extension * @return void */ public function addExtension($extension) { if (($index = array_search($extension, $this->extensions)) !== false) { unset($this->extensions[$index]); } array_unshift($this->extensions, $extension); } /** * Returns whether or not the view name has any hint information. * * @param string $name * @return bool */ public function hasHintInformation($name) { return strpos($name, static::HINT_PATH_DELIMITER) > 0; } /** * Flush the cache of located views. * * @return void */ public function flush() { $this->views = []; } /** * Get the filesystem instance. * * @return \Illuminate\Filesystem\Filesystem */ public function getFilesystem() { return $this->files; } /** * Set the active view paths. * * @param array $paths * @return $this */ public function setPaths($paths) { $this->paths = $paths; return $this; } /** * Get the active view paths. * * @return array */ public function getPaths() { return $this->paths; } /** * Get the views that have been located. * * @return array */ public function getViews() { return $this->views; } /** * Get the namespace to file path hints. * * @return array */ public function getHints() { return $this->hints; } /** * Get registered extensions. * * @return array */ public function getExtensions() { return $this->extensions; } } InvokableComponentVariable.php000064400000004005150145556460012532 0ustar00callable = $callable; } /** * Resolve the displayable value that the class is deferring. * * @return \Illuminate\Contracts\Support\Htmlable|string */ public function resolveDisplayableValue() { return $this->__invoke(); } /** * Get an iterator instance for the variable. * * @return \ArrayIterator */ public function getIterator(): Traversable { $result = $this->__invoke(); return new ArrayIterator($result instanceof Enumerable ? $result->all() : $result); } /** * Dynamically proxy attribute access to the variable. * * @param string $key * @return mixed */ public function __get($key) { return $this->__invoke()->{$key}; } /** * Dynamically proxy method access to the variable. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->__invoke()->{$method}(...$parameters); } /** * Resolve the variable. * * @return mixed */ public function __invoke() { return call_user_func($this->callable); } /** * Resolve the variable as a string. * * @return string */ public function __toString() { return (string) $this->__invoke(); } } LICENSE.md000064400000002063150145556460006164 0ustar00The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Middleware/ShareErrorsFromSession.php000064400000002622150145556460013776 0ustar00view = $view; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { // If the current session has an "errors" variable bound to it, we will share // its value with all view instances so the views can easily access errors // without having to bind. An empty bag is set when there aren't errors. $this->view->share( 'errors', $request->session()->get('errors') ?: new ViewErrorBag ); // Putting the errors in the view for every view allows the developer to just // assume that some errors are always available, which is convenient since // they don't have to continually run checks for the presence of errors. return $next($request); } } View.php000075500000026474150145556460006222 0ustar00view = $view; $this->path = $path; $this->engine = $engine; $this->factory = $factory; $this->data = $data instanceof Arrayable ? $data->toArray() : (array) $data; } /** * Get the evaluated contents of a given fragment. * * @param string $fragment * @return string */ public function fragment($fragment) { return $this->render(function () use ($fragment) { return $this->factory->getFragment($fragment); }); } /** * Get the evaluated contents for a given array of fragments or return all fragments. * * @param array|null $fragments * @return string */ public function fragments(?array $fragments = null) { return is_null($fragments) ? $this->allFragments() : (new Collection($fragments))->map(fn ($f) => $this->fragment($f))->implode(''); } /** * Get the evaluated contents of a given fragment if the given condition is true. * * @param bool $boolean * @param string $fragment * @return string */ public function fragmentIf($boolean, $fragment) { if (value($boolean)) { return $this->fragment($fragment); } return $this->render(); } /** * Get the evaluated contents for a given array of fragments if the given condition is true. * * @param bool $boolean * @param array|null $fragments * @return string */ public function fragmentsIf($boolean, ?array $fragments = null) { if (value($boolean)) { return $this->fragments($fragments); } return $this->render(); } /** * Get all fragments as a single string. * * @return string */ protected function allFragments() { return (new Collection($this->render(fn () => $this->factory->getFragments())))->implode(''); } /** * Get the string contents of the view. * * @param callable|null $callback * @return string * * @throws \Throwable */ public function render(?callable $callback = null) { try { $contents = $this->renderContents(); $response = isset($callback) ? $callback($this, $contents) : null; // Once we have the contents of the view, we will flush the sections if we are // done rendering all views so that there is nothing left hanging over when // another view gets rendered in the future by the application developer. $this->factory->flushStateIfDoneRendering(); return ! is_null($response) ? $response : $contents; } catch (Throwable $e) { $this->factory->flushState(); throw $e; } } /** * Get the contents of the view instance. * * @return string */ protected function renderContents() { // We will keep track of the number of views being rendered so we can flush // the section after the complete rendering operation is done. This will // clear out the sections for any separate views that may be rendered. $this->factory->incrementRender(); $this->factory->callComposer($this); $contents = $this->getContents(); // Once we've finished rendering the view, we'll decrement the render count // so that each section gets flushed out next time a view is created and // no old sections are staying around in the memory of an environment. $this->factory->decrementRender(); return $contents; } /** * Get the evaluated contents of the view. * * @return string */ protected function getContents() { return $this->engine->get($this->path, $this->gatherData()); } /** * Get the data bound to the view instance. * * @return array */ public function gatherData() { $data = array_merge($this->factory->getShared(), $this->data); foreach ($data as $key => $value) { if ($value instanceof Renderable) { $data[$key] = $value->render(); } } return $data; } /** * Get the sections of the rendered view. * * @return array * * @throws \Throwable */ public function renderSections() { return $this->render(function () { return $this->factory->getSections(); }); } /** * Add a piece of data to the view. * * @param string|array $key * @param mixed $value * @return $this */ public function with($key, $value = null) { if (is_array($key)) { $this->data = array_merge($this->data, $key); } else { $this->data[$key] = $value; } return $this; } /** * Add a view instance to the view data. * * @param string $key * @param string $view * @param array $data * @return $this */ public function nest($key, $view, array $data = []) { return $this->with($key, $this->factory->make($view, $data)); } /** * Add validation errors to the view. * * @param \Illuminate\Contracts\Support\MessageProvider|array $provider * @param string $bag * @return $this */ public function withErrors($provider, $bag = 'default') { return $this->with('errors', (new ViewErrorBag)->put( $bag, $this->formatErrors($provider) )); } /** * Parse the given errors into an appropriate value. * * @param \Illuminate\Contracts\Support\MessageProvider|array|string $provider * @return \Illuminate\Support\MessageBag */ protected function formatErrors($provider) { return $provider instanceof MessageProvider ? $provider->getMessageBag() : new MessageBag((array) $provider); } /** * Get the name of the view. * * @return string */ public function name() { return $this->getName(); } /** * Get the name of the view. * * @return string */ public function getName() { return $this->view; } /** * Get the array of view data. * * @return array */ public function getData() { return $this->data; } /** * Get the path to the view file. * * @return string */ public function getPath() { return $this->path; } /** * Set the path to the view. * * @param string $path * @return void */ public function setPath($path) { $this->path = $path; } /** * Get the view factory instance. * * @return \Illuminate\View\Factory */ public function getFactory() { return $this->factory; } /** * Get the view's rendering engine. * * @return \Illuminate\Contracts\View\Engine */ public function getEngine() { return $this->engine; } /** * Determine if a piece of data is bound. * * @param string $key * @return bool */ public function offsetExists($key): bool { return array_key_exists($key, $this->data); } /** * Get a piece of bound data to the view. * * @param string $key * @return mixed */ public function offsetGet($key): mixed { return $this->data[$key]; } /** * Set a piece of data on the view. * * @param string $key * @param mixed $value * @return void */ public function offsetSet($key, $value): void { $this->with($key, $value); } /** * Unset a piece of data from the view. * * @param string $key * @return void */ public function offsetUnset($key): void { unset($this->data[$key]); } /** * Get a piece of data from the view. * * @param string $key * @return mixed */ public function &__get($key) { return $this->data[$key]; } /** * Set a piece of data on the view. * * @param string $key * @param mixed $value * @return void */ public function __set($key, $value) { $this->with($key, $value); } /** * Check if a piece of data is bound to the view. * * @param string $key * @return bool */ public function __isset($key) { return isset($this->data[$key]); } /** * Remove a piece of bound data from the view. * * @param string $key * @return void */ public function __unset($key) { unset($this->data[$key]); } /** * Dynamically bind parameters to the view. * * @param string $method * @param array $parameters * @return \Illuminate\View\View * * @throws \BadMethodCallException */ public function __call($method, $parameters) { if (static::hasMacro($method)) { return $this->macroCall($method, $parameters); } if (! str_starts_with($method, 'with')) { throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); } return $this->with(Str::camel(substr($method, 4)), $parameters[0]); } /** * Get content as a string of HTML. * * @return string */ public function toHtml() { return $this->render(); } /** * Get the string contents of the view. * * @return string * * @throws \Throwable */ public function __toString() { return $this->render(); } } ViewException.php000064400000001607150145556460010065 0ustar00getPrevious(); if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { return Container::getInstance()->call($reportCallable); } return false; } /** * Render the exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response|null */ public function render($request) { $exception = $this->getPrevious(); if ($exception && method_exists($exception, 'render')) { return $exception->render($request); } } } ViewFinderInterface.php000075500000002653150145556460011164 0ustar00registerFactory(); $this->registerViewFinder(); $this->registerBladeCompiler(); $this->registerEngineResolver(); $this->app->terminating(static function () { Component::flushCache(); }); } /** * Register the view environment. * * @return void */ public function registerFactory() { $this->app->singleton('view', function ($app) { // Next we need to grab the engine resolver instance that will be used by the // environment. The resolver will be used by an environment to get each of // the various engine implementations such as plain PHP or Blade engine. $resolver = $app['view.engine.resolver']; $finder = $app['view.finder']; $factory = $this->createFactory($resolver, $finder, $app['events']); // We will also set the container instance on this view environment since the // view composers may be classes registered in the container, which allows // for great testable, flexible composers for the application developer. $factory->setContainer($app); $factory->share('app', $app); $app->terminating(static function () { Component::forgetFactory(); }); return $factory; }); } /** * Create a new Factory Instance. * * @param \Illuminate\View\Engines\EngineResolver $resolver * @param \Illuminate\View\ViewFinderInterface $finder * @param \Illuminate\Contracts\Events\Dispatcher $events * @return \Illuminate\View\Factory */ protected function createFactory($resolver, $finder, $events) { return new Factory($resolver, $finder, $events); } /** * Register the view finder implementation. * * @return void */ public function registerViewFinder() { $this->app->bind('view.finder', function ($app) { return new FileViewFinder($app['files'], $app['config']['view.paths']); }); } /** * Register the Blade compiler implementation. * * @return void */ public function registerBladeCompiler() { $this->app->singleton('blade.compiler', function ($app) { return tap(new BladeCompiler( $app['files'], $app['config']['view.compiled'], $app['config']->get('view.relative_hash', false) ? $app->basePath() : '', $app['config']->get('view.cache', true), $app['config']->get('view.compiled_extension', 'php'), ), function ($blade) { $blade->component('dynamic-component', DynamicComponent::class); }); }); } /** * Register the engine resolver instance. * * @return void */ public function registerEngineResolver() { $this->app->singleton('view.engine.resolver', function () { $resolver = new EngineResolver; // Next, we will register the various view engines with the resolver so that the // environment will resolve the engines needed for various views based on the // extension of view file. We call a method for each of the view's engines. foreach (['file', 'php', 'blade'] as $engine) { $this->{'register'.ucfirst($engine).'Engine'}($resolver); } return $resolver; }); } /** * Register the file engine implementation. * * @param \Illuminate\View\Engines\EngineResolver $resolver * @return void */ public function registerFileEngine($resolver) { $resolver->register('file', function () { return new FileEngine(Container::getInstance()->make('files')); }); } /** * Register the PHP engine implementation. * * @param \Illuminate\View\Engines\EngineResolver $resolver * @return void */ public function registerPhpEngine($resolver) { $resolver->register('php', function () { return new PhpEngine(Container::getInstance()->make('files')); }); } /** * Register the Blade engine implementation. * * @param \Illuminate\View\Engines\EngineResolver $resolver * @return void */ public function registerBladeEngine($resolver) { $resolver->register('blade', function () { $app = Container::getInstance(); $compiler = new CompilerEngine( $app->make('blade.compiler'), $app->make('files'), ); $app->terminating(static function () use ($compiler) { $compiler->forgetCompiledOrNotExpired(); }); return $compiler; }); } } composer.json000064400000002027150145556460007302 0ustar00{ "name": "illuminate/view", "description": "The Illuminate View package.", "license": "MIT", "homepage": "https://laravel.com", "support": { "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, "authors": [ { "name": "Taylor Otwell", "email": "taylor@laravel.com" } ], "require": { "php": "^8.2", "ext-tokenizer": "*", "illuminate/collections": "^11.0", "illuminate/container": "^11.0", "illuminate/contracts": "^11.0", "illuminate/events": "^11.0", "illuminate/filesystem": "^11.0", "illuminate/macroable": "^11.0", "illuminate/support": "^11.0" }, "autoload": { "psr-4": { "Illuminate\\View\\": "" } }, "extra": { "branch-alias": { "dev-master": "11.x-dev" } }, "config": { "sort-packages": true }, "minimum-stability": "dev" }