From 85933facbc41d6a78ec52076222854ac71dfc04a Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 15 Aug 2015 11:05:30 +1000 Subject: [PATCH] Stack partials, store components, unstack partials - Fixes #1373 Fixes instances where nested repeating partials are destroying the partial component stack and causing breaking errors. Nesting example: Partial (with components) ^-> Calls component default markup ^-> Refers to partial override (with repeating partial calls) ^-> Calls another partial (with components) ^-> Components not found (destroyed by repeating calls above) --- modules/cms/classes/Controller.php | 23 ++++--- modules/cms/classes/PartialStack.php | 89 ++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 modules/cms/classes/PartialStack.php diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index c9bd323bb..37b781b00 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -111,7 +111,7 @@ class Controller /** * @var array Component partial stack, used internally. */ - protected $partialComponentStack = []; + protected $partialStack = []; /** * Creates the controller. @@ -127,6 +127,7 @@ class Controller $this->assetPath = Config::get('cms.themesPath', '/themes').'/'.$this->theme->getDirName(); $this->router = new Router($this->theme); + $this->partialStack = new PartialStack; $this->initTwigEnvironment(); self::$instance = $this; @@ -847,6 +848,8 @@ class Controller */ if ($partial instanceof Partial) { + $this->partialStack->stackPartial(); + $manager = ComponentManager::instance(); foreach ($partial->settings['components'] as $component => $properties) { @@ -868,10 +871,7 @@ class Controller $componentObj->alias = $alias; $parameters[$alias] = $partial->components[$alias] = $componentObj; - array_push($this->partialComponentStack, [ - 'name' => $alias, - 'obj' => $componentObj - ]); + $this->partialStack->addComponent($alias, $componentObj); $this->setComponentPropertiesFromParams($componentObj, $parameters); $componentObj->init(); @@ -890,7 +890,7 @@ class Controller } /* - * Render the parital + * Render the partial */ CmsException::mask($partial, 400); $this->loader->setObject($partial); @@ -899,9 +899,7 @@ class Controller CmsException::unmask(); if ($partial instanceof Partial) { - if ($this->partialComponentStack) { - array_pop($this->partialComponentStack); - } + $this->partialStack->unstackPartial(); } $this->vars = $vars; @@ -1224,10 +1222,9 @@ class Controller return $this->layout->components[$name]; } - foreach ($this->partialComponentStack as $componentInfo) { - if ($componentInfo['name'] == $name) { - return $componentInfo['obj']; - } + $partialComponent = $this->partialStack->getComponent($name); + if ($partialComponent !== null) { + return $partialComponent; } return null; diff --git a/modules/cms/classes/PartialStack.php b/modules/cms/classes/PartialStack.php new file mode 100644 index 000000000..7779d1833 --- /dev/null +++ b/modules/cms/classes/PartialStack.php @@ -0,0 +1,89 @@ +activePartial !== null) { + array_unshift($this->partialStack, $this->activePartial); + } + + $this->activePartial = [ + 'components' => [] + ]; + } + + /** + * Partial exit point, removes the active partial from the stack. + */ + public function unstackPartial() + { + $this->activePartial = array_shift($this->partialStack); + } + + /** + * Adds a component to the active partial stack. + */ + public function addComponent($alias, $componentObj) + { + array_push($this->activePartial['components'], [ + 'name' => $alias, + 'obj' => $componentObj + ]); + } + + /** + * Returns a component by its alias from the partial stack. + */ + public function getComponent($name) + { + $component = $this->findComponentFromStack($name, $this->activePartial); + if ($component !== null) { + return $component; + } + + foreach ($this->partialStack as $stack) { + $component = $this->findComponentFromStack($name, $stack); + if ($component !== null) { + return $component; + } + } + + return null; + } + + /** + * Locates a component by its alias from the supplied stack. + */ + protected function findComponentFromStack($name, $stack) + { + foreach ($stack['components'] as $componentInfo) { + if ($componentInfo['name'] == $name) { + return $componentInfo['obj']; + } + } + + return null; + } +}