Skip to content

Commit

Permalink
Initial integration of HelperCollection into View.
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Aug 11, 2010
1 parent 16d5b26 commit c15d228
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 145 deletions.
161 changes: 49 additions & 112 deletions cake/libs/view/view.php
Expand Up @@ -22,6 +22,7 @@
* Included libraries.
*/
App::import('Core', 'ClassRegistry');
App::import('View', 'HelperCollection', false);
App::import('View', 'Helper', false);

/**
Expand All @@ -34,6 +35,12 @@
*/
class View extends Object {

/**
* Helpers collection
*
* @var HelperCollection
*/
public $Helpers;
/**
* Path parts for creating links in views.
*
Expand Down Expand Up @@ -197,14 +204,6 @@ class View extends Object {
*/
public $hasRendered = false;

/**
* Array of loaded view helpers.
*
* @var array
* @access public
*/
public $loaded = array();

/**
* True if in scope of model-specific region
*
Expand Down Expand Up @@ -312,6 +311,7 @@ function __construct(&$controller, $register = true) {
$this->{$var} = $controller->{$var};
}
}
$this->Helpers = new HelperCollection($this);
parent::__construct();

if ($register) {
Expand Down Expand Up @@ -380,7 +380,6 @@ public function element($name, $params = array(), $loadHelpers = false) {
}

if (is_file($file)) {
$params = array_merge_recursive($params, $this->loaded);
$element = $this->_render($file, array_merge($this->viewVars, $params), $loadHelpers);
if (isset($params['cache']) && isset($cacheFile) && isset($expires)) {
cache('views' . DS . $cacheFile, $element, $expires);
Expand Down Expand Up @@ -472,19 +471,19 @@ public function renderLayout($content_for_layout, $layout = null) {
$loadHelpers = true;
} else {
$loadHelpers = false;
$dataForLayout = array_merge($dataForLayout, $this->loaded);
$dataForLayout = array_merge($dataForLayout);
}

$this->_triggerHelpers('beforeLayout');
$this->Helpers->trigger('beforeLayout', array(&$this));
$this->output = $this->_render($layoutFileName, $dataForLayout, $loadHelpers, true);

if ($this->output === false) {
$this->output = $this->_render($layoutFileName, $data_for_layout);
trigger_error(sprintf(__("Error in layout %s, got: <blockquote>%s</blockquote>"), $layoutFileName, $this->output), E_USER_ERROR);
return false;
}

$this->_triggerHelpers('afterLayout');
$this->Helpers->trigger('afterLayout', array(&$this));

return $this->output;
}
Expand All @@ -498,18 +497,7 @@ public function renderLayout($content_for_layout, $layout = null) {
* @return void
*/
function _triggerHelpers($callback) {
if (empty($this->loaded)) {
return false;
}
$helpers = array_keys($this->loaded);
foreach ($helpers as $helperName) {
$helper =& $this->loaded[$helperName];
if (is_object($helper)) {
if (is_subclass_of($helper, 'Helper')) {
$helper->{$callback}();
}
}
}
$this->Helpers->trigger($callback, array(&$this));
}

/**
Expand Down Expand Up @@ -672,6 +660,33 @@ public function error($code, $name, $message) {
));
}

/**
* Magic accessor for helpers.
*
* @return void
*/
public function __get($name) {
if (isset($this->Helpers->{$name})) {
return $this->Helpers->{$name};
}
return null;
}

/**
* Interact with the HelperCollection to load all the helpers.
*
* @return void
*/
public function loadHelpers() {
foreach ($this->helpers as $i => $helper) {
$options = array();
if (!is_int($i)) {
list($options, $helper) = array($helper, $i);
}
$this->Helpers->load($helper, $options, true);
}
}

/**
* Renders and returns output for given view filename with its
* array of data.
Expand All @@ -685,23 +700,11 @@ public function error($code, $name, $message) {
protected function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) {
$loadedHelpers = array();

if ($this->helpers != false && $loadHelpers === true) {
$loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);
$helpers = array_keys($loadedHelpers);
$helperNames = array_map(array('Inflector', 'variable'), $helpers);

for ($i = count($helpers) - 1; $i >= 0; $i--) {
$name = $helperNames[$i];
$helper =& $loadedHelpers[$helpers[$i]];

if (!isset($___dataForView[$name])) {
${$name} =& $helper;
}
$this->loaded[$helperNames[$i]] =& $helper;
$this->{$helpers[$i]} =& $helper;
}
$this->_triggerHelpers('beforeRender');
unset($name, $loadedHelpers, $helpers, $i, $helperNames, $helper);
$attached = $this->Helpers->attached();
if (count($attached) == 0 && $loadHelpers === true) {
$this->loadHelpers();
$this->Helpers->trigger('beforeRender', array(&$this));
unset($attached);
}

extract($___dataForView, EXTR_SKIP);
Expand All @@ -714,7 +717,7 @@ protected function _render($___viewFn, $___dataForView, $loadHelpers = true, $ca
}

if ($loadHelpers === true) {
$this->_triggerHelpers('afterRender');
$this->Helpers->trigger('afterRender', array(&$this));
}

$out = ob_get_clean();
Expand All @@ -724,8 +727,8 @@ protected function _render($___viewFn, $___dataForView, $loadHelpers = true, $ca
);

if ($caching) {
if (is_a($this->loaded['cache'], 'CacheHelper')) {
$cache =& $this->loaded['cache'];
if (isset($this->Helpers->Cache)) {
$cache =& $this->Helpers->Cache;
$cache->base = $this->base;
$cache->here = $this->here;
$cache->helpers = $this->helpers;
Expand All @@ -747,73 +750,7 @@ protected function _render($___viewFn, $___dataForView, $loadHelpers = true, $ca
* @return Helper a constructed helper object.
*/
public function loadHelper($helperName, $settings = array()) {
return $this->Helpers->load($helperName, $settings);
}

/**
* Loads helpers, with their dependencies.
*
* @param array $loaded List of helpers that are already loaded.
* @param array $helpers List of helpers to load.
* @param string $parent holds name of helper, if loaded helper has helpers
* @return array Array containing the loaded helpers.
*/
protected function &_loadHelpers(&$loaded, $helpers, $parent = null) {
foreach ($helpers as $i => $helper) {
$options = array();

if (!is_int($i)) {
$options = $helper;
$helper = $i;
}
list($plugin, $helper) = pluginSplit($helper, true, $this->plugin);
$helperCn = $helper . 'Helper';

if (!isset($loaded[$helper])) {
if (!class_exists($helperCn)) {
$isLoaded = false;
if (!is_null($plugin)) {
$isLoaded = App::import('Helper', $plugin . $helper);
}
if (!$isLoaded) {
if (!App::import('Helper', $helper)) {
$this->cakeError('missingHelperFile', array(array(
'helper' => $helper,
'file' => Inflector::underscore($helper) . '.php',
'base' => $this->base
)));
return false;
}
}
if (!class_exists($helperCn)) {
$this->cakeError('missingHelperClass', array(array(
'helper' => $helper,
'file' => Inflector::underscore($helper) . '.php',
'base' => $this->base
)));
return false;
}
}
$loaded[$helper] =& new $helperCn($options);
$vars = array('base', 'webroot', 'here', 'params', 'action', 'data', 'theme', 'plugin');
$c = count($vars);

for ($j = 0; $j < $c; $j++) {
$loaded[$helper]->{$vars[$j]} = $this->{$vars[$j]};
}

if (!empty($this->validationErrors)) {
$loaded[$helper]->validationErrors = $this->validationErrors;
}
if (is_array($loaded[$helper]->helpers) && !empty($loaded[$helper]->helpers)) {
$loaded =& $this->_loadHelpers($loaded, $loaded[$helper]->helpers, $helper);
}
}
if (isset($loaded[$parent])) {
$loaded[$parent]->{$helper} =& $loaded[$helper];
}
}
return $loaded;
return $this->Helpers->load($helperName, $settings, true);
}

/**
Expand Down
59 changes: 26 additions & 33 deletions cake/tests/cases/libs/view/view.test.php
Expand Up @@ -122,19 +122,6 @@ function getLayoutFileName($name = null) {
return $this->_getLayoutFileName($name);
}

/**
* loadHelpers method
*
* @param mixed $loaded
* @param mixed $helpers
* @param mixed $parent
* @access public
* @return void
*/
function loadHelpers(&$loaded, $helpers, $parent = null) {
return $this->_loadHelpers($loaded, $helpers, $parent);
}

/**
* paths method
*
Expand Down Expand Up @@ -559,26 +546,31 @@ function testElementCache() {

}

/**
* test __get allowing access to helpers.
*
* @return void
*/
function test__get() {
$View = new View($this->PostsController);
$View->loadHelper('Html');
$this->assertType('HtmlHelper', $View->Html);
}

/**
* testLoadHelpers method
*
* @access public
* @return void
*/
function testLoadHelpers() {
$View = new TestView($this->PostsController);
$View = new View($this->PostsController);

$loaded = array();
$result = $View->loadHelpers($loaded, array('Html', 'Form', 'Paginator'));
$this->assertTrue(is_object($result['Html']));
$this->assertTrue(is_object($result['Form']));
$this->assertTrue(is_object($result['Form']->Html));
$this->assertTrue(is_object($result['Paginator']->Html));
$View->helpers = array('Html', 'Form');
$View->loadHelpers();

$View->plugin = 'test_plugin';
$result = $View->loadHelpers($loaded, array('TestPlugin.PluggedHelper'));
$this->assertTrue(is_object($result['PluggedHelper']));
$this->assertTrue(is_object($result['PluggedHelper']->OtherHelper));
$this->assertType('HtmlHelper', $View->Html, 'Object type is wrong.');
$this->assertType('FormHelper', $View->Form, 'Object type is wrong.');
}

/**
Expand All @@ -589,13 +581,14 @@ function testLoadHelpers() {
function testHelperCallbackTriggering() {
$mockHelper = $this->getMock('Helper', array(), array(), 'CallbackMockHelper');
$this->PostsController->helpers = array('Session', 'Html', 'CallbackMock');
$View = new TestView($this->PostsController);
$loaded = array();
$View->loaded = $View->loadHelpers($loaded, $this->PostsController->helpers);
$View->loaded['CallbackMock']->expects($this->once())->method('beforeRender');
$View->loaded['CallbackMock']->expects($this->once())->method('afterRender');
$View->loaded['CallbackMock']->expects($this->once())->method('beforeLayout');
$View->loaded['CallbackMock']->expects($this->once())->method('afterLayout');

$View = new View($this->PostsController);
$View->loadHelpers();

$View->Helpers->CallbackMock->expects($this->once())->method('beforeRender');
$View->Helpers->CallbackMock->expects($this->once())->method('afterRender');
$View->Helpers->CallbackMock->expects($this->once())->method('beforeLayout');
$View->Helpers->CallbackMock->expects($this->once())->method('afterLayout');
$View->render('index');
}

Expand Down Expand Up @@ -725,8 +718,8 @@ function testRenderLayoutWithMockCacheHelper() {
$Controller = new ViewPostsController();
$Controller->cacheAction = '1 day';
$View = new View($Controller);
$View->loaded['cache'] = $this->getMock('CacheHelper');
$View->loaded['cache']->expects($this->exactly(2))->method('cache');
$View->Helpers->Cache = $this->getMock('CacheHelper');
$View->Helpers->Cache->expects($this->exactly(2))->method('cache');

$result = $View->render('index');
$this->assertPattern('/posts index/', $result);
Expand Down

0 comments on commit c15d228

Please sign in to comment.