* * Modification History: * * 2005/08/30 - Created. JTL * 2005/08/31 - Now uses ob nesting so RSS can write its headers. JTL * 2005/09/09 - Added ability to include data set in command. JTL * 2005/09/09 - template() was not available from within RSS. JTL */ define('TEMPLATECOMMAND_CONTENT_ERROR', '_INVALID_TEMPLATE_CONTENT_'); define('TEMPLATECOMMAND_DATA_NOT_FOUND', '_DATA_SET_NOT_FOUND_'); define('TEMPLATECOMMAND_TEMPLATE_NOT_FOUND', '_TEMPLATE_NOT_FOUND_'); class CommandPluginExtension_template extends CommandPluginExtension { function getCachedData($embedding, $params, $paramHash, $content, &$errorMessage) // STATIC { // Extract the template file name and data set ID. $barPos = strpos($content, '|'); if($barPos === false) { $errorMessage = TEMPLATECOMMAND_CONTENT_ERROR; return; } /* next lines work even if get empty strings */ $templateName = trim(substr($content, 0, $barPos)); $dataSet = trim(substr($content, $barPos + 1)); if($templateName == '' || $dataSet == '') { $errorMessage = TEMPLATECOMMAND_CONTENT_ERROR; return; } $templateFN = CommandPluginExtension_template::template($templateName); if(strlen($dataSet) >= 3 && substr($dataSet, 0, 3) == '...') { $dataSetType = 'text'; $dataSet = substr($dataSet, 3); } else $dataSetType = 'id'; // Cache the page if caller allows it. if(isset($paramHash['_cache'])) { $errorMessage = CommandPluginExtension_template::resolve( $templateFN, $dataSetType, $dataSet); if($errorMessage) return; return CommandPluginExtension_template::generate( $templateFN, $dataSetType, $dataSet, $paramHash); } // Cache info needed to dynamically load page. return array($templateFN, $dataSetType, $dataSet, $paramHash); } function runCommand($embedding, $cachedData, &$renderer, &$errorMessage) // STATIC { if(is_string($cachedData)) return $cachedData; list($templateFN, $dataSetType, $dataSet, $paramHash) = $cachedData; $errorMessage = CommandPluginExtension_template::resolve( $templateFN, $dataSetType, $dataSet); if($errorMessage) return; $renderer->info['cache'] = false; return CommandPluginExtension_template::generate( $templateFN, $dataSetType, $dataSet, $paramHash); } function resolve($templateFN, $dataSetType, &$dataSet) // STATIC { global $ID; if(strpos($templateFN, '..') !== false || !@file_exists($templateFN)) // PHP caches the results return TEMPLATECOMMAND_TEMPLATE_NOT_FOUND; if($dataSetType == 'id') { $exists = false; resolve_pageid(getNS($ID), $dataSet, $exists); if(!$exists || auth_quickaclcheck($dataSet) < AUTH_READ) return TEMPLATECOMMAND_DATA_NOT_FOUND; } return null; } function generate($templateFN, $dataSetType, $dataSet, $paramHash) // STATIC { // Generate HTML or text from the template. $source = new TemplateCommandSource($templateFN, $dataSetType, $dataSet, $paramHash); ob_start(); CommandPluginExtension_template::runTemplate($source); $outString = ob_get_contents(); ob_end_clean(); // If the template generated text, translate into HTML. if(!$source->isHTML) { $instructs = p_get_instructions($outString); $info = array(); $outString = p_render('xhtml', $instructs, $info); } return $outString; // return generated HTML } function runTemplate(&$TEMPLATECOMMAND_SOURCE) { // Isolate template in its own function because it has access to // the function variables. Template writes to standard out. include($TEMPLATECOMMAND_SOURCE->templateFN); } /** * This is a duplicate of its namesake in template.php, since the * namesake is not available in an RSS feed. * * @author Andreas Gohr */ function template($tpl){ global $conf; if(@is_readable(DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl)) return DOKU_INC.'lib/tpl/'.$conf['template'].'/'.$tpl; return DOKU_INC.'lib/tpl/default/'.$tpl; } } /****************************************************************************** TemplateCommandSource - Source of data for PHP implementing template ******************************************************************************/ class TemplateCommandSource { //// FRIEND VARIABLES ///////////////////////////////////////////////////// var $isHTML = true; var $templateFN; //// PRIVATE VARIABLES //////////////////////////////////////////////////// var $dataSetText = null; var $dataSetFN = null; var $paramHash; var $textRecords = null; var $htmlRecords = null; //// PUBLIC METHODS /////////////////////////////////////////////////////// function getParamHash() { return $this->paramHash; } function getTextRecords() { $this->isHTML = false; if($this->textRecords != null) return $this->textRecords; if($this->dataSetText != null) $outline = $this->dataSetText; else { $outline = ''; $outline = @file_get_contents($this->dataSetFN); } $outlineParser = new TextOutlineRecordParser($outline); $this->textRecords = $outlineParser->getRecords(); return $this->textRecords; } function getHtmlRecords() { $this->isHTML = true; if($this->htmlRecords != null) return $this->htmlRecords; if($this->dataSetText != null) $instructs = p_get_instructions($this->dataSetText); else $instructs = p_cached_instructions($this->dataSetFN); $info = array(); $outline = p_render('xhtml', $instructs, $info); $outlineParser = new HTMLOutlineRecordParser($outline); $this->htmlRecords = $outlineParser->getRecords(); return $this->htmlRecords; } //// FRIEND METHODS /////////////////////////////////////////////////////// function TemplateCommandSource($templateFN, $dataSetType, $dataSet, $paramHash) { $this->templateFN = $templateFN; if($dataSetType == 'id') $this->dataSetFN = wikiFN($dataSet); else $this->dataSetText = $dataSet; $this->paramHash = $paramHash; } } /****************************************************************************** OutlineRecordParser - Base class for outline record parsers ******************************************************************************/ class OutlineRecordParser { //// PROTECTED VARIABLES ////////////////////////////////////////////////// var $records = array(); // list of records expressed as associative arrays //// PUBLIC METHODS /////////////////////////////////////////////////////// function getRecords() { return $this->records; } //// PROTECTED METHODS //////////////////////////////////////////////////// function parseRecord($fieldSplits) { $record = array(); // Iterate over the fields. Whatever precedes the first line item // of a record is ignored and so may be used for comments. for($i = 1; $i < sizeof($fieldSplits); ++$i) $this->parseField($record, trim($fieldSplits[$i])); if(!empty($record)) array_push($this->records, $record); } function parseLineItem($lineItem, &$fieldName, &$fieldValue) { $colonPos = strpos($lineItem, ':'); if($colonPos === false) { $fieldName = trim($lineItem); $fieldValue = ''; } else { $fieldName = trim(substr($lineItem, 0, $colonPos)); // next line works even if nothing follows colon $fieldValue = trim(substr($lineItem, $colonPos + 1)); } } } /****************************************************************************** TextOutlineRecordParser - Parses wiki text for records expressed in outlines ******************************************************************************/ class TextOutlineRecordParser extends OutlineRecordParser { //// PUBLIC METHODS /////////////////////////////////////////////////////// function TextOutlineRecordParser($outline) { $outline = "\n".$outline; // makes the pregs easier // wiki horizontal rules delimit records $recordSplits = preg_split('/[\n\r]+----+/', $outline); foreach($recordSplits as $recordSplit) { $fieldSplits = preg_split('/[\n\r]+ +\*/', $recordSplit); $this->parseRecord($fieldSplits); } } //// PROTECTED METHODS //////////////////////////////////////////////////// function parseField(&$record, $fieldSplit) { // Extract the line item. $endLineItem = strcspn($fieldSplit, "\n\r"); if($endLineItem === false) $lineItem = $fieldSplit; else $lineItem = substr($fieldSplit, 0, $endLineItem); // Skip over commented out fields. if($lineItem{0} == '#') return; // commented out field // Extract the field name and the line-item value. $fieldName = null; $fieldValue = null; $this->parseLineItem($lineItem, $fieldName, $fieldValue); // Extract the field's multi-line value, if any. if($endLineItem !== false) { $multiline = trim(substr($fieldSplit, $endLineItem)); if($multiline != '') $fieldValue .= $multiline; } // Record the extracted field. $record[$fieldName] = $fieldValue; } } /****************************************************************************** HTMLOutlineRecordParser - Parses HTML for records expressed in outlines ******************************************************************************/ class HTMLOutlineRecordParser extends OutlineRecordParser { //// PUBLIC METHODS /////////////////////////////////////////////////////// function HTMLOutlineRecordParser($outline) { // remove '); if($endOutline !== false) { // next line works even if nothing follows or $multiline = trim(substr($fieldSplit, $endOutline + 5)); if($multiline != '') $fieldValue .= $multiline; } // Record the extracted field. $record[$fieldName] = $fieldValue; } } ?>