dependencies-upgrade

This commit is contained in:
RafficMohammed
2023-01-08 02:20:59 +05:30
parent 7870479b18
commit 49021a4497
1711 changed files with 74994 additions and 70803 deletions

View File

@@ -48,8 +48,13 @@ class AnonymousComponent extends Component
*/
public function data()
{
$this->attributes = $this->attributes ?: new ComponentAttributeBag;
$this->attributes = $this->attributes ?: $this->newAttributeBag();
return $this->data + ['attributes' => $this->attributes];
return array_merge(
optional($this->data['attributes'] ?? null)->getAttributes() ?: [],
$this->attributes->getAttributes(),
$this->data,
['attributes' => $this->attributes]
);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Illuminate\View;
class AppendableAttributeValue
{
/**
* The attribute value.
*
* @var mixed
*/
public $value;
/**
* Create a new appendable attribute value.
*
* @param mixed $value
* @return void
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Get the string value.
*
* @return string
*/
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -2,13 +2,20 @@
namespace Illuminate\View\Compilers;
use Illuminate\Container\Container;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\ReflectsClosures;
use Illuminate\View\Component;
use InvalidArgumentException;
class BladeCompiler extends Compiler implements CompilerInterface
{
use Concerns\CompilesAuthorizations,
Concerns\CompilesClasses,
Concerns\CompilesComments,
Concerns\CompilesComponents,
Concerns\CompilesConditionals,
@@ -18,11 +25,13 @@ class BladeCompiler extends Compiler implements CompilerInterface
Concerns\CompilesIncludes,
Concerns\CompilesInjections,
Concerns\CompilesJson,
Concerns\CompilesJs,
Concerns\CompilesLayouts,
Concerns\CompilesLoops,
Concerns\CompilesRawPhp,
Concerns\CompilesStacks,
Concerns\CompilesTranslations;
Concerns\CompilesTranslations,
ReflectsClosures;
/**
* All of the registered extensions.
@@ -62,7 +71,7 @@ class BladeCompiler extends Compiler implements CompilerInterface
/**
* All of the available compiler functions.
*
* @var array
* @var string[]
*/
protected $compilers = [
// 'Comments',
@@ -74,21 +83,21 @@ class BladeCompiler extends Compiler implements CompilerInterface
/**
* Array of opening and closing tags for raw echos.
*
* @var array
* @var string[]
*/
protected $rawTags = ['{!!', '!!}'];
/**
* Array of opening and closing tags for regular echos.
*
* @var array
* @var string[]
*/
protected $contentTags = ['{{', '}}'];
/**
* Array of opening and closing tags for escaped echos.
*
* @var array
* @var string[]
*/
protected $escapedTags = ['{{{', '}}}'];
@@ -100,14 +109,14 @@ class BladeCompiler extends Compiler implements CompilerInterface
protected $echoFormat = 'e(%s)';
/**
* Array of footer lines to be added to template.
* Array of footer lines to be added to the template.
*
* @var array
*/
protected $footer = [];
/**
* Array to temporary store the raw blocks found in the template.
* Array to temporarily store the raw blocks found in the template.
*
* @var array
*/
@@ -120,6 +129,13 @@ class BladeCompiler extends Compiler implements CompilerInterface
*/
protected $classComponentAliases = [];
/**
* The array of class component namespaces to autoload from.
*
* @var array
*/
protected $classComponentNamespaces = [];
/**
* Indicates if component tags should be compiled.
*
@@ -146,9 +162,11 @@ class BladeCompiler extends Compiler implements CompilerInterface
$contents = $this->appendFilePath($contents);
}
$this->files->put(
$this->getCompiledPath($this->getPath()), $contents
$this->ensureCompiledDirectoryExists(
$compiledPath = $this->getCompiledPath($this->getPath())
);
$this->files->put($compiledPath, $contents);
}
}
@@ -244,7 +262,74 @@ class BladeCompiler extends Compiler implements CompilerInterface
$result = $this->addFooters($result);
}
return $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();
}
}
/**
@@ -318,7 +403,7 @@ class BladeCompiler extends Compiler implements CompilerInterface
}
return (new ComponentTagCompiler(
$this->classComponentAliases, $this
$this->classComponentAliases, $this->classComponentNamespaces, $this
))->compile($value);
}
@@ -340,7 +425,7 @@ class BladeCompiler extends Compiler implements CompilerInterface
}
/**
* Get a placeholder to temporary mark the position of raw blocks.
* Get a placeholder to temporarily mark the position of raw blocks.
*
* @param int|string $replace
* @return string
@@ -439,6 +524,8 @@ class BladeCompiler extends Compiler implements CompilerInterface
*/
protected function callCustomDirective($name, $value)
{
$value = $value ?? '';
if (Str::startsWith($value, '(') && Str::endsWith($value, ')')) {
$value = Str::substr($value, 1, -1);
}
@@ -568,9 +655,9 @@ class BladeCompiler extends Compiler implements CompilerInterface
{
foreach ($components as $key => $value) {
if (is_numeric($key)) {
static::component($value, null, $prefix);
$this->component($value, null, $prefix);
} else {
static::component($key, $value, $prefix);
$this->component($key, $value, $prefix);
}
}
}
@@ -585,6 +672,28 @@ class BladeCompiler extends Compiler implements CompilerInterface
return $this->classComponentAliases;
}
/**
* 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 class component namespaces.
*
* @return array
*/
public function getClassComponentNamespaces()
{
return $this->classComponentNamespaces;
}
/**
* Register a component alias directive.
*
@@ -616,7 +725,7 @@ class BladeCompiler extends Compiler implements CompilerInterface
*/
public function include($path, $alias = null)
{
return $this->aliasInclude($path, $alias);
$this->aliasInclude($path, $alias);
}
/**

View File

@@ -71,4 +71,17 @@ abstract class Compiler
return $this->files->lastModified($path) >=
$this->files->lastModified($compiled);
}
/**
* 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);
}
}
}

View File

@@ -8,6 +8,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Illuminate\View\AnonymousComponent;
use Illuminate\View\DynamicComponent;
use Illuminate\View\ViewFinderInterface;
use InvalidArgumentException;
use ReflectionClass;
@@ -32,6 +33,13 @@ class ComponentTagCompiler
*/
protected $aliases = [];
/**
* The component class namespaces.
*
* @var array
*/
protected $namespaces = [];
/**
* The "bind:" attributes that have been compiled for the current component.
*
@@ -40,15 +48,17 @@ class ComponentTagCompiler
protected $boundAttributes = [];
/**
* Create new component tag compiler.
* Create a new component tag compiler.
*
* @param array $aliases
* @param \Illuminate\View\Compilers\BladeCompiler|null
* @param array $namespaces
* @param \Illuminate\View\Compilers\BladeCompiler|null $blade
* @return void
*/
public function __construct(array $aliases = [], ?BladeCompiler $blade = null)
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());
}
@@ -100,18 +110,26 @@ class ComponentTagCompiler
(?<attributes>
(?:
\s+
[\w\-:.@]+
(
=
(?:
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
\{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\}
)
|
(?:
[\w\-:.@]+
(
=
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
)
)?
)
)
?)*
)*
\s*
)
(?<![\/=\-])
@@ -145,17 +163,25 @@ class ComponentTagCompiler
(?<attributes>
(?:
\s+
[\w\-:.@]+
(
=
(?:
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
\{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\}
)
)?
|
(?:
[\w\-:.@]+
(
=
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
)
)?
)
)
)*
\s*
)
@@ -167,7 +193,7 @@ class ComponentTagCompiler
$attributes = $this->getAttributesFromAttributeString($matches['attributes']);
return $this->componentString($matches[1], $attributes)."\n@endcomponentClass ";
return $this->componentString($matches[1], $attributes)."\n@endComponentClass##END-COMPONENT-CLASS##";
}, $value);
}
@@ -204,8 +230,8 @@ class ComponentTagCompiler
$parameters = $data->all();
}
return " @component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).'])
<?php $component->withAttributes(['.$this->attributesToString($attributes->all()).']); ?>';
return "##BEGIN-COMPONENT-CLASS##@component('{$class}', '{$component}', [".$this->attributesToString($parameters, $escapeBound = false).'])
<?php $component->withAttributes(['.$this->attributesToString($attributes->all(), $escapeAttributes = $class !== DynamicComponent::class).']); ?>';
}
/**
@@ -216,7 +242,7 @@ class ComponentTagCompiler
*
* @throws \InvalidArgumentException
*/
protected function componentClass(string $component)
public function componentClass(string $component)
{
$viewFactory = Container::getInstance()->make(Factory::class);
@@ -234,6 +260,10 @@ class ComponentTagCompiler
);
}
if ($class = $this->findClassByComponent($component)) {
return $class;
}
if (class_exists($class = $this->guessClassName($component))) {
return $class;
}
@@ -242,11 +272,36 @@ class ComponentTagCompiler
return $view;
}
if ($viewFactory->exists($view = $this->guessViewName($component).'.index')) {
return $view;
}
throw new InvalidArgumentException(
"Unable to locate a class or view for component [{$component}]."
);
}
/**
* 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]) || ! isset($segments[1])) {
return;
}
if (class_exists($class = $this->namespaces[$prefix].'\\'.$this->formatClassName($segments[1]))) {
return $class;
}
}
/**
* Guess the class name for the given component.
*
@@ -259,11 +314,24 @@ class ComponentTagCompiler
->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 $namespace.'View\\Components\\'.implode('\\', $componentPieces);
return implode('\\', $componentPieces);
}
/**
@@ -292,7 +360,7 @@ class ComponentTagCompiler
* @param array $attributes
* @return array
*/
protected function partitionDataAndAttributes($class, array $attributes)
public function partitionDataAndAttributes($class, array $attributes)
{
// If the class doesn't exists, we'll assume it's a class-less component and
// return all of the attributes as both data and attributes since we have
@@ -320,7 +388,7 @@ class ComponentTagCompiler
*/
protected function compileClosingTags(string $value)
{
return preg_replace("/<\/\s*x[-\:][\w\-\:\.]*\s*>/", ' @endcomponentClass ', $value);
return preg_replace("/<\/\s*x[-\:][\w\-\:\.]*\s*>/", ' @endComponentClass##END-COMPONENT-CLASS##', $value);
}
/**
@@ -331,14 +399,53 @@ class ComponentTagCompiler
*/
public function compileSlots(string $value)
{
$value = preg_replace_callback('/<\s*x[\-\:]slot\s+(:?)name=(?<name>(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+))\s*>/', function ($matches) {
$pattern = "/
<
\s*
x[\-\:]slot
\s+
(:?)name=(?<name>(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+))
(?<attributes>
(?:
\s+
(?:
(?:
\{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\}
)
|
(?:
[\w\-:.@]+
(
=
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
)
)?
)
)
)*
\s*
)
(?<![\/=\-])
>
/x";
$value = preg_replace_callback($pattern, function ($matches) {
$name = $this->stripQuotes($matches['name']);
if ($matches[1] !== ':') {
$name = "'{$name}'";
}
return " @slot({$name}) ";
$this->boundAttributes = [];
$attributes = $this->getAttributesFromAttributeString($matches['attributes']);
return " @slot({$name}, null, [".$this->attributesToString($attributes).']) ';
}, $value);
return preg_replace('/<\/\s*x[\-\:]slot[^>]*>/', ' @endslot', $value);
@@ -352,6 +459,8 @@ class ComponentTagCompiler
*/
protected function getAttributesFromAttributeString(string $attributeString)
{
$attributeString = $this->parseAttributeBag($attributeString);
$attributeString = $this->parseBindAttributes($attributeString);
$pattern = '/
@@ -394,10 +503,30 @@ class ComponentTagCompiler
$value = "'".$this->compileAttributeEchos($value)."'";
}
if (Str::startsWith($attribute, '::')) {
$attribute = substr($attribute, 1);
}
return [$attribute => $value];
})->toArray();
}
/**
* 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(?:[^}]+?(?<!\s))?)\s*\}\} # exact match of attributes variable being echoed
/x";
return preg_replace($pattern, ' :attributes="$1"', $attributeString);
}
/**
* Parse the "bind" attributes in a given attribute string into their fully-qualified syntax.
*
@@ -408,7 +537,7 @@ class ComponentTagCompiler
{
$pattern = "/
(?:^|\s+) # start of the string or whitespace between attributes
: # attribute needs to start with a semicolon
:(?!:) # attribute needs to start with a single colon
([\w\-:.@]+) # match the actual attribute name
= # only match attributes that have a value
/xm";

View File

@@ -0,0 +1,19 @@
<?php
namespace Illuminate\View\Compilers\Concerns;
trait CompilesClasses
{
/**
* Compile the conditional class statement into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileClass($expression)
{
$expression = is_null($expression) ? '([])' : $expression;
return "class=\"<?php echo \Illuminate\Support\Arr::toCssClasses{$expression} ?>\"";
}
}

View File

@@ -2,7 +2,9 @@
namespace Illuminate\View\Compilers\Concerns;
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Support\Str;
use Illuminate\View\ComponentAttributeBag;
trait CompilesComponents
{
@@ -76,15 +78,7 @@ trait CompilesComponents
*/
protected function compileEndComponent()
{
$hash = array_pop(static::$componentHashStack);
return implode("\n", [
'<?php if (isset($__componentOriginal'.$hash.')): ?>',
'<?php $component = $__componentOriginal'.$hash.'; ?>',
'<?php unset($__componentOriginal'.$hash.'); ?>',
'<?php endif; ?>',
'<?php echo $__env->renderComponent(); ?>',
]);
return '<?php echo $__env->renderComponent(); ?>';
}
/**
@@ -94,7 +88,13 @@ trait CompilesComponents
*/
public function compileEndComponentClass()
{
return static::compileEndComponent()."\n".implode("\n", [
$hash = array_pop(static::$componentHashStack);
return $this->compileEndComponent()."\n".implode("\n", [
'<?php endif; ?>',
'<?php if (isset($__componentOriginal'.$hash.')): ?>',
'<?php $component = $__componentOriginal'.$hash.'; ?>',
'<?php unset($__componentOriginal'.$hash.'); ?>',
'<?php endif; ?>',
]);
}
@@ -160,6 +160,20 @@ trait CompilesComponents
<?php unset(\$__defined_vars); ?>";
}
/**
* Compile the aware statement into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileAware($expression)
{
return "<?php foreach ({$expression} as \$__key => \$__value) {
\$__consumeVariable = is_string(\$__key) ? \$__key : \$__value;
\$\$__consumeVariable = is_string(\$__key) ? \$__env->getConsumableComponentData(\$__key, \$__value) : \$__env->getConsumableComponentData(\$__value);
} ?>";
}
/**
* Sanitize the given component attribute value.
*
@@ -168,8 +182,12 @@ trait CompilesComponents
*/
public static function sanitizeComponentAttribute($value)
{
if (is_object($value) && $value instanceof CanBeEscapedWhenCastToString) {
return $value->escapeWhenCastingToString();
}
return is_string($value) ||
(is_object($value) && method_exists($value, '__toString'))
(is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString'))
? e($value)
: $value;
}

View File

@@ -7,7 +7,7 @@ use Illuminate\Support\Str;
trait CompilesConditionals
{
/**
* Identifier for the first case in switch statement.
* Identifier for the first case in the switch statement.
*
* @var bool
*/
@@ -283,8 +283,9 @@ trait CompilesConditionals
}
/**
* Compile an once block into valid PHP.
* Compile a once block into valid PHP.
*
* @param string|null $id
* @return string
*/
protected function compileOnce($id = null)

View File

@@ -2,8 +2,34 @@
namespace Illuminate\View\Compilers\Concerns;
use Closure;
use Illuminate\Support\Str;
trait CompilesEchos
{
/**
* Custom rendering callbacks for stringable objects.
*
* @var array
*/
protected $echoHandlers = [];
/**
* Add a handler to be executed before echoing a given class.
*
* @param string|callable $class
* @param callable|null $handler
* @return void
*/
public function stringable($class, $handler = null)
{
if ($class instanceof Closure) {
[$class, $handler] = [$this->firstClosureParameterType($class), $class];
}
$this->echoHandlers[$class] = $handler;
}
/**
* Compile Blade echos into valid PHP.
*
@@ -46,7 +72,9 @@ trait CompilesEchos
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
return $matches[1] ? substr($matches[0], 1) : "<?php echo {$matches[2]}; ?>{$whitespace}";
return $matches[1]
? substr($matches[0], 1)
: "<?php echo {$this->wrapInEchoHandler($matches[2])}; ?>{$whitespace}";
};
return preg_replace_callback($pattern, $callback, $value);
@@ -65,7 +93,7 @@ trait CompilesEchos
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
$wrapped = sprintf($this->echoFormat, $matches[2]);
$wrapped = sprintf($this->echoFormat, $this->wrapInEchoHandler($matches[2]));
return $matches[1] ? substr($matches[0], 1) : "<?php echo {$wrapped}; ?>{$whitespace}";
};
@@ -86,9 +114,54 @@ trait CompilesEchos
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
return $matches[1] ? $matches[0] : "<?php echo e({$matches[2]}); ?>{$whitespace}";
return $matches[1]
? $matches[0]
: "<?php echo e({$this->wrapInEchoHandler($matches[2])}); ?>{$whitespace}";
};
return preg_replace_callback($pattern, $callback, $value);
}
/**
* Add an instance of the blade echo handler to the start of the compiled string.
*
* @param string $result
* @return string
*/
protected function addBladeCompilerVariable($result)
{
return "<?php \$__bladeCompiler = app('blade.compiler'); ?>".$result;
}
/**
* Wrap the echoable value in an echo handler if applicable.
*
* @param string $value
* @return string
*/
protected function wrapInEchoHandler($value)
{
$value = Str::of($value)
->trim()
->when(Str::endsWith($value, ';'), function ($str) {
return $str->beforeLast(';');
});
return empty($this->echoHandlers) ? $value : '$__bladeCompiler->applyEchoHandler('.$value.')';
}
/**
* Apply the echo handler for the value if it exists.
*
* @param string $value
* @return string
*/
public function applyEchoHandler($value)
{
if (is_object($value) && isset($this->echoHandlers[get_class($value)])) {
return call_user_func($this->echoHandlers[get_class($value)], $value);
}
return $value;
}
}

View File

@@ -64,7 +64,7 @@ trait CompilesIncludes
{
$expression = $this->stripParentheses($expression);
return "<?php echo \$__env->renderWhen(! $expression, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path'])); ?>";
return "<?php echo \$__env->renderUnless($expression, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path'])); ?>";
}
/**

View File

@@ -12,12 +12,12 @@ trait CompilesInjections
*/
protected function compileInject($expression)
{
$segments = explode(',', preg_replace("/[\(\)\\\"\']/", '', $expression));
$segments = explode(',', preg_replace("/[\(\)]/", '', $expression));
$variable = trim($segments[0]);
$variable = trim($segments[0], " '\"");
$service = trim($segments[1]);
return "<?php \${$variable} = app('{$service}'); ?>";
return "<?php \${$variable} = app({$service}); ?>";
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Illuminate\View\Compilers\Concerns;
use Illuminate\Support\Js;
trait CompilesJs
{
/**
* Compile the "@js" directive into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileJs(string $expression)
{
return sprintf(
"<?php echo \%s::from(%s)->toHtml() ?>",
Js::class, $this->stripParentheses($expression)
);
}
}

View File

@@ -28,6 +28,23 @@ trait CompilesLayouts
return '';
}
/**
* Compile the extends-first statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileExtendsFirst($expression)
{
$expression = $this->stripParentheses($expression);
$echo = "<?php echo \$__env->first({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>";
$this->footer[] = $echo;
return '';
}
/**
* Compile the section statements into valid PHP.
*

View File

@@ -4,6 +4,8 @@ namespace Illuminate\View;
use Closure;
use Illuminate\Container\Container;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View as ViewContract;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionMethod;
@@ -49,27 +51,31 @@ abstract class Component
/**
* Get the view / view contents that represent the component.
*
* @return \Illuminate\View\View|\Closure|string
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string
*/
abstract public function render();
/**
* Resolve the Blade view or view file that should be used when rendering the component.
*
* @return \Illuminate\View\View|\Closure|string
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string
*/
public function resolveView()
{
$view = $this->render();
if ($view instanceof View) {
if ($view instanceof ViewContract) {
return $view;
}
if ($view instanceof Htmlable) {
return $view;
}
$resolver = function ($view) {
$factory = Container::getInstance()->make('view');
return $factory->exists($view)
return strlen($view) <= PHP_MAXPATHLEN && $factory->exists($view)
? $view
: $this->createBladeViewFromString($factory, $view);
};
@@ -94,7 +100,7 @@ abstract class Component
$directory = Container::getInstance()['config']->get('view.compiled')
);
if (! file_exists($viewFile = $directory.'/'.sha1($contents).'.blade.php')) {
if (! is_file($viewFile = $directory.'/'.sha1($contents).'.blade.php')) {
if (! is_dir($directory)) {
mkdir($directory, 0755, true);
}
@@ -115,7 +121,7 @@ abstract class Component
*/
public function data()
{
$this->attributes = $this->attributes ?: new ComponentAttributeBag;
$this->attributes = $this->attributes ?: $this->newAttributeBag();
return array_merge($this->extractPublicProperties(), $this->extractPublicMethods());
}
@@ -260,13 +266,24 @@ abstract class Component
*/
public function withAttributes(array $attributes)
{
$this->attributes = $this->attributes ?: new ComponentAttributeBag;
$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.
*

View File

@@ -8,12 +8,13 @@ use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Arr;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Macroable;
use IteratorAggregate;
class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
{
use Macroable;
use Conditionable, Macroable;
/**
* The raw array of attributes.
@@ -56,10 +57,21 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
return $this->attributes[$key] ?? value($default);
}
/**
* Determine if a given attribute exists in the attribute array.
*
* @param string $key
* @return bool
*/
public function has($key)
{
return array_key_exists($key, $this->attributes);
}
/**
* Only include the given attribute from the attribute array.
*
* @param mixed|array $keys
* @param mixed $keys
* @return static
*/
public function only($keys)
@@ -108,38 +120,38 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
/**
* Return a bag of attributes that have keys starting with the given value / pattern.
*
* @param string $string
* @param string|string[] $needles
* @return static
*/
public function whereStartsWith($string)
public function whereStartsWith($needles)
{
return $this->filter(function ($value, $key) use ($string) {
return Str::startsWith($key, $string);
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
* @param string|string[] $needles
* @return static
*/
public function whereDoesntStartWith($string)
public function whereDoesntStartWith($needles)
{
return $this->filter(function ($value, $key) use ($string) {
return ! Str::startsWith($key, $string);
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
* @param string|string[] $needles
* @return static
*/
public function thatStartWith($string)
public function thatStartWith($needles)
{
return $this->whereStartsWith($string);
return $this->whereStartsWith($needles);
}
/**
@@ -162,39 +174,108 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
return $this->except($props);
}
/**
* 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)]);
}
/**
* Merge additional attributes / values into the attribute bag.
*
* @param array $attributeDefaults
* @param bool $escape
* @return static
*/
public function merge(array $attributeDefaults = [])
public function merge(array $attributeDefaults = [], $escape = true)
{
$attributes = [];
$attributeDefaults = array_map(function ($value) {
if (is_null($value) || is_bool($value)) {
return $value;
}
return e($value);
$attributeDefaults = array_map(function ($value) use ($escape) {
return $this->shouldEscapeAttributeValue($escape, $value)
? e($value)
: $value;
}, $attributeDefaults);
foreach ($this->attributes as $key => $value) {
if ($key !== 'class') {
$attributes[$key] = $value;
[$appendableAttributes, $nonAppendableAttributes] = collect($this->attributes)
->partition(function ($value, $key) use ($attributeDefaults) {
return $key === 'class' ||
(isset($attributeDefaults[$key]) &&
$attributeDefaults[$key] instanceof AppendableAttributeValue);
});
continue;
}
$attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) {
$defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue
? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape)
: ($attributeDefaults[$key] ?? '');
$attributes[$key] = implode(' ', array_unique(
array_filter([$attributeDefaults[$key] ?? '', $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;
}
/**
* Get all of the raw attributes.
*
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Set the underlying attributes.
*
@@ -203,6 +284,15 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
*/
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;
}
@@ -233,6 +323,7 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
* @param string $offset
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->attributes[$offset]);
@@ -244,6 +335,7 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
* @param string $offset
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->get($offset);
@@ -256,6 +348,7 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
$this->attributes[$offset] = $value;
@@ -267,6 +360,7 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
* @param string $offset
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->attributes[$offset]);
@@ -277,6 +371,7 @@ class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
*
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->attributes);

View File

@@ -0,0 +1,89 @@
<?php
namespace Illuminate\View;
use Illuminate\Contracts\Support\Htmlable;
class ComponentSlot implements Htmlable
{
/**
* The slot attribute bag.
*
* @var \Illuminate\View\ComponentAttributeBag
*/
public $attributes;
/**
* The slot contents.
*
* @var string
*/
protected $contents;
/**
* Create a new slot instance.
*
* @param string $contents
* @param array $attributes
* @return void
*/
public function __construct($contents = '', $attributes = [])
{
$this->contents = $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();
}
/**
* Get the slot's HTML string.
*
* @return string
*/
public function __toString()
{
return $this->toHtml();
}
}

View File

@@ -2,11 +2,11 @@
namespace Illuminate\View\Concerns;
use Closure;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr;
use Illuminate\Support\HtmlString;
use Illuminate\View\View;
use InvalidArgumentException;
use Illuminate\View\ComponentSlot;
trait ManagesComponents
{
@@ -24,6 +24,13 @@ trait ManagesComponents
*/
protected $componentData = [];
/**
* The component data for the component that is currently being rendered.
*
* @var array
*/
protected $currentComponentData = [];
/**
* The slot contents for the component.
*
@@ -41,7 +48,7 @@ trait ManagesComponents
/**
* Start a component rendering process.
*
* @param \Illuminate\View\View|\Closure|string $view
* @param \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string $view
* @param array $data
* @return void
*/
@@ -81,16 +88,23 @@ trait ManagesComponents
{
$view = array_pop($this->componentStack);
$data = $this->componentData();
$this->currentComponentData = array_merge(
$previousComponentData = $this->currentComponentData,
$data = $this->componentData()
);
if ($view instanceof Closure) {
$view = $view($data);
}
try {
$view = value($view, $data);
if ($view instanceof View) {
return $view->with($data)->render();
} else {
return $this->make($view, $data)->render();
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;
}
}
@@ -101,30 +115,66 @@ trait ManagesComponents
*/
protected function componentData()
{
$defaultSlot = new HtmlString(trim(ob_get_clean()));
$slots = array_merge([
'__default' => $defaultSlot,
], $this->slots[count($this->componentStack)]);
return array_merge(
$this->componentData[count($this->componentStack)],
['slot' => new HtmlString(trim(ob_get_clean()))],
$this->slots[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)
public function slot($name, $content = null, $attributes = [])
{
if (func_num_args() > 2) {
throw new InvalidArgumentException('You passed too many arguments to the ['.$name.'] slot.');
} elseif (func_num_args() === 2) {
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;
$this->slotStack[$this->currentComponent()][] = [$name, $attributes];
}
}
@@ -141,8 +191,11 @@ trait ManagesComponents
$this->slotStack[$this->currentComponent()]
);
$this->slots[$this->currentComponent()]
[$currentSlot] = new HtmlString(trim(ob_get_clean()));
[$currentName, $currentAttributes] = $currentSlot;
$this->slots[$this->currentComponent()][$currentName] = new ComponentSlot(
trim(ob_get_clean()), $currentAttributes
);
}
/**
@@ -154,4 +207,16 @@ trait ManagesComponents
{
return count($this->componentStack) - 1;
}
/**
* Flush all of the component state.
*
* @return void
*/
protected function flushComponents()
{
$this->componentStack = [];
$this->componentData = [];
$this->currentComponentData = [];
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace Illuminate\View;
use Illuminate\Container\Container;
use Illuminate\Support\Str;
use Illuminate\View\Compilers\ComponentTagCompiler;
class DynamicComponent extends Component
{
/**
* The name of the component.
*
* @var string
*/
public $component;
/**
* The component tag compiler instance.
*
* @var \Illuminate\View\Compilers\BladeTagCompiler
*/
protected static $compiler;
/**
* The cached component classes.
*
* @var array
*/
protected static $componentClasses = [];
/**
* Create a new component instance.
*
* @param string $component
* @return void
*/
public function __construct(string $component)
{
$this->component = $component;
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|string
*/
public function render()
{
$template = <<<'EOF'
<?php extract(collect($attributes->getAttributes())->mapWithKeys(function ($value, $key) { return [Illuminate\Support\Str::camel(str_replace([':', '.'], ' ', $key)) => $value]; })->all(), EXTR_SKIP); ?>
{{ props }}
<x-{{ component }} {{ bindings }} {{ attributes }}>
{{ slots }}
{{ defaultSlot }}
</x-{{ component }}>
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 : '<x-slot name="'.$name.'" '.((string) $slot->attributes).'>{{ $'.$name.' }}</x-slot>';
})->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;
}
}

View File

@@ -2,6 +2,7 @@
namespace Illuminate\View\Engines;
use Illuminate\Filesystem\Filesystem;
use Illuminate\View\Compilers\CompilerInterface;
use Illuminate\View\ViewException;
use Throwable;
@@ -23,13 +24,16 @@ class CompilerEngine extends PhpEngine
protected $lastCompiled = [];
/**
* Create a new Blade view engine instance.
* 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)
public function __construct(CompilerInterface $compiler, Filesystem $files = null)
{
parent::__construct($files ?: new Filesystem);
$this->compiler = $compiler;
}

View File

@@ -32,7 +32,7 @@ class EngineResolver
*/
public function register($engine, Closure $resolver)
{
unset($this->resolved[$engine]);
$this->forget($engine);
$this->resolvers[$engine] = $resolver;
}
@@ -57,4 +57,15 @@ class EngineResolver
throw new InvalidArgumentException("Engine [{$engine}] not found.");
}
/**
* Remove a resolved engine.
*
* @param string $engine
* @return void
*/
public function forget($engine)
{
unset($this->resolved[$engine]);
}
}

View File

@@ -3,9 +3,28 @@
namespace Illuminate\View\Engines;
use Illuminate\Contracts\View\Engine;
use Illuminate\Filesystem\Filesystem;
class FileEngine implements Engine
{
/**
* The filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* Create a new file engine instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @return void
*/
public function __construct(Filesystem $files)
{
$this->files = $files;
}
/**
* Get the evaluated contents of the view.
*
@@ -15,6 +34,6 @@ class FileEngine implements Engine
*/
public function get($path, array $data = [])
{
return file_get_contents($path);
return $this->files->get($path);
}
}

View File

@@ -3,10 +3,29 @@
namespace Illuminate\View\Engines;
use Illuminate\Contracts\View\Engine;
use Illuminate\Filesystem\Filesystem;
use Throwable;
class PhpEngine implements Engine
{
/**
* The filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* Create a new file engine instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @return void
*/
public function __construct(Filesystem $files)
{
$this->files = $files;
}
/**
* Get the evaluated contents of the view.
*
@@ -22,23 +41,21 @@ class PhpEngine implements Engine
/**
* Get the evaluated contents of the view at the given path.
*
* @param string $__path
* @param array $__data
* @param string $path
* @param array $data
* @return string
*/
protected function evaluatePath($__path, $__data)
protected function evaluatePath($path, $data)
{
$obLevel = ob_get_level();
ob_start();
extract($__data, EXTR_SKIP);
// 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 {
include $__path;
$this->files->getRequire($path, $data);
} catch (Throwable $e) {
$this->handleViewException($e, $obLevel);
}

View File

@@ -189,6 +189,20 @@ class Factory implements FactoryContract
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.
*
@@ -467,6 +481,7 @@ class Factory implements FactoryContract
$this->flushSections();
$this->flushStacks();
$this->flushComponents();
}
/**

View File

@@ -38,7 +38,7 @@ class FileViewFinder implements ViewFinderInterface
/**
* Register a view extension with the finder.
*
* @var array
* @var string[]
*/
protected $extensions = ['blade.php', 'php', 'css', 'html'];

View File

@@ -43,6 +43,7 @@ class InvokableComponentVariable implements DeferringDisplayableValue, IteratorA
*
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$result = $this->__invoke();

View File

@@ -81,7 +81,7 @@ class View implements ArrayAccess, Htmlable, ViewContract
* Get the string contents of the view.
*
* @param callable|null $callback
* @return array|string
* @return string
*
* @throws \Throwable
*/
@@ -306,6 +306,7 @@ class View implements ArrayAccess, Htmlable, ViewContract
* @param string $key
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($key)
{
return array_key_exists($key, $this->data);
@@ -317,6 +318,7 @@ class View implements ArrayAccess, Htmlable, ViewContract
* @param string $key
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->data[$key];
@@ -329,6 +331,7 @@ class View implements ArrayAccess, Htmlable, ViewContract
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($key, $value)
{
$this->with($key, $value);
@@ -340,6 +343,7 @@ class View implements ArrayAccess, Htmlable, ViewContract
* @param string $key
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($key)
{
unset($this->data[$key]);

View File

@@ -19,11 +19,8 @@ class ViewServiceProvider extends ServiceProvider
public function register()
{
$this->registerFactory();
$this->registerViewFinder();
$this->registerBladeCompiler();
$this->registerEngineResolver();
}
@@ -88,7 +85,9 @@ class ViewServiceProvider extends ServiceProvider
public function registerBladeCompiler()
{
$this->app->singleton('blade.compiler', function ($app) {
return new BladeCompiler($app['files'], $app['config']['view.compiled']);
return tap(new BladeCompiler($app['files'], $app['config']['view.compiled']), function ($blade) {
$blade->component('dynamic-component', DynamicComponent::class);
});
});
}
@@ -122,7 +121,7 @@ class ViewServiceProvider extends ServiceProvider
public function registerFileEngine($resolver)
{
$resolver->register('file', function () {
return new FileEngine;
return new FileEngine($this->app['files']);
});
}
@@ -135,7 +134,7 @@ class ViewServiceProvider extends ServiceProvider
public function registerPhpEngine($resolver)
{
$resolver->register('php', function () {
return new PhpEngine;
return new PhpEngine($this->app['files']);
});
}
@@ -148,7 +147,7 @@ class ViewServiceProvider extends ServiceProvider
public function registerBladeEngine($resolver)
{
$resolver->register('blade', function () {
return new CompilerEngine($this->app['blade.compiler']);
return new CompilerEngine($this->app['blade.compiler'], $this->app['files']);
});
}
}

View File

@@ -14,13 +14,15 @@
}
],
"require": {
"php": "^7.2.5|^8.0",
"php": "^7.3|^8.0",
"ext-json": "*",
"illuminate/container": "^7.0",
"illuminate/contracts": "^7.0",
"illuminate/events": "^7.0",
"illuminate/filesystem": "^7.0",
"illuminate/support": "^7.0"
"illuminate/collections": "^8.0",
"illuminate/container": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/events": "^8.0",
"illuminate/filesystem": "^8.0",
"illuminate/macroable": "^8.0",
"illuminate/support": "^8.0"
},
"autoload": {
"psr-4": {
@@ -29,7 +31,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
"dev-master": "8.x-dev"
}
},
"config": {