home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / phing / tasks / ext / SmartyTask.php < prev    next >
Encoding:
PHP Script  |  2007-02-05  |  19.8 KB  |  611 lines

  1. <?php
  2.  
  3. /*
  4.  *  $Id: SmartyTask.php 144 2007-02-05 15:19:00Z hans $
  5.  *
  6.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  7.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  8.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  9.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  10.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  12.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  13.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  14.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  15.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  16.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  17.  *
  18.  * This software consists of voluntary contributions made by many individuals
  19.  * and is licensed under the LGPL. For more information please see
  20.  * <http://phing.info>. 
  21.  */
  22.  
  23. require_once 'phing/Task.php';
  24. include_once 'phing/BuildException.php';
  25. include_once 'phing/util/StringHelper.php';
  26.  
  27. /**
  28.  * A phing task for generating output by using Smarty.
  29.  *
  30.  * This is based on the TexenTask from Apache's Velocity engine.  This class
  31.  * was originally proted in order to provide a template compiling system for
  32.  * Torque.
  33.  *
  34.  * TODO:
  35.  *        - Add Path / useClasspath support?
  36.  *
  37.  * @author    Hans Lellelid <hans@xmpl.org> (SmartyTask)
  38.  * @author    Jason van Zyl <jvanzyl@apache.org> (TexenTask)
  39.  * @author    Robert Burrell Donkin <robertdonkin@mac.com>
  40.  * @version   $Id: SmartyTask.php 144 2007-02-05 15:19:00Z hans $
  41.  * @package   phing.tasks.ext
  42.  */
  43. class SmartyTask extends Task {
  44.  
  45.     /**
  46.      * Smarty template engine.
  47.      * @var Smarty
  48.      */
  49.     protected $context;
  50.     
  51.     /**
  52.      * Variables that are assigned to the context on parse/compile.
  53.      * @var array
  54.      */
  55.     protected $properties = array();
  56.     
  57.     /**
  58.      * This is the control template that governs the output.
  59.      * It may or may not invoke the services of worker
  60.      * templates.
  61.      * @var string
  62.      */
  63.     protected $controlTemplate;
  64.     
  65.     /**
  66.      * This is where Velocity will look for templates
  67.      * using the file template loader.
  68.      * @var string
  69.      */
  70.     protected $templatePath;
  71.     
  72.     /**
  73.      * This is where texen will place all the output
  74.      * that is a product of the generation process.
  75.      * @var string
  76.      */
  77.     protected $outputDirectory;
  78.     
  79.     /**
  80.      * This is the file where the generated text
  81.      * will be placed.
  82.      * @var string
  83.      */
  84.     protected $outputFile;
  85.  
  86.     /**
  87.      * <p>
  88.      * These are properties that are fed into the
  89.      * initial context from a properties file. This
  90.      * is simply a convenient way to set some values
  91.      * that you wish to make available in the context.
  92.      * </p>
  93.      * <p>
  94.      * These values are not critical, like the template path
  95.      * or output path, but allow a convenient way to
  96.      * set a value that may be specific to a particular
  97.      * generation task.
  98.      * </p>
  99.      * <p>
  100.      * For example, if you are generating scripts to allow
  101.      * user to automatically create a database, then
  102.      * you might want the <code>$databaseName</code> 
  103.      * to be placed
  104.      * in the initial context so that it is available
  105.      * in a script that might look something like the
  106.      * following:
  107.      * <code><pre>
  108.      * #!bin/sh
  109.      * 
  110.      * echo y | mysqladmin create $databaseName
  111.      * </pre></code>
  112.      * The value of <code>$databaseName</code> isn't critical to
  113.      * output, and you obviously don't want to change
  114.      * the ant task to simply take a database name.
  115.      * So initial context values can be set with
  116.      * properties file.
  117.      *
  118.      * @var array
  119.      */
  120.     protected $contextProperties;
  121.         
  122.     /**
  123.      * Smarty compiles templates before parsing / replacing tokens in them.
  124.      * By default it will try ./templates_c, but you may wish to override this.
  125.      * @var string
  126.      */
  127.     protected $compilePath;
  128.     
  129.     /**
  130.      * Whether to force Smarty to recompile templates.
  131.      * Smarty does check file modification time, but you can set this
  132.      * to be *sure* that the template will be compiled (of course it will
  133.      * be slower if you do).
  134.      * @var boolean
  135.      */
  136.     protected $forceCompile = false;
  137.     
  138.     /**
  139.      * Smarty can use config files.
  140.      * This tells Smarty where to look for the config files.
  141.      * @var string
  142.      */
  143.     protected $configPath;
  144.     
  145.     /**
  146.      * Customize the left delimiter for Smarty tags.
  147.      * @var string
  148.      */
  149.     protected $leftDelimiter;
  150.  
  151.     /**
  152.      * Customize the right delimiter for Smarty tags.
  153.      * @var string
  154.      */
  155.     protected $rightDelimiter;
  156.  
  157.     // -----------------------------------------------------------------------
  158.     // The following getters & setters are used by phing to set properties
  159.     // specified in the XML for the smarty task.
  160.     // -----------------------------------------------------------------------
  161.     
  162.     public function init() {
  163.         include_once 'Smarty.class.php';
  164.         if (!class_exists('Smarty')) {
  165.             throw new BuildException("To use SmartyTask, you must have the path to Smarty.class.php on your include_path or your \$PHP_CLASSPATH environment variable.");
  166.         }
  167.     }
  168.     
  169.     /**
  170.      * [REQUIRED] Set the control template for the
  171.      * generating process.
  172.      * @param string $controlTemplate
  173.      * @return void
  174.      */
  175.     public function setControlTemplate ($controlTemplate) {
  176.         $this->controlTemplate = $controlTemplate;
  177.     }
  178.  
  179.     /**
  180.      * Get the control template for the
  181.      * generating process.
  182.      * @return string
  183.      */
  184.     public function getControlTemplate() {
  185.         return $this->controlTemplate;
  186.     }
  187.  
  188.     /**
  189.      * [REQUIRED] Set the path where Velocity will look
  190.      * for templates using the file template
  191.      * loader.
  192.      * @return void
  193.      * @throws Exception 
  194.      */
  195.     public function setTemplatePath($templatePath) {
  196.         $resolvedPath = "";        
  197.         $tok = strtok($templatePath, ",");
  198.         while ( $tok ) {            
  199.             // resolve relative path from basedir and leave
  200.             // absolute path untouched.
  201.             $fullPath = $this->project->resolveFile($tok);
  202.             $cpath = $fullPath->getCanonicalPath();
  203.             if ($cpath === false) {
  204.                 $this->log("Template directory does not exist: " . $fullPath->getAbsolutePath());
  205.             } else {
  206.                 $resolvedPath .= $cpath;
  207.             }
  208.             $tok = strtok(",");
  209.             if ( $tok ) {
  210.                 $resolvedPath .= ",";
  211.             }
  212.         }
  213.         $this->templatePath = $resolvedPath;
  214.      }
  215.  
  216.     /**
  217.      * Get the path where Velocity will look
  218.      * for templates using the file template
  219.      * loader.
  220.      * @return string
  221.      */
  222.     public function getTemplatePath() {
  223.         return $this->templatePath;
  224.     }        
  225.  
  226.     /**
  227.      * [REQUIRED] Set the output directory. It will be
  228.      * created if it doesn't exist.
  229.      * @param PhingFile $outputDirectory
  230.      * @return void
  231.      * @throws Exception
  232.      */
  233.     public function setOutputDirectory(PhingFile $outputDirectory) {
  234.         try {            
  235.             if (!$outputDirectory->exists()) {
  236.                 $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),Project::MSG_VERBOSE);
  237.                 if (!$outputDirectory->mkdirs()) {
  238.                     throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath());
  239.                 }
  240.             }
  241.             $this->outputDirectory = $outputDirectory->getCanonicalPath();
  242.         } catch (IOException $ioe) {
  243.             throw new BuildException($ioe->getMessage());
  244.         }
  245.     }
  246.       
  247.     /**
  248.      * Get the output directory.
  249.      * @return string
  250.      */
  251.     public function getOutputDirectory() {
  252.         return $this->outputDirectory;
  253.     }        
  254.  
  255.     /**
  256.      * [REQUIRED] Set the output file for the
  257.      * generation process.
  258.      * @return void
  259.      */
  260.     public function setOutputFile($outputFile) {
  261.         $this->outputFile = $outputFile;
  262.     }
  263.  
  264.     /**
  265.      * Get the output file for the
  266.      * generation process.
  267.      * @return string
  268.      */
  269.     public function getOutputFile() {
  270.         return $this->outputFile;
  271.     }        
  272.  
  273.     /**
  274.      * Set the path Smarty uses as a "cache" for compiled templates.
  275.      * @param string $compilePath
  276.      */
  277.     public function setCompilePath($compilePath) {
  278.         $this->compilePath = $compilePath;
  279.     }
  280.     
  281.     /**
  282.      * Get the path Smarty uses for compiling templates.
  283.      * @return string
  284.      */
  285.     public function getCompilePath() {
  286.         return $this->compilePath;
  287.     }
  288.     
  289.     /**
  290.      * Set whether Smarty should always recompile tempaltes.
  291.      * @param boolean $force
  292.      * @return void
  293.      */
  294.     public function setForceCompile($force) {
  295.         $this->forceCompile = (boolean) $force;
  296.     }
  297.     
  298.     /**
  299.      * Get whether Smarty should always recompile template.
  300.      * @return boolean
  301.      */
  302.     public function getForceCompile() {
  303.         return $this->forceCompile;
  304.     }
  305.     
  306.     /**
  307.      * Set where Smarty looks for config files.
  308.      * @param string $configPath
  309.      * @return void
  310.      */
  311.     public function setConfigPath($configPath) {
  312.         $this->configPath = $configPath;
  313.     }
  314.     
  315.     /**
  316.      * Get the path that Smarty uses for looking for config files.
  317.      * @return string
  318.      */
  319.     public function getConfigPath() {
  320.         return $this->configPath;
  321.     }
  322.     
  323.     /**
  324.      * Set Smarty template left delimiter.
  325.      * @param string $delim
  326.      * @return void
  327.      */
  328.     public function setLeftDelimiter($delim) {
  329.         $this->leftDelimiter = $delim;
  330.     }
  331.     
  332.     /**
  333.      * Get Smarty template right delimiter
  334.      * @return string
  335.      */
  336.     public function getLeftDelimiter() {
  337.         return $this->leftDelimiter;
  338.     }
  339.     
  340.     /**
  341.      * Set Smarty template right delimiter.
  342.      * @param string $delim
  343.      * @return void
  344.      */
  345.     public function setRightDelimiter($delim) {
  346.         $this->rightDelimiter = $delim;
  347.     }
  348.     
  349.     /**
  350.      * Get Smarty template right delimiter
  351.      * @return string
  352.      */
  353.     public function getRightDelimiter() {
  354.         return $this->rightDelimiter;
  355.     }
  356.     
  357.     
  358.     /**
  359.      * Set the context properties that will be
  360.      * fed into the initial context be the
  361.      * generating process starts.
  362.      * @param string $file
  363.      * @return void
  364.      */
  365.     public function setContextProperties($file) {
  366.     
  367.         $sources = explode(",", $file);
  368.         $this->contextProperties = new Properties();
  369.         
  370.         // Always try to get the context properties resource
  371.         // from a file first. Templates may be taken from a JAR
  372.         // file but the context properties resource may be a 
  373.         // resource in the filesystem. If this fails than attempt
  374.         // to get the context properties resource from the
  375.         // classpath.
  376.         for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) {
  377.             $source = new Properties();
  378.             
  379.             try {
  380.             
  381.                 // resolve relative path from basedir and leave
  382.                 // absolute path untouched.
  383.                 $fullPath = $this->project->resolveFile($sources[$i]);
  384.                 $this->log("Using contextProperties file: " . $fullPath->__toString());
  385.                 $source->load($fullPath);
  386.                 
  387.             } catch (Exception $e) {
  388.               
  389.               throw new BuildException("Context properties file " . $sources[$i] .
  390.                             " could not be found in the file system!");
  391.                      
  392.             }
  393.         
  394.             $keys = $source->keys();
  395.             
  396.             foreach ($keys as $key) {
  397.                 $name = $key;
  398.                 $value = $this->project->replaceProperties($source->getProperty($name));
  399.                 $this->contextProperties->setProperty($name, $value);
  400.             }
  401.         }
  402.     }
  403.  
  404.     /**
  405.      * Get the context properties that will be
  406.      * fed into the initial context be the
  407.      * generating process starts.
  408.      * @return Properties
  409.      */
  410.     public function getContextProperties() {
  411.         return $this->contextProperties;
  412.     }     
  413.  
  414.     // ---------------------------------------------------------------
  415.     // End of XML setters & getters
  416.     // ---------------------------------------------------------------
  417.  
  418.    
  419.     /**
  420.      * Creates a Smarty object.
  421.      *
  422.      * @return Smarty initialized (cleared) Smarty context.
  423.      * @throws Exception the execute method will catch 
  424.      *         and rethrow as a <code>BuildException</code>
  425.      */
  426.     public function initControlContext() {        
  427.         $this->context->clear_all_assign();        
  428.         return $this->context;
  429.     }
  430.     
  431.     /**
  432.      * Execute the input script with Velocity
  433.      *
  434.      * @throws BuildException  
  435.      * BuildExceptions are thrown when required attributes are missing.
  436.      * Exceptions thrown by Velocity are rethrown as BuildExceptions.
  437.      */
  438.     public function main() {
  439.     
  440.         // Make sure the template path is set.
  441.         if (empty($this->templatePath)) {
  442.             throw new BuildException("The template path needs to be defined!");
  443.         }            
  444.     
  445.         // Make sure the control template is set.
  446.         if ($this->controlTemplate === null) {
  447.             throw new BuildException("The control template needs to be defined!");
  448.         }            
  449.  
  450.         // Make sure the output directory is set.
  451.         if ($this->outputDirectory === null) {
  452.             throw new BuildException("The output directory needs to be defined!");
  453.         }            
  454.         
  455.         // Make sure there is an output file.
  456.         if ($this->outputFile === null) {
  457.             throw new BuildException("The output file needs to be defined!");
  458.         }            
  459.         
  460.         // Setup Smarty runtime.
  461.         
  462.         // Smarty uses one object to store properties and to store
  463.         // the context for the template (unlike Velocity).  We setup this object, calling it
  464.         // $this->context, and then initControlContext simply zeros out
  465.         // any assigned variables.
  466.         $this->context = new Smarty();
  467.         
  468.         if ($this->compilePath !== null) {
  469.             $this->log("Using compilePath: " . $this->compilePath);
  470.             $this->context->compile_dir = $this->compilePath;
  471.         }
  472.         
  473.         if ($this->configPath !== null) {
  474.             $this->log("Using configPath: " . $this->configPath);
  475.             $this->context->config_dir = $this->configPath;
  476.         }        
  477.         
  478.         if ($this->forceCompile !== null) {
  479.             $this->context->force_compile = $this->forceCompile;
  480.         }
  481.         
  482.         if ($this->leftDelimiter !== null) {
  483.             $this->context->left_delimiter = $this->leftDelimiter;
  484.         }
  485.         
  486.         if ($this->rightDelimiter !== null) {
  487.             $this->context->right_delimiter = $this->rightDelimiter;
  488.         }
  489.         
  490.         if ($this->templatePath !== null) {
  491.             $this->log("Using templatePath: " . $this->templatePath);
  492.             $this->context->template_dir = $this->templatePath;
  493.         }                                                        
  494.         
  495.         $smartyCompilePath = new PhingFile($this->context->compile_dir);
  496.         if (!$smartyCompilePath->exists()) {
  497.             $this->log("Compile directory does not exist, creating: " . $smartyCompilePath->getPath(), Project::MSG_VERBOSE);
  498.             if (!$smartyCompilePath->mkdirs()) {
  499.                 throw new BuildException("Smarty needs a place to compile templates; specify a 'compilePath' or create ".$this->context->compile_dir);
  500.             }
  501.         }
  502.         
  503.         // Make sure the output directory exists, if it doesn't
  504.         // then create it.
  505.         $file = new PhingFile($this->outputDirectory);
  506.         if (!$file->exists()) {
  507.             $this->log("Output directory does not exist, creating: " . $file->getAbsolutePath());
  508.             $file->mkdirs();
  509.         }
  510.         
  511.         $path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile;
  512.         $this->log("Generating to file " . $path);
  513.         
  514.         $writer = new FileWriter($path);
  515.                 
  516.         // The generator and the output path should
  517.         // be placed in the init context here and
  518.         // not in the generator class itself.
  519.         $c = $this->initControlContext();
  520.         
  521.         // Set any variables that need to always
  522.         // be loaded
  523.         $this->populateInitialContext($c);
  524.         
  525.         // Feed all the options into the initial
  526.         // control context so they are available
  527.         // in the control/worker templates.
  528.         if ($this->contextProperties !== null) {
  529.             
  530.             foreach($this->contextProperties->keys() as $property) {
  531.                     
  532.                 $value = $this->contextProperties->getProperty($property);
  533.                 
  534.                 // Special exception (from Texen)
  535.                 // for properties ending in file.contents:
  536.                 // in that case we dump the contents of the file
  537.                 // as the "value" for the Property.
  538.                 if (StringHelper::endsWith("file.contents", $property)) {
  539.                     // pull in contents of file specified 
  540.                                             
  541.                     $property = substr($property, 0, strpos($property, "file.contents") - 1);
  542.                     
  543.                     // reset value, and then 
  544.                     // read in teh contents of the file into that var
  545.                     $value = "";
  546.                     $f = new PhingFile($project->resolveFile($value)->getCanonicalPath());                        
  547.                     if ($f->exists()) {
  548.                         try {
  549.                             $fr = new FileReader($f);
  550.                             $fr->readInto($value);
  551.                         } catch (Exception $e) {
  552.                             throw $e;
  553.                         }
  554.                     }    
  555.                                                                     
  556.                  } // if ends with file.contents
  557.                 
  558.                     if (StringHelper::isBoolean($value)) {
  559.                         $value = StringHelper::booleanValue($value);
  560.                     }
  561.                                                         
  562.                  $c->assign($property, $value); 
  563.                  
  564.             } // foreach property
  565.                 
  566.         } // if contextProperties !== null
  567.         
  568.         try {
  569.             //$c->display($this->controlTemplate);            
  570.             $writer->write($c->fetch($this->controlTemplate));
  571.             $writer->close();
  572.         } catch (IOException $ioe) {
  573.             $writer->close();
  574.             throw new BuildException("Cannot write parsed template.");
  575.         }        
  576.         
  577.         $this->cleanup();    
  578.     }
  579.  
  580.     /**
  581.      * <p>Place useful objects into the initial context.</p>
  582.      *
  583.      * <p>TexenTask places <code>Date().toString()</code> into the
  584.      * context as <code>$now</code>.  Subclasses who want to vary the
  585.      * objects in the context should override this method.</p>
  586.      *
  587.      * <p><code>$generator</code> is not put into the context in this
  588.      * method.</p>
  589.      *
  590.      * @param context The context to populate, as retrieved from
  591.      * {@link #initControlContext()}.
  592.      * @return void
  593.      * @throws Exception Error while populating context.  The {@link
  594.      * #execute()} method will catch and rethrow as a
  595.      * <code>BuildException</code>.
  596.      */
  597.     protected function populateInitialContext(Smarty $context)  {       
  598.     }
  599.     
  600.     /**
  601.      * A hook method called at the end of {@link #execute()} which can
  602.      * be overridden to perform any necessary cleanup activities (such
  603.      * as the release of database connections, etc.).  By default,
  604.      * does nothing.
  605.      * @return void
  606.      * @throws Exception Problem cleaning up.
  607.      */
  608.     protected function cleanup() {
  609.     }
  610. }
  611.