Documentation is available at Crafty_Compiler.class.php
- <?PHP
- /**
- * Implementation file of the Crafty_Compiler class.
- *
- * <pre>
- * PROJECT : Crafty
- * Template Engine.
- * AUTHOR : Crafty Team <crafty@zulan.net>
- * COPYRIGHT : (c) Thomas Ilsche, 2004
- *
- * FILE : [ROOT]\Crafty_Compiler.class.php
- * DESCRIPTION: Implementation file of the Crafty_Compiler class.
- * </pre>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * @package Crafty_Compiler
- * @author Crafty Team <crafty@zulan.net>
- * @copyright Copyright (c) Thomas Ilsche 2005
- * @version 1.0.4.2005.02.18
- * @link http://crafty.zulan.net
- * @license http://www.gnu.org/licenses/lgpl.html
- * GNU Lesser General Public License Version 2.1
- ***/
- /**
- * Crafty_Compiler class implementation
- *
- * This is the compiler class of the Crafty template engine. If you just want
- * to write templates, you will not need to make use of it.
- * The {@link Crafty} class will spawn an instance for internal usage if required.
- *
- * @package Crafty_Compiler
- * @author Crafty Team <crafty@zulan.net>
- * @copyright Copyright (c) Thomas Ilsche 2005
- * @version 1.0.4.2005.02.18
- * @link http://crafty.zulan.net
- * @license http://www.gnu.org/licenses/lgpl.html
- * GNU Lesser General Public License Version 2.1
- ***/
- class Crafty_Compiler
- {
- /**
- * Stores all {@link Crafty_Block} instances
- *
- * All blocks loaded will be created and stored in this array.
- * They are indexed by their name.
- *
- * @var array
- ***/
- public $blocks = array();
- /**
- * Stores all Crafty_Core_* instances
- *
- * All Crafty_Core_* instances that are loaded, except for
- * {@link Crafty_Core_Define} and {@link Crafty_Core_Require}, will be stored in
- * this array indexed by their classname.
- *
- * @var array
- ***/
- public $cores = array();
- /**
- * Stores the root {@link Crafty_Config} object
- *
- * This object is loaded by the {@link __construct() constructor} from the
- * Crafty_Compiler.config.xml file
- *
- * @var Crafty_Config
- ***/
- public $config;
- /**
- * Stores a filehandle to the compiled (binary) template
- *
- * {@link Crafty_Block::compileElement()} will use this filehandle to write the
- * compiled content into the file.
- *
- * @var resource
- ***/
- public $write_c_file_handle;
- /**
- * Object handle of a Crafty object
- *
- * This is the object that created the current Crafty_Compiler class.
- * Set by the {@link __construct() Constructor}
- *
- * @var Crafty
- ***/
- public $crafty;
- /**
- * Are variable blocks used?
- *
- * If this is TRUE {@link compile()} will also compile every loaded block
- * as variable block into a separate file.
- *
- * @var boolean
- ***/
- public $variable_blocks_used = FALSE;
- /**
- * Stores the name of the compiled template and its directory
- *
- * This is the MD5 hash of realpath($template_name), constructed by
- * {@link Crafty::display()}
- *
- * @var string
- ***/
- public $template_hash = '';
- /**
- * Path to the uncompiled template
- *
- * Set by {@link load()} and used by several Crafty_Core objects,
- * e.g. to check if an external block is present.
- *
- * @var string
- ***/
- public $template_path = '';
- /**
- * Array of strings that need to be replaced before parsing
- *
- * Double backslashes, backslash and single quote, backslash and double quote are
- * replaced during the process of parsing to protect the core pregs from beeing
- * confused.
- *
- * @var array
- ***/
- public $preparse_search = array();
- /**
- * Temporary replacements during the parsing process for {@link $preparse_search}
- *
- * The {@link __construct constructor} will create this array by some sha1 hashes
- *
- * @var array
- */
- public $preparse_replace = array();
- /**
- * Final replacements for {@link $preparse_search}
- *
- * Those will be replaced just after parsing. Security will be cared of
- * afterwards.
- *
- * @var array
- ***/
- public $preparse_final = array();
- /**
- * Stores defined values
- *
- * Associative array of all defines, created by {@link load()} using
- * {@link Crafty_Core_Define}
- *
- * @var array
- ***/
- public $defines = array();
- /**
- * Initializes a Crafty_Compiler instance
- *
- * The constructor intializes a Crafty_Compiler instance and loads the required
- * framework files, such as the class definitions for {@link Crafty_Config},
- * {@link Crafty_Block}, {@link Crafty_Core}, {@link Crafty_Core_Define},
- * {@link Crafty_Core_Require} and all other Crafty_Core_* classes.<br/>
- * It also instantiates the Crafty_Core_* classes and stores them in
- * {@link $cores}
- *
- * @param Crafty $crafty Crafty object that created this Compiler
- ***/
- public function __construct(Crafty $crafty)
- {
- require_once($crafty->path_crafty . 'Crafty_Config.class.php');
- require_once($crafty->path_crafty . 'Crafty_Block.class.php');
- require_once($crafty->path_crafty . 'core' . DIRECTORY_SEPARATOR
- . 'Crafty_Core.class.php');
- $this->crafty = $crafty;
- $this->config = new crafty_config($crafty->path_crafty
- . 'Crafty_Compiler.config.xml', $this);
- $path_core = $crafty->path_crafty . 'core' . DIRECTORY_SEPARATOR;
- /* escape sequences */
- $this->add_preparse('\\');
- $this->add_preparse('"');
- $this->add_preparse("'");
- $this->add_preparse(stripslashes($this->config->core->delimiter->left));
- $this->add_preparse(stripslashes($this->config->core->delimiter->right));
- $this->defines['_CRAFTY_COMPILE_TIME']['static'] = time();
- $this->defines['_CRAFTY_VERSION']['static'] = CRAFTY_VERSION;
- /* Loading the Core_* Casses */
- if (($dir = opendir($path_core)) === FALSE) {
- throw new Crafty_Exception("Cannot open core directory '"
- . $path_core ."'");
- return FALSE;
- }
- while ($file = readdir($dir)) {
- if ((substr($file, 0, 12) == 'Crafty_Core_')
- && (substr($file, -10) == '.class.php')) {
- require_once($path_core . $file);
- $core_class_name = substr($file, 0, -10);
- if (!class_exists($core_class_name)) {
- throw new Crafty_Exception("No class found named
- $core_class_name");
- } else {
- $new_core = new $core_class_name($this);
- if (!is_subclass_of($new_core, 'Crafty_Core')) {
- throw new Crafty_Exception("Crafty_Core_" . $new_core->name
- . ' is not a subclass of
- Crafty_Core and can not be used
- as core ');
- } else {
- $this->cores[$core_class_name] = $new_core;
- }
- }
- }
- }
- closedir($dir);
- require_once($crafty->path_crafty . 'Crafty_Core_Define.class.php');
- require_once($crafty->path_crafty . 'Crafty_Core_Require.class.php');
- }
- /**
- * Loads a template file.
- *
- * This method loads a template file, parses the {@link $define}s using
- * {@link Crafty_Core_Define}, parses the requires using
- * {@link Crafty_Core_Require} and calling itself for each require.<br/>
- * Then it parses the blocks and stores them in the {@link $blocks} array.
- *
- * @param $template Relative path to the template
- * @return boolean State of success
- ***/
- public function load($template_o)
- {
- $template = realpath($template_o);
- if ($template === FALSE) {
- throw new Crafty_Exception('Template file "' . $template_o
- . '" does not exist');
- }
- $old_template_path = $this->template_path;
- $this->template_path = dirname($template);
- if (!is_readable($template)) {
- throw new Crafty_Exception("Cannot open template file \"$template\"");
- }
- $content = file_get_contents($template);
- /* Config var loader */
- $core_define = new Crafty_Core_Define($this);
- if ($core_define->getPattern() &&
- (preg_match_all($core_define->getPattern(), $content, $matches,
- PREG_SET_ORDER | PREG_OFFSET_CAPTURE) !== FALSE)) {
- foreach($matches as $match_num => $match) {
- $callback_handover = array();
- foreach($match as $sub) {
- $callback_handover[] = $sub[0];
- }
- try {
- $pcm = $core_define->pregCallback($callback_handover);
- } catch ( Crafty_Exception $e ) {
- $e->file = $template;
- $e->line = $this->line_number($content, $match[0][1]);
- throw $e;
- }
- /* Cheap solution but should do it */
- /* This is now (v.1.0.4) done by the _parameterCheck
- $this->defines = array_merge($pcm['data'], $this->defines); */
- }
- unset($pcm);
- }
- unset($core_define);
- $core_require = new Crafty_Core_Require($this);
- if ($core_require->getPattern() &&
- (preg_match_all($core_require->getPattern(), $content, $matches,
- PREG_SET_ORDER | PREG_OFFSET_CAPTURE) !== FALSE)) {
- foreach($matches as $match_num => $match) {
- $callback_handover = array();
- foreach($match as $sub) {
- $callback_handover[] = $sub[0];
- }
- try {
- $pcm = $core_require->pregCallback($callback_handover);
- } catch ( Crafty_Exception $e ) {
- $e->file = $template;
- $e->line = $this->line_number($content, $match[0][1]);
- throw $e;
- }
- }
- unset($pcm);
- unset($matches);
- $this->variable_blocks_used = TRUE;
- }
- unset($core_require);
- /* I dislike using temp vars but this will make it look better... really */
- $cbd = $this->config->block->delimiter;
- $pattern = '/(?>' . sprintf($cbd->format, $cbd->start . '['
- . $cbd->top->separator[0] . '](.*?)')
- . '\r?\n?)'
- . '((?s).*?)'
- . sprintf($cbd->format, $cbd->end) . '/i';
- if (!preg_match_all($pattern, $content, $matches,
- PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
- throw new Crafty_Exception('Can not find any BLOCK', $template);
- }
- $split_pattern = '/[' . $cbd->top->separator[0] . ']/';
- foreach($matches as $number => $match) {
- $line_decl = $this->line_number($content, $match[1][1]);
- $splitted = preg_split($split_pattern, $match[1][0]);
- /* Lowercase all parameters... */
- for($i = 0; $i < count($splitted); $i++) {
- $splitted[$i] = strtolower($splitted[$i]);
- }
- if (empty($splitted[0])) {
- throw new Crafty_Exception('Block with no name',
- $template, $line_decl);
- }
- $name = $splitted[0];
- if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]*$/', $name)) {
- throw new Crafty_Exception("Invalid blockname: '". $name ."'",
- $template, $line_decl);
- }
- $block = new Crafty_Block($name, $this);
- if (in_array('external', $splitted)) {
- $block->is_external = TRUE;
- }
- $block->filename = $template;
- $block->line_decl = $line_decl;
- $block->line_cont = $this->line_number($content, $match[2][1]);
- if (isset($this->blocks[$block->name])) {
- throw new Crafty_Exception('Cannot redeclare block named "'
- . $block->name
- . '" (previously declared in "'
- . $this->blocks[$block->name]->filename
- . '" on line '
- . $this->blocks[$block->name]->line_decl
- . ')'
- , $template, $line_decl);
- }
- $block->load($match[2][0]);
- $this->blocks[$block->name] = $block;
- }
- /* for recursion... */
- $this->template_path = $old_template_path;
- }
- /**
- * Compiles a template
- *
- * This method basically opens a compiled template file, adds the php tags
- * and compiles the "main" block.<br/>
- * If {@link $variable_blocks_used variable blocks are used} it also compiles any
- * loaded template file into a separate file.
- *
- * @param $template_hash Hashfilename of the current template
- * @return boolean State of success
- ***/
- public function compile($template_hash)
- {
- $this->template_hash = $template_hash;
- $template_c = $this->crafty->path_templates_c . $this->template_hash
- . '.tpl.php';
- if (!isset($this->blocks['main'])) {
- throw new Crafty_Exception('No "main" block found');
- }
- /* Initializing the prefix and suffix blocks */
- $block_prefix = new Crafty_Block('', $this);
- $block_prefix->content[] = "<?php\n";
- $block_prefix->content[] = '/* file generated by Crafty version ';
- $block_prefix->content[] = CRAFTY_VERSION;
- $block_prefix->content[] = ' at ';
- $block_prefix->content[] = date('Y-m-d H:i:s');
- $block_prefix->content[] = ', PHP version ';
- $block_prefix->content[] = PHP_VERSION;
- $block_prefix->content[] = " */\n";
- $block_suffix = new Crafty_Block('', $this);
- $block_suffix->content[] = "?>\n";
- if (file_exists($template_c)) {
- if (!is_writable($template_c)) {
- throw new Crafty_Exception("No write permission on \"$template_c\""
- . ' even though the file exists.<br />'
- . ' Please grant write access for the user'
- . ' / process running php on all files in'
- . ' the "'
- . $this->crafty->path_templates_c
- . '" directory.');
- }
- } else {
- if (!is_writable($this->crafty->path_templates_c)) {
- throw new Crafty_Exception('No write permission on "'
- . $this->crafty->path_templates_c
- . '". Please grant write access for the'
- . 'user / process running php.');
- }
- }
- $file_handle = fopen($template_c, 'w');
- $this->write_c_file_handle = $file_handle;
- $block_prefix->compile();
- $this->blocks['main']->compile();
- if ($this->variable_blocks_used) { /* OH MY GOD! WE'RE DOOMED! */
- $block_func_prefix = new Crafty_Block('', $this);
- $block_func_prefix->content[000] = 'function _';
- $block_func_prefix->content[010] = $this->template_hash;
- $block_func_prefix->content[020] = '_';
- $block_func_prefix->content[100] = ''; /* block name */
- $block_func_prefix->content[200] = "(\$p,&\$d){\n";
- $block_func_suffix = new Crafty_Block('', $this);
- $block_func_suffix->content[0] = "}\n";
- $block_func_inc = new Crafty_Block('', $this);
- $block_func_inc->content[000] = "include('";
- $block_func_inc->content[100] = '';
- $block_func_inc->content[200] = "');\n";
- foreach($this->blocks as $block_name => $block) {
- $block_func_prefix->content[100] = $block_name;
- $block_func_prefix->compile();
- $block->name = "main.'.\$p.'";
- if (!$block->is_external) {
- $block->compile();
- } else {
- $block_dir = $this->crafty->path_templates_c . $this->template_hash
- . '_files';
- $block_file = $block_dir . DIRECTORY_SEPARATOR . $block_name
- . '.block.tpl.php';
- $block_func_inc->content[100] = $block_file;
- $block_func_inc->compile();
- }
- $block_func_suffix->compile();
- }
- }
- $block_suffix->compile();
- fclose($file_handle);
- $this->write_c_file_handle = NULL;
- /* External variable blocks */
- if ($this->variable_blocks_used) { /* OH MY GOD! WE'RE DOOMED! */
- foreach($this->blocks as $block_name => $block) {
- if ($block->is_external) {
- $block_dir = $this->crafty->path_templates_c . $this->template_hash
- . '_files';
- if (!is_dir($block_dir)) {
- if (!mkdir($block_dir)) {
- throw new Crafty_Exception('Cannot create compiled block '
- . 'directory: "' . $block_dir
- . '" Check your chmod settings for '
- . 'the compiled template path.');
- }
- }
- $block_file = $block_dir . DIRECTORY_SEPARATOR . $block_name
- . '.block.tpl.php';
- if (($file_handle = fopen($block_file, 'w')) === FALSE) {
- throw new Crafty_Exception('Cannot open template compile '
- . "\"$template_c\" for writing");
- }
- $this->write_c_file_handle = $file_handle;
- $block_prefix->compile();
- /*$block->name = "main.'.\$p.'"; done already */
- $block->compile();
- $block_suffix->compile();
- fclose($file_handle);
- $this->write_c_file_handle = NULL;
- }
- }
- }
- return TRUE;
- }
- /**
- * Booleanize a value
- *
- * Check the string for true|yes|on|1 / false|no|off|0 and return a boolean in that
- * case
- *
- * @param string $value
- * @return mixed
- ***/
- public function booleanize($value)
- {
- if (preg_match('/^\s*(true|yes|on|1)\s*$/i', $value)) {
- return true;
- } elseif (preg_match('/^\s*(false|no|off|0)\s*$/i', $value)) {
- return false;
- } else {
- return $value;
- }
- }
- /**
- * Gets the linenumber of an offset
- *
- * @param string $content
- * @param int $offset
- * @param string $start_line Optional: Default 1
- * @return int
- ***/
- public function line_number($content, $offset, $start_line = 1)
- {
- return preg_match_all('/\r\n|\n|\r/', substr($content,0,$offset), $void) + $start_line;
- }
- /**
- * Adds a character(sequence) that will be able to be escaped by a backslash
- *
- * @param string character(sequence) to be escapable
- ***/
- public function add_preparse($character)
- {
- $this->preparse_search[] = '\\' . $character;
- $this->preparse_replace[] = sha1($character . 'Crafty');
- $this->preparse_final[] = $character;
- }
- }
- ?>
Documentation generated on Sat, 19 Feb 2005 01:43:40 +0100 by phpDocumentor 1.3.0RC3