Fixed error check
[squirrelmail.git] / class / template / template.class.php
index 9b413a329b115fb30e1219cc62584d6b37730885..db04cfa6306bac62d89c1a85e34e250c1d55e75d 100755 (executable)
@@ -42,45 +42,61 @@ class Template
    */
   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();
-  
+
   /**
    * Javascript files required by the template
-   * 
+   *
    * @var array
    */
   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 
+   * not provided, the js file by the same name will be included from the
    * default template directory.
-   * 
+   *
    * @var array
    */
   var $provided_js_files = array();
-  
+
   /**
-   * Constructor
-   *
-   * @param string $sTplDir where the template set is located
+   * 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.
    */
-  function Template($sTplDir) {
-       $this->template_dir = $sTplDir;
-       
-       // Pull in the tempalte config file
-       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();
-
-#       echo 'Template Dir: '.$this->template_dir.': ';
-#       var_dump($this->templates_provided);
+  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();
+        }
   }
 
 
@@ -123,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 != '')
@@ -135,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)
@@ -168,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)
   {
@@ -186,44 +230,194 @@ class Template
     }
   }
 
-  /**
-   * 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
-    
-    $template = in_array($file, $this->templates_provided) ? $this->template_dir . $file : SM_PATH .'templates/default/'. $file;
-    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)
-  {
-    ob_start();
-    $t = &$this->values; // place values array directly in scope
-
-    $template = in_array($file, $this->templates_provided) ? $this->template_dir . $file : SM_PATH .'templates/default/'. $file;
-    include($template);
-    $contents = ob_get_contents();
-    ob_end_clean();
-    return $contents;
-  }
+    /**
+     *
+     * 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;
+        }
+    }
 
   /**
-   * Return paths to the required javascript files.  Used when generating page 
+   * Return paths to the required javascript files.  Used when generating page
    * header.
-   * 
+   *
    * @return array $paths
    */
   function getJavascriptIncludes () {
@@ -233,9 +427,25 @@ class Template
             $paths[] = './'.$this->template_dir.'js/'.basename($file);
         else $paths[] = SM_PATH .'templates/default/js/'.basename($file);
     }
-    
+
     return $paths;
   }
-}
 
-?>
+  /**
+   * Return any additional stylsheets provided by the template.  Used when
+   * generating page headers.
+   *
+   * @return array $paths
+   */
+  function getAdditionalStyleSheets () {
+    $paths = array();
+    foreach ($this->additional_css_sheets as $css) {
+        $css = basename($css);
+        if (strtolower($css) == 'stylesheet.tpl') {
+            continue;
+        }
+        $paths[] = $css;
+    }
+    return $paths;
+  }
+}