links. This is useful in Ajax applications.
* It returns the SSViewer objects, so that you can call new SSViewer("X")->dontRewriteHashlinks()->process();
*/
public function dontRewriteHashlinks() {
$this->rewriteHashlinks = false;
Config::inst()->update('SSViewer', 'rewrite_hash_links', false);
return $this;
}
public function exists() {
return $this->chosenTemplates;
}
/**
* @param string $identifier A template name without '.ss' extension or path
* @param string $type The template type, either "main", "Includes" or "Layout"
*
* @return string Full system path to a template file
*/
public static function getTemplateFileByType($identifier, $type) {
$loader = SS_TemplateLoader::instance();
if(Config::inst()->get('SSViewer', 'theme_enabled')) {
$theme = Config::inst()->get('SSViewer', 'theme');
} else {
$theme = null;
}
$found = $loader->findTemplates("$type/$identifier", $theme);
if (isset($found['main'])) {
return $found['main'];
}
else if (!empty($found)) {
$founds = array_values($found);
return $founds[0];
}
}
/**
* Clears all parsed template files in the cache folder.
*
* Can only be called once per request (there may be multiple SSViewer instances).
*
* @param bool $force Set this to true to force a re-flush. If left to false, flushing
* may only be performed once a request.
*/
public static function flush_template_cache($force = false) {
if (!self::$template_cache_flushed || $force) {
$dir = dir(TEMP_FOLDER);
while (false !== ($file = $dir->read())) {
if (strstr($file, '.cache')) unlink(TEMP_FOLDER . '/' . $file);
}
self::$template_cache_flushed = true;
}
}
/**
* Clears all partial cache blocks.
*
* Can only be called once per request (there may be multiple SSViewer instances).
*
* @param bool $force Set this to true to force a re-flush. If left to false, flushing
* may only be performed once a request.
*/
public static function flush_cacheblock_cache($force = false) {
if (!self::$cacheblock_cache_flushed || $force) {
$cache = SS_Cache::factory('cacheblock');
$backend = $cache->getBackend();
if(
$backend instanceof Zend_Cache_Backend_ExtendedInterface
&& ($capabilities = $backend->getCapabilities())
&& $capabilities['tags']
) {
$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $cache->getTags());
} else {
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
}
self::$cacheblock_cache_flushed = true;
}
}
/**
* @var Zend_Cache_Core
*/
protected $partialCacheStore = null;
/**
* Set the cache object to use when storing / retrieving partial cache blocks.
*
* @param Zend_Cache_Core $cache
*/
public function setPartialCacheStore($cache) {
$this->partialCacheStore = $cache;
}
/**
* Get the cache object to use when storing / retrieving partial cache blocks.
*
* @return Zend_Cache_Core
*/
public function getPartialCacheStore() {
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
* template, then do the include
*
* Effectively this is the common code that both SSViewer#process and SSViewer_FromString#process call
*
* @param string $cacheFile - The path to the file that contains the template compiled to PHP
* @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 $underlay - Any variables to layer underneath the scope
* @param Object $inheritedScope - the current scope of a parent template including a sub-template
*
* @return string - The result of executing the template
*/
protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay, $inheritedScope = null) {
if(isset($_GET['showtemplate']) && $_GET['showtemplate'] && Permission::check('ADMIN')) {
$lines = file($cacheFile);
echo "Template: $cacheFile
";
echo "";
foreach($lines as $num => $line) {
echo str_pad($num+1,5) . htmlentities($line, ENT_COMPAT, 'UTF-8');
}
echo "
";
}
$cache = $this->getPartialCacheStore();
$scope = new SSViewer_DataPresenter($item, $overlay, $underlay, $inheritedScope);
$val = '';
include($cacheFile);
return $val;
}
/**
* 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" placeholders with their
* respective subtemplates.
*
* The method injects extra HTML in the header via {@link Requirements::includeInHTML()}.
*
* Note: You can call this method indirectly by {@link ViewableData->renderWith()}.
*
* @param ViewableData $item
* @param array|null $arguments - arguments to an included template
* @param Object $inheritedScope - the current scope of a parent template including a sub-template
*
* @return HTMLText Parsed template output.
*/
public function process($item, $arguments = null, $inheritedScope = null) {
SSViewer::$topLevel[] = $item;
if(isset($this->chosenTemplates['main'])) {
$template = $this->chosenTemplates['main'];
} else {
$keys = array_keys($this->chosenTemplates);
$key = reset($keys);
$template = $this->chosenTemplates[$key];
}
$cacheFile = TEMP_FOLDER . "/.cache"
. str_replace(array('\\','/',':'), '.', Director::makeRelative(realpath($template)));
$lastEdited = filemtime($template);
if(!file_exists($cacheFile) || filemtime($cacheFile) < $lastEdited) {
$content = file_get_contents($template);
$content = $this->parseTemplateContent($content, $template);
$fh = fopen($cacheFile,'w');
fwrite($fh, $content);
fclose($fh);
}
$underlay = array('I18NNamespace' => basename($template));
// Makes the rendered sub-templates available on the parent item,
// through $Content and $Layout placeholders.
foreach(array('Content', 'Layout') as $subtemplate) {
if(isset($this->chosenTemplates[$subtemplate])) {
$subtemplateViewer = clone $this;
// Disable requirements - this will be handled by the parent template
$subtemplateViewer->includeRequirements(false);
// The subtemplate is the only file we want to process, so set it as the "main" template file
$subtemplateViewer->chosenTemplates = array('main' => $this->chosenTemplates[$subtemplate]);
$underlay[$subtemplate] = $subtemplateViewer->process($item, $arguments);
}
}
$output = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay, $inheritedScope);
if($this->includeRequirements) {
$output = Requirements::includeInHTML($template, $output);
}
array_pop(SSViewer::$topLevel);
// If we have our crazy base tag, then fix # links referencing the current page.
$rewrite = Config::inst()->get('SSViewer', 'rewrite_hash_links');
if($this->rewriteHashlinks && $rewrite) {
if(strpos($output, '";
} else {
$thisURLRelativeToBase = Convert::raw2att($_SERVER['REQUEST_URI']);
}
$output = preg_replace('/(