egroupware/etemplate/inc/class.etemplate_widget_template.inc.php
Nathan Gray ecb972ca66 Etemplate now uses JSON instead of XML for templates on the client side.
XML files are parsed into JSON objects on the server, then sent as JSON.
Etemplate parses the JSON object on the client side instead of the XML file directly.  This is supposed to be faster for IE.
2015-08-18 17:47:40 +00:00

261 lines
7.8 KiB
PHP

<?php
/**
* EGroupware - eTemplate serverside template widget
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage api
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker@outdoor-training.de>
* @copyright 2002-11 by RalfBecker@outdoor-training.de
* @version $Id$
*/
// allow to call direct for tests (see end of class)
if (!isset($GLOBALS['egw_info']))
{
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'login',
'debug' => 'etemplate_widget_template',
)
);
include_once '../../header.inc.php';
}
/**
* eTemplate widget baseclass
*/
class etemplate_widget_template extends etemplate_widget
{
/**
* Cache of already read templates
*
* @var array with name => template pairs
*/
protected static $cache = array();
/**
* Tell egw framework it's ok to call this
*/
public $public_functions = array(
'ajaxtoJSON' => true
);
/**
* Get instance of template specified by name, template(-set) and version
*
* @param string $_name
* @param string $template_set =null default try template-set from user and if not found "default"
* @param string $version =''
* @param string $load_via ='' use given template to load $name
* @todo Reading customized templates from database
* @return etemplate_widget_template|boolean false if not found
*/
public static function instance($_name, $template_set=null, $version='', $load_via='')
{
//$start = microtime(true);
list($name) = explode('?', $_name); // remove optional cache-buster
if (isset(self::$cache[$name]) || !($path = self::relPath($name, $template_set, $version)))
{
if ((!$path || self::read($load_via, $template_set)) && isset(self::$cache[$name]))
{
//error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') read from cache");
return self::$cache[$name];
}
// Template not found, try again as if $name were a partial name
else if(!$path && strpos($name,'.') === false)
{
foreach(self::$cache as $c_name => $c_template)
{
list(,, $c_sub) = explode('.',$c_name, 3);
if($name == $c_sub)
{
//error_log(__METHOD__ . "('$name' loaded from cache ($c_name)");
return $c_template;
}
$parts = explode('.',$c_name);
if($name == $parts[count($parts)-1]) return $c_template;
}
}
// Template not found, try again with content expansion
if (is_array(self::$request->content))
{
$expand_name = self::expand_name($name, '','','','',self::$cont);
if ($expand_name && $expand_name != $name &&
($template = self::instance($expand_name, $template_set, $version, $load_via)))
{
// Remember original, un-expanded name in case content changes while still cached
$template->original_name = $name;
return $template;
}
}
error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') template NOT found!");
return false;
}
$reader = new XMLReader();
if (!$reader->open(self::rel2path($path))) return false;
while($reader->read())
{
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'template')
{
$template = new etemplate_widget_template($reader);
//echo $template->id; _debug_array($template);
self::$cache[$template->id] = $template;
if ($template->id == $name)
{
//error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') read in ".round(1000.0*(microtime(true)-$start),2)." ms");
return $template;
}
}
}
// template not found in file, should never happen
error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') template NOT found in file '$path'!");
return false;
}
const VFS_TEMPLATE_PATH = '/etemplates';
/**
* Get path/URL relative to EGroupware install of a template of full vfs url
*
* @param string $name
* @param string $template_set =null default try template-set from user and if not found "default"
* @param string $version =''
* @return string path of template xml file or null if not found
*/
public static function relPath($name, $template_set=null, $version='')
{
unset($version); // not used currently
list($app, $rest) = explode('.', $name, 2);
if (empty($template_set))
{
$template_set = $GLOBALS['egw_info']['user']['preferences']['common']['template_set'];
}
$template_path = '/'.$app.'/templates/'.$template_set.'/'.$rest.'.xet';
$default_path = '/'.$app.'/templates/default/'.$rest.'.xet';
foreach(array(egw_vfs::PREFIX.self::VFS_TEMPLATE_PATH, EGW_SERVER_ROOT) as $prefix)
{
if (file_exists($prefix.$template_path))
{
$path = $template_path;
break;
}
if (file_exists($prefix.$default_path))
{
$path = $default_path;
break;
}
}
// for a vfs template path we keep the prefix, to be able to distinquish between real filesystem and vfs
if (isset($path) && $prefix !== EGW_SERVER_ROOT)
{
$path = $prefix.$path;
}
//error_log(__METHOD__."('$name', '$template_set') returning ".array2string($path));
return $path;
}
/**
* Convert relative template path from relPath to an absolute path
*
* @param string $path
* @return string
*/
public static function rel2path($path)
{
if ($path[0] === '/')
{
$path = EGW_SERVER_ROOT.$path;
}
return $path;
}
/**
* Convert relative template path from relPath to an url incl. cache-buster modification time postfix
*
* @param string $path
* @return string url
*/
public static function rel2url($path)
{
if ($path)
{
if ($path[0] === '/')
{
$url = $GLOBALS['egw_info']['server']['webserver_url'].$path.'?'.filemtime(self::rel2path($path));
}
else
{
$url = egw_vfs::download_url($path);
if ($url[0] == '/') $url = egw::link($url);
// mtime postfix has to use '?download=', as our WebDAV treats everything else literal and not ignore them like Apache for static files!
$url .= '?download='.filemtime($path);
}
}
//error_log(__METHOD__."('$path') returning $url");
return $url;
}
/**
* Run method on all children
*
* Reimplemented because templates can have an own namespace specified in attrs[content], NOT id!
*
* @param string $method_name
* @param array $params =array('') parameter(s) first parameter has to be cname, second $expand!
* @param boolean $respect_disabled =false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
*/
public function run($method_name, $params=array(''), $respect_disabled=false)
{
$cname =& $params[0];
$old_cname = $params[0];
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content'], $params[1]);
// Check for template from content, and run over it
// templates included via template tag have their name to load them from in attribute "template"
$expand_name = self::expand_name($this->id ? $this->id : $this->attrs['template'], '','','','',self::$request->content);
if($this->original_name)
{
$expand_name = self::expand_name($this->original_name, '','','','',self::$request->content);
}
//error_log("$this running $method_name() cname: {$this->id} -> expand_name: $expand_name");
if($expand_name && $expand_name != $this->id)
{
if (($row_template = etemplate_widget_template::instance($expand_name)))
{
$row_template->run($method_name, $params, $respect_disabled);
}
}
else
{
parent::run($method_name, $params, $respect_disabled);
}
$params[0] = $old_cname;
}
}
/*
if ($GLOBALS['egw_info']['flags']['debug'] == 'etemplate_widget_template')
{
$name = isset($_GET['name']) ? $_GET['name'] : 'timesheet.edit';
if (!($template = etemplate_widget_template::instance($name)))
{
header('HTTP-Status: 404 Not Found');
echo "<html><head><title>Not Found</title><body><h1>Not Found</h1><p>The requested eTemplate '$name' was not found!</p></body></html>\n";
exit;
}
header('Content-Type: text/xml');
echo $template->toXml();
}
*/