Fixed error check
[squirrelmail.git] / class / template / template.class.php
index 5fb9d168671850b81521922b8a1e20585e5ac47d..db04cfa6306bac62d89c1a85e34e250c1d55e75d 100755 (executable)
@@ -1,20 +1,18 @@
 <?php
+
 /**
  * Copyright 2003, Paul James
- * Copyright (c) 2005 The SquirrelMail Project Team
- * Licensed under the GNU GPL. For full terms see the file COPYING.
  *
  * This file contains some methods from the Smarty templating engine version
  * 2.5.0 by Monte Ohrt <monte@ispi.net> and Andrei Zmievski <andrei@php.net>.
  *
- * @version $Id$
- */
-
-/**
  * The SquirrelMail (Foowd) template implementation.
  * Derived from the foowd template implementation and adapted
  * for squirrelmail
- * @package SquirrelMail
+ * @copyright &copy; 2005-2006 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+ * @version $Id$
+ * @package squirrelmail
  */
 
 /**
@@ -24,9 +22,9 @@
  * This class uses a similar API to Smarty.
  *
  * @author Paul James
- * @author Monte Ohrt <monte@ispi.net>
- * @author Andrei Zmievski <andrei@php.net>
- * @package SquirrelMail
+ * @author Monte Ohrt <monte at ispi.net>
+ * @author Andrei Zmievski <andrei at php.net>
+ * @package squirrelmail
  */
 class Template
 {
@@ -42,15 +40,63 @@ class Template
    *
    * @var string
    */
-  var $template_dir = 'templates\default';
+  var $template_dir = '';
+
+  /**
+   * The default template directory
+   *
+   * @var string
+   */
+  var $default_template_dir = 'templates/default/';
+
+  /**
+   * Template files provided by this template set
+   *
+   * @var array
+   */
+  var $templates_provided = array();
 
   /**
-   * Constructor
+   * Javascript files required by the template
    *
-   * @param string $sTplDir where the template set is located
+   * @var array
    */
-  function Template($sTplDir = 'templates\default') {
-       $this->template_dir = $sTplDir;
+  var $required_js_files = array();
+
+  /**
+   * Javascript files provided by the template.  If a JS file is required, but
+   * not provided, the js file by the same name will be included from the
+   * default template directory.
+   *
+   * @var array
+   */
+  var $provided_js_files = array();
+
+  /**
+   * Additional stylesheets provided by the template.  This allows template
+   * authors to provide additional CSS sheets to templates while using the 
+   * default template set stylesheet for other definitions.
+   */
+  var $additional_css_sheets = array();
+
+    /**
+     * Constructor
+     *
+     * @param string $sTplDir where the template set is located
+     */
+    function Template($sTplDir) {
+        $this->template_dir = $sTplDir;
+
+        // Pull in the tempalte config file
+        if (!file_exists($this->template_dir . 'template.php')) {
+             trigger_error('No template.php could be found in the requested template directory ("'.$this->template_dir.'")', E_USER_ERROR);
+        } else {
+            include ($this->template_dir . 'template.php');
+            $this->templates_provided = is_array($templates_provided) ? $templates_provided : array();
+            $this->required_js_files = is_array($required_js_files) ? $required_js_files : array();
+            $this->provided_js_files = is_array($provided_js_files) ? $provided_js_files: array();
+            $this->additional_css_sheets = is_array($additional_css_sheets) ? $additional_css_sheets : array();
+        }
   }
 
 
@@ -93,11 +139,20 @@ class Template
    *
    * @param array|string $tpl_var the template variable name(s)
    * @param mixed $value the value to append
+   * @param boolean $merge when $value is given as an array, 
+   *                       this indicates whether or not that 
+   *                       array itself should be appended as 
+   *                       a new template variable value or if 
+   *                       that array's values should be merged 
+   *                       into the existing array of template 
+   *                       variable values
    */
   function append($tpl_var, $value = NULL, $merge = FALSE)
   {
     if (is_array($tpl_var))
     {
+      //FIXME: $tpl_var is supposed to be a list of template var names,
+      //       so we should be looking at the values NOT the keys!
       foreach ($tpl_var as $_key => $_val)
       {
         if ($_key != '')
@@ -105,6 +160,18 @@ class Template
           if(isset($this->values[$_key]) && !is_array($this->values[$_key]))
             settype($this->values[$_key],'array');
 
+          //FIXME: we should be iterating the $value array here not the values of the
+          //       list of template variable names!  I think this is totally broken 
+          // This might just be a matter of needing to clarify the method's API;
+          // values may have been meant to be passed in $tpl_var in the case that
+          // $tpl_var is an array.  Ugly and non-intuitive.
+          // PROPOSAL: API should be as such:  
+          //   if (is_string($tpl_var)) then $values are added/merged as already done
+          //   if (is_array($tpl_var)) then $values is required to be an array whose
+          //                                keys must match up with $tpl_var keys and
+          //                                whose values are then what is added to
+          //                                each template variable value (array or 
+          //                                strings, doesn't matter)
           if($merge && is_array($_val))
           {
             foreach($_val as $_mkey => $_mval)
@@ -138,6 +205,13 @@ class Template
    *
    * @param string $tpl_var the template variable name
    * @param mixed $value the referenced value to append
+   * @param boolean $merge when $value is given as an array, 
+   *                       this indicates whether or not that 
+   *                       array itself should be appended as 
+   *                       a new template variable value or if 
+   *                       that array's values should be merged 
+   *                       into the existing array of template 
+   *                       variable values
    */
   function append_by_ref($tpl_var, &$value, $merge = FALSE)
   {
@@ -156,35 +230,222 @@ class Template
     }
   }
 
+
+    /**
+     *
+     * Return the relative template directory path for this template set.
+     *
+     * @return string The relative path to the template directory based
+     *                from the main SquirrelMail directory (SM_PATH).
+     *
+     */
+    function get_template_file_directory() {
+
+//FIXME: temporarily parse off SM_PATH from the template dir class attribute until we can change the entire template subsystem such that the template dir is derived internally in this class from the template ID/name/attributes
+return substr($this->template_dir, strlen(SM_PATH));
+        return $this->template_dir;
+
+    }
+
+
+    /**
+     *
+     * Return the relative template directory path for the DEFAULT template set.
+     *
+     * @return string The relative path to the default template directory based
+     *                from the main SquirrelMail directory (SM_PATH).
+     *
+     */
+    function get_default_template_file_directory() {
+
+        return $this->default_template_dir;
+
+    }
+
+
+    /**
+     *
+     * Find the right template file.
+     *
+     * Templates are expected to be found in the template set directory,
+     * for example:
+     *     SM_PATH/templates/<template name>/
+     * or, in the case of plugin templates, in a plugin directory in the 
+     * template set directory, for example:
+     *     SM_PATH/templates/<template name>/plugins/<plugin name>/
+     * *OR* in a template directory in the plugin as a fallback, for example:
+     *     SM_PATH/plugins/<plugin name>/templates/<template name>/
+     * If the correct file is not found for the current template set, a 
+     * default template is loaded, which is expected to be found in the 
+     * default template directory, for example:
+     *     SM_PATH/templates/default/
+     * or for plugins, in a plugin directory in the default template set,
+     * for example:
+     *     SM_PATH/templates/default/plugins/<plugin name>/
+     * *OR* in a default template directory in the plugin as a fallback,
+     * for example:
+     *     SM_PATH/plugins/<plugin name>/templates/default/
+     *
+     * Plugin authors must note that the $filename MUST be prefaced
+     * with "plugins/<plugin name>/" in order to correctly resolve the 
+     * template file.
+     *
+     * @param string $filename The name of the template file,
+     *                         possibly prefaced with 
+     *                         "plugins/<plugin name>/"
+     *                         indicating that it is a plugin
+     *                         template.
+     *
+     * @return string The full path to the template file; if 
+     *                not found, an empty string.  The caller
+     *                is responsible for throwing erros or 
+     *                other actions if template file is not found.
+     *
+     */
+    function get_template_file_path($filename) {
+
+        // is the template found in the normal template directory?
+        //
+        $filepath = SM_PATH . $this->get_template_file_directory() . $filename;
+        if (!file_exists($filepath)) {
+
+            // no, so now we have to get the default template...
+            // however, in the case of a plugin template, let's
+            // give one more try to find the right template as
+            // provided by the plugin
+            //
+            if (strpos($filename, 'plugins/') === 0) {
+
+                $plugin_name = substr($filename, 8, strpos($filename, '/', 8) - 8);
+                $filepath = SM_PATH . 'plugins/' . $plugin_name . '/'
+                          . $this->get_template_file_directory() 
+                          . substr($filename, strlen($plugin_name) + 9);
+
+                // no go, we have to get the default template, 
+                // first try the default SM template
+                //
+                if (!file_exists($filepath)) {
+
+                    $filepath = SM_PATH 
+                              . $this->get_default_template_file_directory() 
+                              . $filename;
+
+                    // still no luck?  get default template from the plugin
+                    //
+                    if (!file_exists($filepath)) {
+
+                        $filepath = SM_PATH . 'plugins/' . $plugin_name . '/'
+                                  . $this->get_default_template_file_directory() 
+                                  . substr($filename, strlen($plugin_name) + 9);
+
+                        // no dice whatsoever, return empty string
+                        //
+                        if (!file_exists($filepath)) {
+                            $filepath = '';
+                        }
+
+                    }
+
+                }
+
+
+            // get default template for non-plugin templates
+            //
+            } else {
+
+                $filepath = SM_PATH . $this->get_default_template_file_directory() 
+                          . $filename;
+
+                // no dice whatsoever, return empty string
+                //
+                if (!file_exists($filepath)) {
+                    $filepath = '';
+                }
+
+            }
+
+        }
+
+        return $filepath;
+
+    }
+
+
+    /**
+     * Display the template
+     *
+     * @param string $file The template file to use
+     */
+    function display($file)
+    {
+        // Pull in our config file
+        $t = &$this->values; // place values array directly in scope
+
+        // Get right template file
+        $template = $this->get_template_file_path($file);
+        if (empty($template)) {
+            trigger_error('The template "'.htmlspecialchars($file).'" could not be displayed!', E_USER_ERROR);
+        } else {
+            ob_start();
+            include($template);
+            ob_end_flush();
+        }
+    }
+
+    /**
+     * Return the results of applying a template.
+     *
+     * @param string $file The template file to use
+     * @return string A string of the results
+     */
+    function fetch($file) {
+        $t = &$this->values; // place values array directly in scope
+
+        // Get right template file
+        $template = $this->get_template_file_path($file);
+        if (empty($template)) {
+            trigger_error('The template "'.htmlspecialchars($file).'" could not be fetched!', E_USER_ERROR);
+        } else {
+            ob_start();
+            include($template);
+            $contents = ob_get_contents();
+            ob_end_clean();
+            return $contents;
+        }
+    }
+
   /**
-   * Display the template
+   * Return paths to the required javascript files.  Used when generating page
+   * header.
    *
-   * @param string $file The template file to use
+   * @return array $paths
    */
-  function display($file)
-  {
-    $t = &$this->values; // place values array directly in scope
-    ob_start();
-    include($this->template_dir.$file);
-    ob_end_flush();
+  function getJavascriptIncludes () {
+    $paths = array();
+    foreach ($this->required_js_files as $file) {
+        if (in_array($file, $this->provided_js_files))
+            $paths[] = './'.$this->template_dir.'js/'.basename($file);
+        else $paths[] = SM_PATH .'templates/default/js/'.basename($file);
+    }
+
+    return $paths;
   }
 
   /**
-   * Return the results of applying a template.
+   * Return any additional stylsheets provided by the template.  Used when
+   * generating page headers.
    *
-   * @param string $file The template file to use
-   * @return string A string of the results
+   * @return array $paths
    */
-  function fetch($file)
-  {
-    ob_start();
-    $t = &$this->values; // place values array directly in scope
-    include($this->template_dir.$file);
-    $contents = ob_get_contents();
-    ob_end_clean();
-    return $contents;
+  function getAdditionalStyleSheets () {
+    $paths = array();
+    foreach ($this->additional_css_sheets as $css) {
+        $css = basename($css);
+        if (strtolower($css) == 'stylesheet.tpl') {
+            continue;
+        }
+        $paths[] = $css;
+    }
+    return $paths;
   }
-
 }
-
-?>