2010-12-02 23:34:41 +00:00
< ? php
/*
* $Id : SmartyTask . php 3076 2006 - 12 - 18 08 : 52 : 12 Z fabien $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL . For more information please see
* < http :// phing . info >.
*/
2011-09-08 15:00:41 -04:00
require_once 'phing/TaskPhing.php' ;
2010-12-02 23:34:41 +00:00
include_once 'phing/BuildException.php' ;
include_once 'phing/util/StringHelper.php' ;
/**
* A phing task for generating output by using Smarty .
*
* This is based on the TexenTask from Apache ' s Velocity engine . This class
* was originally proted in order to provide a template compiling system for
* Torque .
*
* TODO :
* - Add Path / useClasspath support ?
*
* @ author Hans Lellelid < hans @ xmpl . org > ( SmartyTask )
* @ author Jason van Zyl < jvanzyl @ apache . org > ( TexenTask )
* @ author Robert Burrell Donkin < robertdonkin @ mac . com >
* @ version $Id : SmartyTask . php 3076 2006 - 12 - 18 08 : 52 : 12 Z fabien $
* @ package phing . tasks . ext
*/
2011-09-08 15:00:41 -04:00
class SmartyTask extends TaskPhing {
2010-12-02 23:34:41 +00:00
/**
* Smarty template engine .
* @ var Smarty
*/
protected $context ;
/**
* Variables that are assigned to the context on parse / compile .
* @ var array
*/
protected $properties = array ();
/**
* This is the control template that governs the output .
* It may or may not invoke the services of worker
* templates .
* @ var string
*/
protected $controlTemplate ;
/**
* This is where Velocity will look for templates
* using the file template loader .
* @ var string
*/
protected $templatePath ;
/**
* This is where texen will place all the output
* that is a product of the generation process .
* @ var string
*/
protected $outputDirectory ;
/**
* This is the file where the generated text
* will be placed .
* @ var string
*/
protected $outputFile ;
/**
* < p >
* These are properties that are fed into the
* initial context from a properties file . This
* is simply a convenient way to set some values
* that you wish to make available in the context .
* </ p >
* < p >
* These values are not critical , like the template path
* or output path , but allow a convenient way to
* set a value that may be specific to a particular
* generation task .
* </ p >
* < p >
* For example , if you are generating scripts to allow
* user to automatically create a database , then
* you might want the < code > $databaseName </ code >
* to be placed
* in the initial context so that it is available
* in a script that might look something like the
* following :
* < code >< pre >
* #!bin/sh
*
* echo y | mysqladmin create $databaseName
* </ pre ></ code >
* The value of < code > $databaseName </ code > isn ' t critical to
* output , and you obviously don ' t want to change
* the ant task to simply take a database name .
* So initial context values can be set with
* properties file .
*
* @ var array
*/
protected $contextProperties ;
/**
* Smarty compiles templates before parsing / replacing tokens in them .
* By default it will try ./ templates_c , but you may wish to override this .
* @ var string
*/
protected $compilePath ;
/**
* Whether to force Smarty to recompile templates .
* Smarty does check file modification time , but you can set this
* to be * sure * that the template will be compiled ( of course it will
* be slower if you do ) .
* @ var boolean
*/
protected $forceCompile = false ;
/**
* Smarty can use config files .
* This tells Smarty where to look for the config files .
* @ var string
*/
protected $configPath ;
/**
* Customize the left delimiter for Smarty tags .
* @ var string
*/
protected $leftDelimiter ;
/**
* Customize the right delimiter for Smarty tags .
* @ var string
*/
protected $rightDelimiter ;
// -----------------------------------------------------------------------
// The following getters & setters are used by phing to set properties
// specified in the XML for the smarty task.
// -----------------------------------------------------------------------
public function init () {
include_once 'Smarty.class.php' ;
if ( ! class_exists ( 'Smarty' )) {
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. " );
}
}
/**
* [ REQUIRED ] Set the control template for the
* generating process .
* @ param string $controlTemplate
* @ return void
*/
public function setControlTemplate ( $controlTemplate ) {
$this -> controlTemplate = $controlTemplate ;
}
/**
* Get the control template for the
* generating process .
* @ return string
*/
public function getControlTemplate () {
return $this -> controlTemplate ;
}
/**
* [ REQUIRED ] Set the path where Velocity will look
* for templates using the file template
* loader .
* @ return void
* @ throws Exception
*/
public function setTemplatePath ( $templatePath ) {
$resolvedPath = " " ;
$tok = strtok ( $templatePath , " , " );
while ( $tok ) {
// resolve relative path from basedir and leave
// absolute path untouched.
$fullPath = $this -> project -> resolveFile ( $tok );
$cpath = $fullPath -> getCanonicalPath ();
if ( $cpath === false ) {
$this -> log ( " Template directory does not exist: " . $fullPath -> getAbsolutePath ());
} else {
$resolvedPath .= $cpath ;
}
$tok = strtok ( " , " );
if ( $tok ) {
$resolvedPath .= " , " ;
}
}
$this -> templatePath = $resolvedPath ;
}
/**
* Get the path where Velocity will look
* for templates using the file template
* loader .
* @ return string
*/
public function getTemplatePath () {
return $this -> templatePath ;
}
/**
* [ REQUIRED ] Set the output directory . It will be
* created if it doesn ' t exist .
* @ param PhingFile $outputDirectory
* @ return void
* @ throws Exception
*/
public function setOutputDirectory ( PhingFile $outputDirectory ) {
try {
if ( ! $outputDirectory -> exists ()) {
$this -> log ( " Output directory does not exist, creating: " . $outputDirectory -> getPath (), PROJECT_MSG_VERBOSE );
if ( ! $outputDirectory -> mkdirs ()) {
throw new IOException ( " Unable to create Ouptut directory: " . $outputDirectory -> getAbsolutePath ());
}
}
$this -> outputDirectory = $outputDirectory -> getCanonicalPath ();
} catch ( IOException $ioe ) {
throw new BuildException ( $ioe -> getMessage ());
}
}
/**
* Get the output directory .
* @ return string
*/
public function getOutputDirectory () {
return $this -> outputDirectory ;
}
/**
* [ REQUIRED ] Set the output file for the
* generation process .
* @ return void
*/
public function setOutputFile ( $outputFile ) {
$this -> outputFile = $outputFile ;
}
/**
* Get the output file for the
* generation process .
* @ return string
*/
public function getOutputFile () {
return $this -> outputFile ;
}
/**
* Set the path Smarty uses as a " cache " for compiled templates .
* @ param string $compilePath
*/
public function setCompilePath ( $compilePath ) {
$this -> compilePath = $compilePath ;
}
/**
* Get the path Smarty uses for compiling templates .
* @ return string
*/
public function getCompilePath () {
return $this -> compilePath ;
}
/**
* Set whether Smarty should always recompile tempaltes .
* @ param boolean $force
* @ return void
*/
public function setForceCompile ( $force ) {
$this -> forceCompile = ( boolean ) $force ;
}
/**
* Get whether Smarty should always recompile template .
* @ return boolean
*/
public function getForceCompile () {
return $this -> forceCompile ;
}
/**
* Set where Smarty looks for config files .
* @ param string $configPath
* @ return void
*/
public function setConfigPath ( $configPath ) {
$this -> configPath = $configPath ;
}
/**
* Get the path that Smarty uses for looking for config files .
* @ return string
*/
public function getConfigPath () {
return $this -> configPath ;
}
/**
* Set Smarty template left delimiter .
* @ param string $delim
* @ return void
*/
public function setLeftDelimiter ( $delim ) {
$this -> leftDelimiter = $delim ;
}
/**
* Get Smarty template right delimiter
* @ return string
*/
public function getLeftDelimiter () {
return $this -> leftDelimiter ;
}
/**
* Set Smarty template right delimiter .
* @ param string $delim
* @ return void
*/
public function setRightDelimiter ( $delim ) {
$this -> rightDelimiter = $delim ;
}
/**
* Get Smarty template right delimiter
* @ return string
*/
public function getRightDelimiter () {
return $this -> rightDelimiter ;
}
/**
* Set the context properties that will be
* fed into the initial context be the
* generating process starts .
* @ param string $file
* @ return void
*/
public function setContextProperties ( $file ) {
$sources = explode ( " , " , $file );
$this -> contextProperties = new Properties ();
// Always try to get the context properties resource
// from a file first. Templates may be taken from a JAR
// file but the context properties resource may be a
// resource in the filesystem. If this fails than attempt
// to get the context properties resource from the
// classpath.
for ( $i = 0 , $sourcesLength = count ( $sources ); $i < $sourcesLength ; $i ++ ) {
$source = new Properties ();
try {
// resolve relative path from basedir and leave
// absolute path untouched.
$fullPath = $this -> project -> resolveFile ( $sources [ $i ]);
$this -> log ( " Using contextProperties file: " . $fullPath -> __toString ());
$source -> load ( $fullPath );
} catch ( Exception $e ) {
throw new BuildException ( " Context properties file " . $sources [ $i ] .
" could not be found in the file system! " );
}
$keys = $source -> keys ();
foreach ( $keys as $key ) {
$name = $key ;
$value = $this -> project -> replaceProperties ( $source -> getProperty ( $name ));
$this -> contextProperties -> setProperty ( $name , $value );
}
}
}
/**
* Get the context properties that will be
* fed into the initial context be the
* generating process starts .
* @ return Properties
*/
public function getContextProperties () {
return $this -> contextProperties ;
}
// ---------------------------------------------------------------
// End of XML setters & getters
// ---------------------------------------------------------------
/**
* Creates a Smarty object .
*
* @ return Smarty initialized ( cleared ) Smarty context .
* @ throws Exception the execute method will catch
* and rethrow as a < code > BuildException </ code >
*/
public function initControlContext () {
$this -> context -> clear_all_assign ();
return $this -> context ;
}
/**
* Execute the input script with Velocity
*
* @ throws BuildException
* BuildExceptions are thrown when required attributes are missing .
* Exceptions thrown by Velocity are rethrown as BuildExceptions .
*/
public function main () {
// Make sure the template path is set.
if ( empty ( $this -> templatePath )) {
throw new BuildException ( " The template path needs to be defined! " );
}
// Make sure the control template is set.
if ( $this -> controlTemplate === null ) {
throw new BuildException ( " The control template needs to be defined! " );
}
// Make sure the output directory is set.
if ( $this -> outputDirectory === null ) {
throw new BuildException ( " The output directory needs to be defined! " );
}
// Make sure there is an output file.
if ( $this -> outputFile === null ) {
throw new BuildException ( " The output file needs to be defined! " );
}
// Setup Smarty runtime.
// Smarty uses one object to store properties and to store
// the context for the template (unlike Velocity). We setup this object, calling it
// $this->context, and then initControlContext simply zeros out
// any assigned variables.
$this -> context = new Smarty ();
if ( $this -> compilePath !== null ) {
$this -> log ( " Using compilePath: " . $this -> compilePath );
$this -> context -> compile_dir = $this -> compilePath ;
}
if ( $this -> configPath !== null ) {
$this -> log ( " Using configPath: " . $this -> configPath );
$this -> context -> config_dir = $this -> configPath ;
}
if ( $this -> forceCompile !== null ) {
$this -> context -> force_compile = $this -> forceCompile ;
}
if ( $this -> leftDelimiter !== null ) {
$this -> context -> left_delimiter = $this -> leftDelimiter ;
}
if ( $this -> rightDelimiter !== null ) {
$this -> context -> right_delimiter = $this -> rightDelimiter ;
}
if ( $this -> templatePath !== null ) {
$this -> log ( " Using templatePath: " . $this -> templatePath );
$this -> context -> template_dir = $this -> templatePath ;
}
$smartyCompilePath = new PhingFile ( $this -> context -> compile_dir );
if ( ! $smartyCompilePath -> exists ()) {
$this -> log ( " Compile directory does not exist, creating: " . $smartyCompilePath -> getPath (), PROJECT_MSG_VERBOSE );
if ( ! $smartyCompilePath -> mkdirs ()) {
throw new BuildException ( " Smarty needs a place to compile templates; specify a 'compilePath' or create " . $this -> context -> compile_dir );
}
}
// Make sure the output directory exists, if it doesn't
// then create it.
$file = new PhingFile ( $this -> outputDirectory );
if ( ! $file -> exists ()) {
$this -> log ( " Output directory does not exist, creating: " . $file -> getAbsolutePath ());
$file -> mkdirs ();
}
$path = $this -> outputDirectory . DIRECTORY_SEPARATOR . $this -> outputFile ;
$this -> log ( " Generating to file " . $path );
$writer = new FileWriter ( $path );
// The generator and the output path should
// be placed in the init context here and
// not in the generator class itself.
$c = $this -> initControlContext ();
// Set any variables that need to always
// be loaded
$this -> populateInitialContext ( $c );
// Feed all the options into the initial
// control context so they are available
// in the control/worker templates.
if ( $this -> contextProperties !== null ) {
foreach ( $this -> contextProperties -> keys () as $property ) {
$value = $this -> contextProperties -> getProperty ( $property );
// Special exception (from Texen)
// for properties ending in file.contents:
// in that case we dump the contents of the file
// as the "value" for the Property.
if ( StringHelper :: endsWith ( " file.contents " , $property )) {
// pull in contents of file specified
$property = substr ( $property , 0 , strpos ( $property , " file.contents " ) - 1 );
// reset value, and then
// read in teh contents of the file into that var
$value = " " ;
$f = new PhingFile ( $project -> resolveFile ( $value ) -> getCanonicalPath ());
if ( $f -> exists ()) {
try {
$fr = new FileReader ( $f );
$fr -> readInto ( $value );
} catch ( Exception $e ) {
throw $e ;
}
}
} // if ends with file.contents
if ( StringHelper :: isBoolean ( $value )) {
$value = StringHelper :: booleanValue ( $value );
}
$c -> assign ( $property , $value );
} // foreach property
} // if contextProperties !== null
try {
//$c->display($this->controlTemplate);
$writer -> write ( $c -> fetch ( $this -> controlTemplate ));
$writer -> close ();
} catch ( IOException $ioe ) {
$writer -> close ();
throw new BuildException ( " Cannot write parsed template. " );
}
$this -> cleanup ();
}
/**
* < p > Place useful objects into the initial context .</ p >
*
* < p > TexenTask places < code > Date () . toString () </ code > into the
* context as < code > $now </ code >. Subclasses who want to vary the
* objects in the context should override this method .</ p >
*
* < p >< code > $generator </ code > is not put into the context in this
* method .</ p >
*
* @ param context The context to populate , as retrieved from
* { @ link #initControlContext()}.
* @ return void
* @ throws Exception Error while populating context . The { @ link
* #execute()} method will catch and rethrow as a
* < code > BuildException </ code >.
*/
protected function populateInitialContext ( Smarty $context ) {
}
/**
* A hook method called at the end of { @ link #execute()} which can
* be overridden to perform any necessary cleanup activities ( such
* as the release of database connections , etc . ) . By default ,
* does nothing .
* @ return void
* @ throws Exception Problem cleaning up .
*/
protected function cleanup () {
}
}