BUG Only include processed requirements at the top level. (Fixes #7847)

After each sub template was processed Requirements::includeInHTML() is included which appended requirements again.
This commit is contained in:
Will Rossiter 2012-11-04 12:59:40 +13:00
parent 39b2818f5f
commit dfd3455802
4 changed files with 95 additions and 11 deletions

View File

@ -0,0 +1,7 @@
<html>
<% include SSViewerTestProcessHead %>
<body>
<% include SSViewerTestCommentsWithInclude %>
</body>
</html>

View File

@ -0,0 +1,3 @@
<head>
<% require javascript(framework/tests/forms/RequirementsTest_a.js) %>
</head>

View File

@ -1025,6 +1025,42 @@ after')
$result = $viewer->process(new ArrayData(array('List' => $list))); $result = $viewer->process(new ArrayData(array('List' => $list)));
$this->assertEquals($result, ''); $this->assertEquals($result, '');
} }
public function testProcessOnlyIncludesRequirementsOnce() {
$template = new SSViewer(array('SSViewerTestProcess'));
$basePath = dirname($this->getCurrentRelativePath()) . '/forms';
$backend = new Requirements_Backend;
$backend->set_combined_files_enabled(false);
$backend->combine_files(
'RequirementsTest_ab.css',
array(
$basePath . '/RequirementsTest_a.css',
$basePath . '/RequirementsTest_b.css'
)
);
Requirements::set_backend($backend);
$this->assertEquals(1, substr_count($template->process(array()), "a.css"));
$this->assertEquals(1, substr_count($template->process(array()), "b.css"));
// if we disable the requirements then we should get nothing
$template->includeRequirements(false);
$this->assertEquals(0, substr_count($template->process(array()), "a.css"));
$this->assertEquals(0, substr_count($template->process(array()), "b.css"));
}
public function testRequireCallInTemplateInclude() {
$template = new SSViewer(array('SSViewerTestProcess'));
Requirements::set_suffix_requirements(false);
$this->assertEquals(1, substr_count(
$template->process(array()),
"tests/forms/RequirementsTest_a.js"
));
}
} }
/** /**

View File

@ -563,6 +563,11 @@ class SSViewer {
*/ */
protected static $current_custom_theme = null; protected static $current_custom_theme = null;
/**
* @var boolean
*/
protected $includeRequirements = true;
/** /**
* Create a template from a string instead of a .ss file * Create a template from a string instead of a .ss file
* *
@ -592,7 +597,7 @@ class SSViewer {
/** /**
* Returns the path to the theme folder * Returns the path to the theme folder
* *
* @return String * @return string
*/ */
public static function get_theme_folder() { public static function get_theme_folder() {
return self::current_theme() ? THEMES_DIR . "/" . self::current_theme() : project(); return self::current_theme() ? THEMES_DIR . "/" . self::current_theme() : project();
@ -667,7 +672,11 @@ class SSViewer {
} }
/** /**
* Returns true if at least one of the listed templates exists * Returns true if at least one of the listed templates exists.
*
* @param array $templates
*
* @return boolean
*/ */
public static function hasTemplate($templates) { public static function hasTemplate($templates) {
$manifest = SS_TemplateLoader::instance()->getManifest(); $manifest = SS_TemplateLoader::instance()->getManifest();
@ -681,20 +690,25 @@ class SSViewer {
/** /**
* Set a global rendering option. * Set a global rendering option.
*
* The following options are available: * The following options are available:
* - rewriteHashlinks: If true (the default), <a href="#..."> will be rewritten to contain the * - rewriteHashlinks: If true (the default), <a href="#..."> will be rewritten to contain the
* current URL. This lets it play nicely with our <base> tag. * current URL. This lets it play nicely with our <base> tag.
* - If rewriteHashlinks = 'php' then, a piece of PHP script will be inserted before the hash * - If rewriteHashlinks = 'php' then, a piece of PHP script will be inserted before the hash
* links: "<?php echo $_SERVER['REQUEST_URI']; ?>". This is useful if you're generating a * links: "<?php echo $_SERVER['REQUEST_URI']; ?>". This is useful if you're generating a
* page that will be saved to a .php file and may be accessed from different URLs. * page that will be saved to a .php file and may be accessed from different URLs.
*
* @param string $optionName
* @param mixed $optionVal
*/ */
public static function setOption($optionName, $optionVal) { public static function setOption($optionName, $optionVal) {
SSViewer::$options[$optionName] = $optionVal; SSViewer::$options[$optionName] = $optionVal;
} }
/** /**
* @param String * @param string
* @return Mixed *
* @return mixed
*/ */
public static function getOption($optionName) { public static function getOption($optionName) {
return SSViewer::$options[$optionName]; return SSViewer::$options[$optionName];
@ -705,6 +719,7 @@ class SSViewer {
); );
protected static $topLevel = array(); protected static $topLevel = array();
public static function topLevel() { public static function topLevel() {
if(SSViewer::$topLevel) { if(SSViewer::$topLevel) {
return SSViewer::$topLevel[sizeof(SSViewer::$topLevel)-1]; return SSViewer::$topLevel[sizeof(SSViewer::$topLevel)-1];
@ -728,6 +743,7 @@ class SSViewer {
/** /**
* @param string $identifier A template name without '.ss' extension or path * @param string $identifier A template name without '.ss' extension or path
* @param string $type The template type, either "main", "Includes" or "Layout" * @param string $type The template type, either "main", "Includes" or "Layout"
*
* @return string Full system path to a template file * @return string Full system path to a template file
*/ */
public static function getTemplateFileByType($identifier, $type) { public static function getTemplateFileByType($identifier, $type) {
@ -766,6 +782,7 @@ class SSViewer {
/** /**
* Set the cache object to use when storing / retrieving partial cache blocks. * Set the cache object to use when storing / retrieving partial cache blocks.
*
* @param Zend_Cache_Core $cache * @param Zend_Cache_Core $cache
*/ */
public function setPartialCacheStore($cache) { public function setPartialCacheStore($cache) {
@ -773,13 +790,23 @@ class SSViewer {
} }
/** /**
* Get the cache object to use when storing / retrieving partial cache blocks * Get the cache object to use when storing / retrieving partial cache blocks.
*
* @return Zend_Cache_Core * @return Zend_Cache_Core
*/ */
public function getPartialCacheStore() { public function getPartialCacheStore() {
return $this->partialCacheStore ? $this->partialCacheStore : SS_Cache::factory('cacheblock'); return $this->partialCacheStore ? $this->partialCacheStore : SS_Cache::factory('cacheblock');
} }
/**
* Flag whether to include the requirements in this response.
*
* @param boolean
*/
public function includeRequirements($incl = true) {
$this->includeRequirements = $incl;
}
/** /**
* An internal utility function to set up variables in preparation for including a compiled * An internal utility function to set up variables in preparation for including a compiled
* template, then do the include * template, then do the include
@ -790,6 +817,7 @@ class SSViewer {
* @param Object $item - The item to use as the root scope for the template * @param Object $item - The item to use as the root scope for the template
* @param array|null $overlay - Any variables to layer on top of the scope * @param array|null $overlay - Any variables to layer on top of the scope
* @param array|null $underlay - Any variables to layer underneath the scope * @param array|null $underlay - Any variables to layer underneath the scope
*
* @return string - The result of executing the template * @return string - The result of executing the template
*/ */
protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay) { protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay) {
@ -814,15 +842,18 @@ class SSViewer {
/** /**
* The process() method handles the "meat" of the template processing. * The process() method handles the "meat" of the template processing.
* It takes care of caching the output (via {@link SS_Cache}), *
* as well as replacing the special "$Content" and "$Layout" * It takes care of caching the output (via {@link SS_Cache}), as well as
* placeholders with their respective subtemplates. * replacing the special "$Content" and "$Layout" placeholders with their
* respective subtemplates.
*
* The method injects extra HTML in the header via {@link Requirements::includeInHTML()}. * The method injects extra HTML in the header via {@link Requirements::includeInHTML()}.
* *
* Note: You can call this method indirectly by {@link ViewableData->renderWith()}. * Note: You can call this method indirectly by {@link ViewableData->renderWith()}.
* *
* @param ViewableData $item * @param ViewableData $item
* @param SS_Cache $cache Optional cache backend * @param SS_Cache $cache Optional cache backend.
*
* @return String Parsed template output. * @return String Parsed template output.
*/ */
public function process($item, $arguments = null) { public function process($item, $arguments = null) {
@ -869,14 +900,18 @@ class SSViewer {
foreach(array('Content', 'Layout') as $subtemplate) { foreach(array('Content', 'Layout') as $subtemplate) {
if(isset($this->chosenTemplates[$subtemplate])) { if(isset($this->chosenTemplates[$subtemplate])) {
$subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate]); $subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate]);
$subtemplateViewer->includeRequirements(false);
$subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore()); $subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore());
$underlay[$subtemplate] = $subtemplateViewer->process($item, $arguments); $underlay[$subtemplate] = $subtemplateViewer->process($item, $arguments);
} }
} }
$val = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay); $output = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay);
$output = Requirements::includeInHTML($template, $val);
if($this->includeRequirements) {
$output = Requirements::includeInHTML($template, $output);
}
array_pop(SSViewer::$topLevel); array_pop(SSViewer::$topLevel);
@ -890,6 +925,7 @@ class SSViewer {
} else { } else {
$thisURLRelativeToBase = strip_tags($_SERVER['REQUEST_URI']); $thisURLRelativeToBase = strip_tags($_SERVER['REQUEST_URI']);
} }
$output = preg_replace('/(<a[^>]+href *= *)"#/i', '\\1"' . $thisURLRelativeToBase . '#', $output); $output = preg_replace('/(<a[^>]+href *= *)"#/i', '\\1"' . $thisURLRelativeToBase . '#', $output);
} }
} }
@ -903,6 +939,8 @@ class SSViewer {
*/ */
public static function execute_template($template, $data, $arguments = null) { public static function execute_template($template, $data, $arguments = null) {
$v = new SSViewer($template); $v = new SSViewer($template);
$v->includeRequirements(false);
return $v->process($data, $arguments); return $v->process($data, $arguments);
} }