summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--system/core/Loader.php51
-rw-r--r--tests/codeigniter/core/Loader_test.php15
2 files changed, 60 insertions, 6 deletions
diff --git a/system/core/Loader.php b/system/core/Loader.php
index d9a1539aa..fb8b73b1f 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -94,6 +94,13 @@ class CI_Loader {
protected $_ci_cached_vars = array();
/**
+ * Stack of variable arrays to provide nested _ci_load calls all variables from parent calls
+ *
+ * @var array
+ */
+ protected $_ci_load_vars_stack = array();
+
+ /**
* List of loaded classes
*
* @var array
@@ -934,15 +941,46 @@ class CI_Loader {
}
/*
- * Extract and cache variables
+ * Extract and stack variables
*
* You can either set variables using the dedicated $this->load->vars()
* function or via the second parameter of this function. We'll merge
- * the two types and cache them so that views that are embedded within
- * other views can have access to these variables.
+ * the two types so that loaded views and files have access to these
+ * variables.
+ * Additionally we want all subsequent nested _ci_load() calls embedded
+ * within the current file to 'inherit' all variables that are
+ * accessible to the current file. For this purpose we push the current
+ * variable configuration (_ci_vars) to the stack and remove it again
+ * after the file or view is completely loaded. Nested _ci_load() calls
+ * within the current file extend the stack with their variable
+ * configuration.
*/
- empty($_ci_vars) OR $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
- extract($this->_ci_cached_vars);
+
+ // Init current _ci_vars as current variable configuration
+ if ( ! is_array($_ci_vars))
+ {
+ $_ci_vars = [];
+ }
+
+ // Include the global cached vars into the current _ci_vars if needed
+ if ( ! empty($this->_ci_cached_vars))
+ {
+ $_ci_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
+ }
+
+ // Merge the last variable configuration from a parent _ci_load()
+ // call into the current _ci_vars
+ if ( ! empty($this->_ci_load_vars_stack))
+ {
+ $previous_variable_configuration = end($this->_ci_load_vars_stack);
+ $_ci_vars = array_merge($previous_variable_configuration, $_ci_vars);
+ }
+
+ // Push the current _ci_vars to the stack
+ array_push($this->_ci_load_vars_stack, $_ci_vars);
+
+ // Extract the current _ci_vars
+ extract($_ci_vars);
/**
* Buffer the output
@@ -960,6 +998,9 @@ class CI_Loader {
include($_ci_path); // include() vs include_once() allows for multiple views with the same name
log_message('info', 'File loaded: '.$_ci_path);
+ // Remove current _ci_vars from stack again
+ array_pop($this->_ci_load_vars_stack);
+
// Return the file data if requested
if ($_ci_return === TRUE)
{
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index 4fa6d6869..df9c9f44b 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -311,12 +311,16 @@ class Loader_test extends CI_TestCase {
$var = 'hello';
$value = 'World!';
$content = 'This is my test page. ';
- $this->ci_vfs_create($view, $content.'<?php echo $'.$var.';', $this->ci_app_root, 'views');
+ $this->ci_vfs_create($view, $content.'<?php echo (isset($'.$var.') ? $'.$var.' : "undefined");', $this->ci_app_root, 'views');
// Test returning view
$out = $this->load->view($view, array($var => $value), TRUE);
$this->assertEquals($content.$value, $out);
+ // Test view with missing parameter in $vars
+ $out = $this->load->view($view, [], TRUE);
+ $this->assertEquals($content.'undefined', $out);
+
// Mock output class
$output = $this->getMockBuilder('CI_Output')->setMethods(array('append_output'))->getMock();
$output->expects($this->once())->method('append_output')->with($content.$value);
@@ -326,6 +330,15 @@ class Loader_test extends CI_TestCase {
$vars = new stdClass();
$vars->$var = $value;
$this->assertInstanceOf('CI_Loader', $this->load->view($view, $vars));
+
+ // Create another view in VFS, nesting the first one without its own $vars
+ $nesting_view = 'unit_test_nesting_view';
+ $nesting_content = 'Here comes a nested view. ';
+ $this->ci_vfs_create($nesting_view, $nesting_content.'<?php $loader->view("'.$view.'");', $this->ci_app_root, 'views');
+
+ // Test $vars inheritance to nested views
+ $out = $this->load->view($nesting_view, array("loader" => $this->load, $var => $value), TRUE);
+ $this->assertEquals($nesting_content.$content.$value, $out);
}
// --------------------------------------------------------------------