diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php
index c418fc4d06b8..a43a76aec0a8 100755
--- a/src/Illuminate/Events/Dispatcher.php
+++ b/src/Illuminate/Events/Dispatcher.php
@@ -66,6 +66,13 @@ class Dispatcher implements DispatcherContract
*/
protected $transactionManagerResolver;
+ /**
+ * The cache of events that have listeners.
+ *
+ * @var array
+ */
+ protected $listenerCache = [];
+
/**
* Create a new event dispatcher instance.
*
@@ -107,6 +114,8 @@ public function listen($events, $listener = null)
$this->listeners[$event][] = $listener;
}
}
+
+ $this->listenerCache = [];
}
/**
@@ -131,9 +140,15 @@ protected function setupWildcardListen($event, $listener)
*/
public function hasListeners($eventName)
{
- return isset($this->listeners[$eventName]) ||
+ if (isset($this->listenerCache[$eventName])) {
+ return $this->listenerCache[$eventName];
+ }
+
+ $this->listenerCache[$eventName] = isset($this->listeners[$eventName]) ||
isset($this->wildcards[$eventName]) ||
$this->hasWildcardListeners($eventName);
+
+ return $this->listenerCache[$eventName];
}
/**
@@ -703,6 +718,8 @@ public function forget($event)
unset($this->wildcardsCache[$key]);
}
}
+
+ $this->listenerCache = [];
}
/**
diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php
index eba64365626b..f9601e04250d 100644
--- a/src/Illuminate/View/AnonymousComponent.php
+++ b/src/Illuminate/View/AnonymousComponent.php
@@ -25,10 +25,11 @@ class AnonymousComponent extends Component
* @param array $data
* @return void
*/
- public function __construct($view, $data)
+ public function __construct($view, $data, Factory $factory)
{
$this->view = $view;
$this->data = $data;
+ self::$factory = $factory;
}
/**
@@ -41,6 +42,29 @@ public function render()
return $this->view;
}
+ /**
+ * Resolve the component instance with the given data.
+ *
+ * @param array $data
+ * @return static
+ */
+ public static function resolve($data)
+ {
+ return new static($data['view'], $data['data'], $data['factory']);
+ }
+
+ /**
+ * Resolve the Blade view or view file that should be used when rendering the component.
+ *
+ * @return string
+ */
+ public function resolveView()
+ {
+ $view = $this->render();
+
+ return $this->extractBladeViewFromString($view);
+ }
+
/**
* Get the data that should be supplied to the view.
*
diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php
index 7ec15ac96f74..f1febb6c9727 100755
--- a/src/Illuminate/View/Compilers/Compiler.php
+++ b/src/Illuminate/View/Compilers/Compiler.php
@@ -44,6 +44,13 @@ abstract class Compiler
*/
protected $compiledExtension = 'php';
+ /**
+ * The cache of compiled paths.
+ *
+ * @var array
+ */
+ protected $compiledPathCache = [];
+
/**
* Create a new compiler instance.
*
@@ -82,7 +89,7 @@ public function __construct(
*/
public function getCompiledPath($path)
{
- return $this->cachePath.'/'.hash('xxh128', 'v2'.Str::after($path, $this->basePath)).'.'.$this->compiledExtension;
+ return $this->compiledPathCache[$path] ??= $this->cachePath.'/'.hash('xxh128', 'v2'.Str::after($path, $this->basePath)).'.'.$this->compiledExtension;
}
/**
diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php
index 9c3d6adbec99..c726f3fb8e98 100644
--- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php
+++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php
@@ -251,6 +251,7 @@ protected function componentString(string $component, array $attributes)
$parameters = [
'view' => $view,
'data' => '['.$this->attributesToString($data->all(), $escapeBound = false).']',
+ 'factory' => '$__env',
];
$class = AnonymousComponent::class;
@@ -776,9 +777,17 @@ protected function attributesToString(array $attributes, $escapeBound = true)
{
return collect($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}";
+ $shouldSanitize = $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value);
+
+ if ($shouldSanitize) {
+ $value = \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute($value);
+
+ if (is_string($value)) {
+ return "'{$attribute}' => '{$value}'";
+ }
+ }
+
+ return "'{$attribute}' => {$value}";
})
->implode(',');
}
diff --git a/src/Illuminate/View/Concerns/ManagesComponents.php b/src/Illuminate/View/Concerns/ManagesComponents.php
index 456e6a044e5d..ab6fc54fb474 100644
--- a/src/Illuminate/View/Concerns/ManagesComponents.php
+++ b/src/Illuminate/View/Concerns/ManagesComponents.php
@@ -56,9 +56,11 @@ public function startComponent($view, array $data = [])
if (ob_start()) {
$this->componentStack[] = $view;
- $this->componentData[$this->currentComponent()] = $data;
+ $currentComponent = $this->currentComponent();
- $this->slots[$this->currentComponent()] = [];
+ $this->componentData[$currentComponent] = $data;
+
+ $this->slots[$currentComponent] = [];
}
}
diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php
index bc6e59d55afd..2db93d8cdd01 100755
--- a/src/Illuminate/View/Factory.php
+++ b/src/Illuminate/View/Factory.php
@@ -2,14 +2,15 @@
namespace Illuminate\View;
-use Illuminate\Contracts\Container\Container;
-use Illuminate\Contracts\Events\Dispatcher;
-use Illuminate\Contracts\Support\Arrayable;
-use Illuminate\Contracts\View\Factory as FactoryContract;
use Illuminate\Support\Arr;
+use InvalidArgumentException;
use Illuminate\Support\Traits\Macroable;
+use Illuminate\Contracts\Events\Dispatcher;
+use Illuminate\Contracts\Support\Arrayable;
use Illuminate\View\Engines\EngineResolver;
-use InvalidArgumentException;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Contracts\Container\Container;
+use Illuminate\Contracts\View\Factory as FactoryContract;
class Factory implements FactoryContract
{
@@ -104,6 +105,20 @@ class Factory implements FactoryContract
*/
protected $normalizedNameCache = [];
+ /**
+ * Flag to determine if renderable shared data cache is set.
+ *
+ * @var boolean
+ */
+ protected $renderableSharedCacheIsSet = false;
+
+ /**
+ * The cache of shared data with objects cast to strings.
+ *
+ * @var array
+ */
+ protected $renderableSharedCache = [];
+
/**
* Create a new view factory instance.
*
@@ -358,6 +373,8 @@ public function share($key, $value = null)
$this->shared[$key] = $value;
}
+ $this->renderableSharedCacheIsSet = false;
+
return $value;
}
@@ -631,4 +648,22 @@ public function getShared()
{
return $this->shared;
}
+
+ public function getRenderableShared()
+ {
+ if ($this->renderableSharedCacheIsSet) {
+ return $this->renderableSharedCache;
+ }
+
+ $this->renderableSharedCache = $this->getShared();
+ foreach ($this->renderableSharedCache as $key => $value) {
+ if ($value instanceof Renderable) {
+ $this->renderableSharedCache[$key] = $value->render();
+ }
+ }
+
+ $this->renderableSharedCacheIsSet = true;
+
+ return $this->renderableSharedCache;
+ }
}
diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php
index 0751a8dff5ba..8cd0037b3fa3 100755
--- a/src/Illuminate/View/View.php
+++ b/src/Illuminate/View/View.php
@@ -215,7 +215,7 @@ protected function getContents()
*/
public function gatherData()
{
- $data = array_merge($this->factory->getShared(), $this->data);
+ $data = $this->data;
foreach ($data as $key => $value) {
if ($value instanceof Renderable) {
@@ -223,7 +223,7 @@ public function gatherData()
}
}
- return $data;
+ return array_merge($this->factory->getRenderableShared(), $data);
}
/**
@@ -305,7 +305,7 @@ protected function formatErrors($provider)
*/
public function name()
{
- return $this->getName();
+ return $this->view;
}
/**
diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php
index 38a4a037b21a..2fa1f4d28a59 100644
--- a/tests/View/Blade/BladeComponentTagCompilerTest.php
+++ b/tests/View/Blade/BladeComponentTagCompilerTest.php
@@ -474,7 +474,7 @@ public function testClasslessComponents()
$result = $this->compiler()->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -493,7 +493,7 @@ public function testClasslessComponentsWithIndexView()
$result = $this->compiler()->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -512,7 +512,7 @@ public function testPackagesClasslessComponents()
$result = $this->compiler()->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -546,7 +546,7 @@ public function testClasslessComponentsWithAnonymousComponentNamespace()
$result = $compiler->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'frontend::anonymous-component', ['view' => 'public.frontend.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'frontend::anonymous-component', ['view' => 'public.frontend.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -580,7 +580,7 @@ public function testClasslessComponentsWithAnonymousComponentNamespaceWithIndexV
$result = $compiler->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'admin.auth::anonymous-component', ['view' => 'admin.auth.components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'admin.auth::anonymous-component', ['view' => 'admin.auth.components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -613,7 +613,7 @@ public function testClasslessComponentsWithAnonymousComponentPath()
$result = $compiler->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel.index','data' => []])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel.index','data' => [],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
@@ -646,7 +646,7 @@ public function testClasslessIndexComponentsWithAnonymousComponentPath()
$result = $compiler->compileTags('');
- $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel','data' => []])
+ $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel','data' => [],'factory' => \$__env])
except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>