Spaces:
Sleeping
Sleeping
| /* | |
| * $Id: SmartyTask.php 3076 2006-12-18 08:52:12Z 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>. | |
| */ | |
| require_once 'phing/TaskPhing.php'; | |
| 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:12Z fabien $ | |
| * @package phing.tasks.ext | |
| */ | |
| class SmartyTask extends TaskPhing { | |
| /** | |
| * 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() { | |
| } | |
| } | |