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;
SSViewer::config()->update('rewrite_hash_links', false);
return $this;
}
public function exists()
{
return $this->chosen;
}
/**
* @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 = null)
{
return ThemeResourceLoader::instance()->findTemplate(['type' => $type, $identifier], self::get_themes());
}
/**
* 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 = 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 : 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 ViewableData $item The item to use as the root scope for the template
* @param array $overlay Any variables to layer on top of the scope
* @param array $underlay Any variables to layer underneath the scope
* @param ViewableData $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 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 ViewableData $inheritedScope The current scope of a parent template including a sub-template
* @return DBHTMLText Parsed template output.
*/
public function process($item, $arguments = null, $inheritedScope = null)
{
SSViewer::$topLevel[] = $item;
$template = $this->chosen;
$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) {
$sub = null;
if (isset($this->subTemplates[$subtemplate])) {
$sub = $this->subTemplates[$subtemplate];
} elseif (!is_array($this->templates)) {
$sub = ['type' => $subtemplate, $this->templates];
} elseif (!array_key_exists('type', $this->templates) || !$this->templates['type']) {
$sub = array_merge($this->templates, ['type' => $subtemplate]);
}
if ($sub) {
$subtemplateViewer = clone $this;
// Disable requirements - this will be handled by the parent template
$subtemplateViewer->includeRequirements(false);
// Select the right template
$subtemplateViewer->setTemplate($sub);
if ($subtemplateViewer->exists()) {
$underlay[$subtemplate] = $subtemplateViewer->process($item, $arguments);
}
}
}
$output = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay, $inheritedScope);
if ($this->includeRequirements) {
$output = Requirements::includeInHTML($output);
}
array_pop(SSViewer::$topLevel);
// If we have our crazy base tag, then fix # links referencing the current page.
$rewrite = SSViewer::config()->get('rewrite_hash_links');
if ($this->rewriteHashlinks && $rewrite) {
if (strpos($output, '";
} else {
$thisURLRelativeToBase = Convert::raw2att(preg_replace("/^(\\/)+/", "/", $_SERVER['REQUEST_URI']));
}
$output = preg_replace('/(