Убрал phptal и лишнее

This commit is contained in:
Фёдор Подлеснов 2016-07-21 14:49:21 +03:00
parent 651a841187
commit 96043d70e6
95 changed files with 4 additions and 10833 deletions

View file

@ -1,788 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
define('PHPTAL_VERSION', '1_1_14');
//{{{PHPTAL_DIR
if (!defined('PHPTAL_DIR')) define('PHPTAL_DIR',dirname(__FILE__).DIRECTORY_SEPARATOR);
else assert('substr(PHPTAL_DIR,-1) == DIRECTORY_SEPARATOR');
//}}}
/* Please don't use the following constants. They have been replaced by methods in the PHPTAL class and are kept for backwards compatibility only. */
//{{{
if (!defined('PHPTAL_PHP_CODE_DESTINATION')) {
if (function_exists('sys_get_temp_dir')) define('PHPTAL_PHP_CODE_DESTINATION',rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR);
else if (substr(PHP_OS,0,3) == 'WIN') {
if (file_exists('c:\\WINNT\\Temp\\')) define('PHPTAL_PHP_CODE_DESTINATION', 'c:\\WINNT\\Temp\\');
else define('PHPTAL_PHP_CODE_DESTINATION', 'c:\\WINDOWS\\Temp\\');
}
else define('PHPTAL_PHP_CODE_DESTINATION', '/tmp/');
}
if (!defined('PHPTAL_DEFAULT_ENCODING')) define('PHPTAL_DEFAULT_ENCODING', 'UTF-8');
if (!defined('PHPTAL_PHP_CODE_EXTENSION')) define('PHPTAL_PHP_CODE_EXTENSION', 'php');
//}}}
define('PHPTAL_XHTML', 1);
define('PHPTAL_XML', 2);
require_once PHPTAL_DIR.'PHPTAL/FileSource.php';
require_once PHPTAL_DIR.'PHPTAL/RepeatController.php';
require_once PHPTAL_DIR.'PHPTAL/Context.php';
require_once PHPTAL_DIR.'PHPTAL/Exception.php';
require_once PHPTAL_DIR.'PHPTAL/TalesRegistry.php';
/**
* PHPTAL template entry point.
*
* <code>
* <?php
* require_once 'PHPTAL.php';
* try {
* $tpl = new PHPTAL('mytemplate.html');
* $tpl->title = 'Welcome here';
* $tpl->result = range(1, 100);
* ...
* echo $tpl->execute();
* }
* catch (Exception $e) {
* echo $e;
* }
* ?>
* </code>
*
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL
{
const XHTML = 1;
const XML = 2;
/**
* PHPTAL Constructor.
*
* @param string $path Template file path.
*/
public function __construct($path=false)
{
$this->_path = $path;
$this->_repositories = array();
if (defined('PHPTAL_TEMPLATE_REPOSITORY')){
$this->_repositories[] = PHPTAL_TEMPLATE_REPOSITORY;
}
$this->_resolvers = array();
$this->_globalContext = new StdClass();
$this->_context = new PHPTAL_Context();
$this->_context->setGlobal($this->_globalContext);
}
/**
* create
* returns a new PHPTAL object
*
* @param string $path Template file path.
* @return PHPTAL
*/
public static function create($path=false)
{
return new PHPTAL($path);
}
/**
* Clone template state and context.
*/
public function __clone()
{
$context = $this->_context;
$this->_context = clone $this->_context;
$this->_context->setParent($context);
$this->_context->setGlobal($this->_globalContext);
}
/**
* Set template from file path.
* @param $path string
*/
public function setTemplate($path)
{
$this->_prepared = false;
$this->_functionName = null;
$this->_path = $path;
$this->_source = null;
return $this;
}
/**
* Set template from source.
*
* Should be used only with temporary template sources. Use setTemplate() whenever possible.
*
* @param $src string The phptal template source.
* @param path string Fake and 'unique' template path.
*/
public function setSource($src, $path=false)
{
if ($path == false)
$path = '<string> '.md5($src);
require_once PHPTAL_DIR.'PHPTAL/StringSource.php';
$this->_source = new PHPTAL_StringSource($src, $path);
$this->_path = $path;
return $this;
}
/**
* Specify where to look for templates.
*
* @param $rep mixed string or Array of repositories
*/
public function setTemplateRepository($rep)
{
if (is_array($rep)){
$this->_repositories = $rep;
}
else {
$this->_repositories[] = $rep;
}
return $this;
}
/**
* Get template repositories.
*/
public function getTemplateRepositories()
{
return $this->_repositories;
}
/**
* Clears the template repositories.
*/
public function clearTemplateRepositories()
{
$this->_repositories = array();
return $this;
}
/**
* Ignore XML/XHTML comments on parsing.
* @param $bool bool
*/
public function stripComments($bool)
{
$this->_stripComments = $bool;
return $this;
}
/**
* Set output mode
* XHTML output mode will force elements like <link/>, <meta/> and <img/>, etc. to be empty
* and threats attributes like selected, checked to be boolean attributes.
*
* XML output mode outputs XML without such modifications and is neccessary to generate RSS feeds properly.
* @param $mode int (PHPTAL::XML or PHPTAL::XHTML).
*/
public function setOutputMode($mode=PHPTAL_XHTML)
{
if ($mode != PHPTAL::XHTML && $mode != PHPTAL::XML){
throw new PHPTAL_Exception('Unsupported output mode '.$mode);
}
$this->_outputMode = $mode;
return $this;
}
/**
* Get output mode
*/
public function getOutputMode()
{
return $this->_outputMode;
}
/**
* Set input and ouput encoding.
* @param $enc string example: 'UTF-8'
*/
public function setEncoding($enc)
{
$this->_encoding = $enc;
if ($this->_translator) $this->_translator->setEncoding($enc);
return $this;
}
/**
* Get input and ouput encoding.
* @param $enc string example: 'UTF-8'
*/
public function getEncoding()
{
return $this->_encoding;
}
/**
* Set the storage location for intermediate PHP files. The path cannot contain characters that would be interpreted by glob() (e.g. * or ?)
* @param string $path Intermediate file path.
*/
public function setPhpCodeDestination($path)
{
$this->_phpCodeDestination = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
return $this;
}
/**
* Get the storage location for intermediate PHP files.
*/
public function getPhpCodeDestination()
{
return $this->_phpCodeDestination;
}
/**
* Set the file extension for intermediate PHP files.
* @param string $extension The file extension.
*/
public function setPhpCodeExtension($extension)
{
$this->_phpCodeExtension = $extension;
return $this;
}
/**
* Get the file extension for intermediate PHP files.
*/
public function getPhpCodeExtension()
{
return $this->_phpCodeExtension;
}
/**
* Flags whether to ignore intermediate php files and to
* reparse templates every time (if set to true).
* Don't use in production - this makes PHPTAL significantly slower.
* @param bool bool Forced reparse state.
*/
public function setForceReparse($bool)
{
$this->_forceReparse = (bool) $bool;
return $this;
}
/**
* Get the value of the force reparse state.
*/
public function getForceReparse()
{
return $this->_forceReparse !== NULL ? $this->_forceReparse : (defined('PHPTAL_FORCE_REPARSE') && PHPTAL_FORCE_REPARSE);
}
/**
* Set I18N translator.
* This sets encoding used by the translator, so be sure to use encoding-dependent features of the translator (e.g. addDomain) _after_ calling setTranslator.
*/
public function setTranslator(PHPTAL_TranslationService $t)
{
$this->_translator = $t;
$this->_translator->setEncoding($this->getEncoding());
return $this;
}
/**
* Set template pre filter. It will be called once before template is compiled.
*/
public function setPreFilter(PHPTAL_Filter $filter)
{
$this->_prefilter = $filter;
return $this;
}
/**
* Set template post filter. It will be called every time after template generates output.
*/
public function setPostFilter(PHPTAL_Filter $filter)
{
$this->_postfilter = $filter;
return $this;
}
/**
* Register a trigger for specified phptal:id.
* @param $id string phptal:id to look for
*/
public function addTrigger($id, PHPTAL_Trigger $trigger)
{
$this->_triggers[$id] = $trigger;
return $this;
}
/**
* Returns trigger for specified phptal:id.
* @param $id string phptal:id
*/
public function getTrigger($id)
{
if (array_key_exists($id, $this->_triggers)){
return $this->_triggers[$id];
}
return null;
}
/**
* Set a context variable.
* @param $varname string
* @param $value mixed
*/
public function __set($varname, $value)
{
$this->_context->__set($varname, $value);
}
/**
* Set a context variable.
* @param $varname string
* @param $value mixed
*/
public function set($varname, $value)
{
$this->_context->__set($varname, $value);
return $this;
}
/**
* Execute the template code.
*
* @return string
*/
public function execute()
{
if (!$this->_prepared) {
$this->prepare();
}
// includes generated template PHP code
$this->_context->__file = $this->__file;
require_once $this->getCodePath();
$templateFunction = $this->getFunctionName();
try {
ob_start();
$templateFunction($this, $this->_context);
$res = ob_get_clean();
}
catch (Exception $e){
ob_end_clean();
throw $e;
}
// unshift doctype
$docType = $this->_context->__docType;
if ($docType){
$res = $docType . "\n" . $res;
}
// unshift xml declaration
$xmlDec = $this->_context->__xmlDeclaration;
if ($xmlDec){
$res = $xmlDec . "\n" . $res;
}
if ($this->_postfilter != null){
return $this->_postfilter->filter($res);
}
return $res;
}
protected function setConfigurationFrom(PHPTAL $from)
{
// use references - this way config of both objects will be more-or-less in sync
$this->_encoding = &$from->_encoding;
$this->_outputMode = &$from->_outputMode;
$this->_stripComments = &$from->_stripComments;
$this->_forceReparse = &$from->_forceReparse;
$this->_phpCodeDestination = &$from->_phpCodeDestination;
$this->_phpCodeExtension = &$from->_phpCodeExtension;
$this->_cacheLifetime = &$from->_cacheLifetime;
$this->_cachePurgeFrequency = &$from->_cachePurgeFrequency;
$this->setTemplateRepository($from->_repositories);
array_unshift($this->_repositories, dirname($from->_source->getRealPath()));
$this->_resolvers = &$from->_resolvers;
$this->_prefilter = &$from->_prefilter;
$this->_postfilter = &$from->_postfilter;
}
private $externalMacroTempaltesCache = array();
/**
* Execute a template macro.
* Should be used only from within generated template code!
*
* @param $path string Template macro path
*/
public function executeMacro($path)
{
// extract macro source file from macro name, if not source file
// found in $path, then the macro is assumed to be local
if (preg_match('/^(.*?)\/([a-z0-9_]*)$/i', $path, $m)){
list(,$file,$macroName) = $m;
if (isset($this->externalMacroTempaltesCache[$file]))
{
$tpl = $this->externalMacroTempaltesCache[$file];
}
else
{
$tpl = new PHPTAL($file);
$tpl->setConfigurationFrom($this);
$tpl->prepare();
// require PHP generated code
require_once $tpl->getCodePath();
$this->externalMacroTempaltesCache[$file] = $tpl;
if (count($this->externalMacroTempaltesCache) > 10) $this->externalMacroTempaltesCache = array(); // keep it small (typically only 1 or 2 external files are used)
}
// save current file
$currentFile = $this->_context->__file;
$this->_context->__file = $tpl->__file;
$fun = $tpl->getFunctionName() . '_' . $macroName;
if (!function_exists($fun)) throw new PHPTAL_Exception("Macro '$macroName' is not defined in $file",$this->_source->getRealPath());
$fun($this, $this->_context);
// restore current file
$this->_context->__file = $currentFile;
}
else
{
// call local macro
$fun = $this->getFunctionName() . '_' . trim($path);
if (!function_exists($fun)) throw new PHPTAL_Exception("Macro '$path' is not defined",$this->_source->getRealPath());
$fun( $this, $this->_context );
}
}
private function setCodeFile()
{
$this->_codeFile = $this->getPhpCodeDestination() . $this->getFunctionName() . '.' . $this->getPhpCodeExtension();
}
/**
* Prepare template without executing it.
*/
public function prepare()
{
// clear just in case settings changed and cache is out of date
$this->externalMacroTempaltesCache = array();
// find the template source file
$this->findTemplate();
$this->__file = $this->_source->getRealPath();
$this->setCodeFile();
// parse template if php generated code does not exists or template
// source file modified since last generation of PHPTAL_FORCE_REPARSE
// is defined.
if ($this->getForceReparse() || !file_exists($this->_codeFile))
{
if ($this->getCachePurgeFrequency() && mt_rand()%$this->getCachePurgeFrequency() == 0)
{
$this->cleanUpGarbage();
}
$this->parse();
}
$this->_prepared = true;
return $this;
}
public function getCacheLifetime()
{
return $this->_cacheLifetime;
}
/**
* how long compiled templates and phptal:cache files are kept, in days
*/
public function setCacheLifetime($days)
{
$this->_cacheLifetime = max(0.5,$days);
return $this;
}
/**
* PHPTAL will scan cache and remove old files on every nth compile
* Set to 0 to disable cleanups
*/
public function setCachePurgeFrequency($n)
{
$this->_cachePurgeFrequency = (int)$n;
return $this;
}
public function getCachePurgeFrequency()
{
return $this->_cachePurgeFrequency;
}
/**
* Removes all compiled templates from cache after PHPTAL_CACHE_LIFETIME days
*/
public function cleanUpGarbage()
{
$phptalCacheFilesExpire = time() - $this->getCacheLifetime() * 3600 * 24;
$upperLimit = $this->getPhpCodeDestination() . 'tpl_' . $phptalCacheFilesExpire . '_';
$lowerLimit = $this->getPhpCodeDestination() . 'tpl_0_';
$phptalCacheFiles = glob($this->getPhpCodeDestination() . 'tpl_*.' . $this->getPhpCodeExtension() . '*');
if ($phptalCacheFiles)
{
foreach($phptalCacheFiles as $index => $file)
{
if ($file > $upperLimit && substr($file,0,strlen($lowerLimit)) !== $lowerLimit)
{
unset($phptalCacheFiles[$index]);
}
}
foreach($phptalCacheFiles as $file)
{
$time = filemtime($file);
if ($time && $time < $phptalCacheFilesExpire) @unlink($file);
}
}
}
/**
* Removes single compiled template from cache and all its fragments cached by phptal:cache.
* Must be called after setSource/setTemplate.
*/
public function cleanUpCache()
{
if (!$this->getCodePath())
{
$this->findTemplate(); $this->setCodeFile();
if (!$this->getCodePath()) throw new PHPTAL_Exception("No codefile");
}
$filename = $this->getCodePath();
$phptalCacheFiles = glob($filename . '*');
if ($phptalCacheFiles) foreach($phptalCacheFiles as $file)
{
if (substr($file, 0, strlen($filename)) !== $filename) continue; // safety net
@unlink($file);
}
$this->_prepared = false;
}
/**
* Returns the path of the intermediate PHP code file.
*
* The returned file may be used to cleanup (unlink) temporary files
* generated by temporary templates or more simply for debug.
*
* @return string
*/
public function getCodePath()
{
return $this->_codeFile;
}
/**
* Returns the generated template function name.
* @return string
*/
public function getFunctionName()
{
if (!$this->_functionName) {
$this->_functionName = 'tpl_' . $this->_source->getLastModifiedTime() . '_' . PHPTAL_VERSION .
substr(preg_replace('/[^a-zA-Z]/','',basename($this->_source->getRealPath())),0,10) . md5($this->_source->getRealPath());
}
return $this->_functionName;
}
/**
* Returns template translator.
* @return PHPTAL_TranslationService
*/
public function getTranslator()
{
return $this->_translator;
}
/**
* Returns array of exceptions caught by tal:on-error attribute.
* @return array<Exception>
*/
public function getErrors()
{
return $this->_errors;
}
/**
* Public for phptal templates, private for user.
* @access private
*/
public function addError(Exception $error)
{
array_push($this->_errors, $error);
return $this;
}
/**
* Returns current context object.
* Use only in Triggers.
*
* @return PHPTAL_Context
*/
public function getContext()
{
return $this->_context;
}
/**
* only for use in generated template code
* @access private
*/
public function getGlobalContext()
{
return $this->_globalContext;
}
/**
* only for use in generated template code
* @access private
*/
public function pushContext()
{
$this->_context = $this->_context->pushContext();
return $this->_context;
}
/**
* only for use in generated template code
* @access private
*/
public function popContext()
{
$this->_context = $this->_context->popContext();
return $this->_context;
}
protected function parse()
{
require_once PHPTAL_DIR.'PHPTAL/Dom/Parser.php';
// instantiate the PHPTAL source parser
$parser = new PHPTAL_Dom_Parser($this->_encoding);
$parser->stripComments($this->_stripComments);
$data = $this->_source->getData();
$realpath = $this->_source->getRealPath();
if ($this->_prefilter)
$data = $this->_prefilter->filter($data);
$tree = $parser->parseString($data, $realpath);
require_once PHPTAL_DIR.'PHPTAL/Php/CodeGenerator.php';
$generator = new PHPTAL_Php_CodeGenerator($this->getFunctionName(), $this->_source->getRealPath());
$generator->setEncoding($this->_encoding);
$generator->setOutputMode($this->_outputMode);
$generator->generate($tree);
if (!@file_put_contents($this->_codeFile, $generator->getResult())) {
throw new PHPTAL_Exception('Unable to open '.$this->_codeFile.' for writing');
}
return $this;
}
/**
* Search template source location.
*/
protected function findTemplate()
{
if ($this->_path == false){
throw new PHPTAL_Exception('No template file specified');
}
// template source already defined
if ($this->_source != null){
return;
}
array_push($this->_resolvers, new PHPTAL_FileSourceResolver($this->_repositories));
foreach ($this->_resolvers as $resolver){
$source = $resolver->resolve($this->_path);
if ($source != null){
$this->_source = $source;
break;
}
}
array_pop($this->_resolvers);
if ($this->_source == null){
throw new PHPTAL_Exception('Unable to locate template file '.$this->_path);
}
}
protected $_prefilter = null;
protected $_postfilter = null;
// list of template source repositories
protected $_repositories = array();
// template path
protected $_path = null;
// template source resolvers
protected $_resolvers = array();
// template source (only set when not working with file)
protected $_source = null;
// destination of PHP intermediate file
protected $_codeFile = null;
// php function generated for the template
protected $_functionName = null;
// set to true when template is ready for execution
protected $_prepared = false;
// associative array of phptal:id => PHPTAL_Trigger
protected $_triggers = array();
// i18n translator
protected $_translator = null;
// global execution context
protected $_globalContext = null;
// current execution context
protected $_context = null;
// current template file (changes within macros)
public $__file = false;
// list of on-error caught exceptions
protected $_errors = array();
protected $_encoding = PHPTAL_DEFAULT_ENCODING;
protected $_outputMode = PHPTAL::XHTML;
protected $_stripComments = false;
// configuration properties
protected $_forceReparse = NULL;
protected $_phpCodeDestination = PHPTAL_PHP_CODE_DESTINATION;
protected $_phpCodeExtension = PHPTAL_PHP_CODE_EXTENSION;
protected $_cacheLifetime = 30;
protected $_cachePurgeFrequency = 50;
}
?>

View file

@ -1,12 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Filter.php';
class PHPTAL_CommentFilter implements PHPTAL_Filter
{
public function filter($src){
return preg_replace('/(<!--.*?-->)/s', '', $src);
}
}
?>

View file

@ -1,405 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* This class handles template execution context.
* @package phptal
*/
class PHPTAL_Context
{
public static $USE_GLOBAL = false;
public $__line = false;
public $__file = false;
public $__repeat;
public $__xmlDeclaration;
public $__docType;
public $__nothrow;
public $__translator;
public function __construct()
{
$this->__repeat = new StdClass();
}
public function __clone()
{
$this->__repeat = clone($this->__repeat);
}
public function setParent(PHPTAL_Context $parent)
{
$this->_parentContext = $parent;
}
public function setGlobal(StdClass $globalContext)
{
$this->_globalContext = $globalContext;
}
public function pushContext()
{
if (self::$USE_GLOBAL) return $this;
$res = clone $this;
$res->setParent($this);
return $res;
}
public function popContext()
{
if (self::$USE_GLOBAL) return $this;
return $this->_parentContext;
}
/**
* Set output document type if not already set.
*
* This method ensure PHPTAL uses the first DOCTYPE encountered (main
* template or any macro template source containing a DOCTYPE.
*/
public function setDocType($doctype)
{
if ($this->_parentContext != null){
return $this->_parentContext->setDocType($doctype);
}
if ($this->_parentContext != null){
return $this->_parentContext->setDocType($doctype);
}
if (!$this->__docType){
$this->__docType = $doctype;
}
}
/**
* Set output document xml declaration.
*
* This method ensure PHPTAL uses the first xml declaration encountered
* (main template or any macro template source containing an xml
* declaration).
*/
public function setXmlDeclaration($xmldec)
{
if ($this->_parentContext != null){
return $this->_parentContext->setXmlDeclaration($xmldec);
}
if ($this->_parentContext != null){
return $this->_parentContext->setXmlDeclaration($xmldec);
}
if (!$this->__xmlDeclaration){
$this->__xmlDeclaration = $xmldec;
}
}
/**
* Activate or deactivate exception throwing during unknown path
* resolution.
*/
public function noThrow($bool)
{
$this->__nothrow = $bool;
}
/**
* Returns true if specified slot is filled.
*/
public function hasSlot($key)
{
if ($this->_parentContext) return $this->_parentContext->hasSlot($key); // setting slots in any context
return array_key_exists($key, $this->_slots);
}
/**
* Returns the content of specified filled slot.
*/
public function getSlot($key)
{
if ($this->_parentContext) return $this->_parentContext->getSlot($key); // setting slots in any context
return $this->_slots[$key];
}
/**
* Fill a macro slot.
*/
public function fillSlot($key, $content)
{
if ($this->_parentContext) $this->_parentContext->fillSlot($key,$content); // setting slots in any context
else $this->_slots[$key] = $content;
}
/**
* Push current filled slots on stack.
*/
public function pushSlots()
{
array_push($this->_slotsStack, $this->_slots);
$this->_slots = array();
}
/**
* Restore filled slots stack.
*/
public function popSlots()
{
$this->_slots = array_pop($this->_slotsStack);
}
/**
* Context setter.
*/
public function __set($varname, $value)
{
if ($varname[0] == '_')
{
throw new PHPTAL_Exception('Template variable error \''.$varname.'\' must not begin with underscore');
}
$this->$varname = $value;
}
/**
* Context getter.
*/
public function __get($varname)
{
if ($varname == 'repeat')
return $this->__repeat;
if (isset($this->$varname)){
return $this->$varname;
}
if (isset($this->_globalContext->$varname)){
return $this->_globalContext->$varname;
}
if (defined($varname))
{
return constant($varname);
}
if ($this->__nothrow)
return null;
$e = sprintf('Unable to find path %s in current scope', $varname);
throw new PHPTAL_Exception($e, $this->__file, $this->__line);
}
private $_slots = array();
private $_slotsStack = array();
private $_parentContext = null;
private $_globalContext = null;
}
// emulate property_exists() function, this is slow but much better than
// isset(), use next release of PHP5 as soon as available !
if (!function_exists('property_exists')){
function property_exists($o, $property)
{
return array_key_exists($property, get_object_vars($o));
}
}
/**
* Resolve TALES path starting from the first path element.
*
* The TALES path : object/method1/10/method2
* will call : phptal_path($ctx->object, 'method1/10/method2')
*
* The nothrow param is used by phptal_exists() and prevent this function to
* throw an exception when a part of the path cannot be resolved, null is
* returned instead.
*/
function phptal_path($base, $path, $nothrow=false)
{//{{{
$parts = explode('/', $path);
$current = true;
if ($base === null)
{
if ($nothrow) return null;
throw new PHPTAL_Exception("Trying to read property '$path' from NULL");
}
while (($current = array_shift($parts)) !== null){
// object handling
if (is_object($base)){
// look for method
if (method_exists($base, $current)){
$base = $base->$current();
continue;
}
// look for variable
if (property_exists($base, $current)){
$base = $base->$current;
continue;
}
if ($base instanceof ArrayAccess && $base->offsetExists($current))
{
$base = $base->offsetGet($current);
continue;
}
if ($base instanceof Countable && ($current === 'length' || $current === 'size'))
{
$base = count($base);
continue;
}
// look for isset (priority over __get)
if (method_exists($base,'__isset') && is_callable(array($base, '__isset')))
{
if ($base->__isset($current)){
$base = $base->$current;
continue;
}
}
// ask __get and discard if it returns null
else if (method_exists($base,'__get') && is_callable(array($base, '__get')))
{
$tmp = $base->$current;
if (NULL !== $tmp){
$base = $tmp;
continue;
}
}
// magic method call
if (method_exists($base, '__call')){
try
{
$base = $base->$current();
continue;
}
catch(BadMethodCallException $e){}
}
// emulate array behaviour
if (is_numeric($current) && method_exists($base, '__getAt')){
$base = $base->__getAt($current);
continue;
}
if ($nothrow)
return null;
$err = 'Unable to find part "%s" in path "%s" inside '.(is_object($base)?get_class($base):gettype($base));
$err = sprintf($err, $current, $path);
throw new PHPTAL_Exception($err);
}
// array handling
if (is_array($base)) {
// key or index
if (array_key_exists((string)$current, $base)){
$base = $base[$current];
continue;
}
// virtual methods provided by phptal
if ($current == 'length' || $current == 'size'){
$base = count($base);
continue;
}
if ($nothrow)
return null;
$err = 'Unable to find array key "%s" in path "%s"';
$err = sprintf($err, $current, $path);
throw new PHPTAL_Exception($err);
}
// string handling
if (is_string($base)) {
// virtual methods provided by phptal
if ($current == 'length' || $current == 'size'){
$base = strlen($base);
continue;
}
// access char at index
if (is_numeric($current)){
$base = $base[$current];
continue;
}
}
// if this point is reached, then the part cannot be resolved
if ($nothrow)
return null;
$err = 'Unable to find part "%s" in path "%s" with base "%s"';
$err = sprintf($err, $current, $path, is_scalar($base)?"$base":(is_object($base)?get_class($base):gettype($base)));
throw new PHPTAL_Exception($err);
}
return $base;
}
function phptal_true($ctx, $path)
{
$ctx->noThrow(true);
$res = phptal_path($ctx, $path, true);
$ctx->noThrow(false);
return !!$res;
}
/**
* Returns true if $path can be fully resolved in $ctx context.
*/
function phptal_exists($ctx, $path)
{
// special note: this method may requires to be extended to a full
// phptal_path() sibling to avoid calling latest path part if it is a
// method or a function...
$ctx->noThrow(true);
$res = phptal_path($ctx, $path, true);
$ctx->noThrow(false);
return $res !== NULL;
}
function phptal_isempty($var)
{
return $var === null || $var === false || $var === ''
|| ((is_array($var) || $var instanceof Countable) && count($var)===0);
}
function phptal_escape($var, $ent, $encoding)
{
if (is_string($var)) {
return htmlspecialchars($var, $ent, $encoding);
}
elseif (is_object($var)) {
if ($var instanceof SimpleXMLElement) return $var->asXML();
return htmlspecialchars($var->__toString(), $ent, $encoding);
}
elseif (is_bool($var)){
return (int)$var;
}
return $var;
}
?>

View file

@ -1,237 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
// From http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4
//
// Order of Operations
//
// When there is only one TAL statement per element, the order in which
// they are executed is simple. Starting with the root element, each
// element's statements are executed, then each of its child elements is
// visited, in order, to do the same.
//
// Any combination of statements may appear on the same elements, except
// that the content and replace statements may not appear together.
//
// When an element has multiple statements, they are executed in this
// order:
//
// * define
// * condition
// * repeat
// * content or replace
// * attributes
// * omit-tag
//
// Since the on-error statement is only invoked when an error occurs, it
// does not appear in the list.
//
// The reasoning behind this ordering goes like this: You often want to set
// up variables for use in other statements, so define comes first. The
// very next thing to do is decide whether this element will be included at
// all, so condition is next; since the condition may depend on variables
// you just set, it comes after define. It is valuable be able to replace
// various parts of an element with different values on each iteration of a
// repeat, so repeat is next. It makes no sense to replace attributes and
// then throw them away, so attributes is last. The remaining statements
// clash, because they each replace or edit the statement element.
//
// If you want to override this ordering, you must do so by enclosing the
// element in another element, possibly div or span, and placing some of
// the statements on this new element.
//
require_once PHPTAL_DIR.'PHPTAL/Namespace.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace/TAL.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace/METAL.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace/I18N.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace/PHPTAL.php';
/**
* PHPTAL constants.
*
* This is a pseudo singleton class, a user may decide to provide
* his own singleton instance which will then be used by PHPTAL.
*
* This behaviour is mainly usefull to remove builtin namespaces
* and provide custom ones.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Defs
{
public static function getInstance()
{
if (self::$_instance == null){
self::$_instance = new PHPTAL_Dom_Defs();
}
return self::$_instance;
}
public static function setInstance(PHPTAL_Dom_Defs $instance)
{
self::$_instance = $instance;
}
public function __construct()
{
$this->_dictionary = array();
$this->_namespaces = array();
$this->_xmlns = array();
}
public function isEmptyTag($tagName)
{
return in_array(strtolower($tagName), self::$XHTML_EMPTY_TAGS);
}
public function xmlnsToLocalName($xmlns)
{
return $this->_xmlns[$xmlns];
}
/**
* Returns true if the attribute is an xhtml boolean attribute.
*
* @return bool
*/
public function isBooleanAttribute($att)
{
return in_array($att, self::$XHTML_BOOLEAN_ATTRIBUTES);
}
/**
* Returns true if the attribute is in the phptal dictionnary.
*
* @return bool
*/
public function isPhpTalAttribute($att)
{
return array_key_exists(strtolower($att), $this->_dictionary);
}
/**
* Returns true if the attribute is a valid phptal attribute or an unknown
* attribute.
*
* Examples of valid attributes: tal:content, metal:use-slot
* Examples of invalid attributes: tal:unknown, metal:content
*
* @return bool
*/
public function isValidAttribute($att)
{
if (preg_match('/^(.*):(.*)$/', $att, $m)) {
list (,$ns,$sub) = $m;
if (array_key_exists(strtolower($ns), $this->_namespaces)
&& !$this->isPhpTalAttribute($att)) {
return false;
}
}
return true;
}
/**
* Returns true if the attribute is a phptal handled xml namespace
* declaration.
*
* Examples of handled xmlns: xmlns:tal, xmlns:metal
*
* @return bool
*/
public function isHandledXmlNs($att, $value)
{
$att = strtolower($att);
return substr($att, 0, 6) == 'xmlns:'
&& array_key_exists($value, $this->_xmlns);
}
public function getNamespaceAttribute($attName)
{
return $this->_dictionary[strtolower($attName)];
}
/**
* Register a PHPTAL_Namespace and its attribute into PHPTAL.
*/
public function registerNamespace(PHPTAL_Namespace $ns)
{
$nsname = strtolower($ns->name);
$this->_namespaces[$nsname] = $ns;
$this->_xmlns[$ns->xmlns] = $nsname;
foreach ($ns->getAttributes() as $name => $attribute){
$key = $nsname.':'.strtolower($name);
$this->_dictionary[$key] = $attribute;
}
}
private static $_instance = null;
private $_dictionary;
private $_namespaces;
private $_xmlns;
/**
* This array contains XHTML tags that must be echoed in a &lt;tag/&gt; form
* instead of the &lt;tag&gt;&lt;/tag&gt; form.
*
* In fact, some browsers does not support the later form so PHPTAL
* ensure these tags are correctly echoed.
*/
private static $XHTML_EMPTY_TAGS = array(
'area',
'base',
'basefont',
'br',
'col',
'frame',
'hr',
'img',
'input',
'isindex',
'link',
'meta',
'param',
);
/**
* This array contains XHTML boolean attributes, their value is self
* contained (ie: they are present or not).
*/
private static $XHTML_BOOLEAN_ATTRIBUTES = array(
'checked',
'compact',
'declare',
'defer',
'disabled',
'ismap',
'multiple',
'noresize',
'noshade',
'nowrap',
'readonly',
'selected',
);
}
?>

View file

@ -1,254 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Php/CodeWriter.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* Document node abstract class.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
abstract class PHPTAL_Dom_Node
{
public function __construct()
{
}
public function setSource($file, $line)
{
$this->_file = $file;
$this->_line = $line;
}
public function getSourceLine()
{
return $this->_line;
}
public function getSourceFile()
{
return $this->_file;
}
private $_file;
private $_line;
}
/**
* Node container.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Tree extends PHPTAL_Dom_Node
{
public function __construct()
{
parent::__construct();
$this->_children = array();
}
public function addChild(PHPTAL_Dom_Node $node)
{
array_push($this->_children, $node);
}
public function &getChildren()
{
return $this->_children;
}
public function clearChildren()
{
$this->_children = array();
}
protected $_children;
}
/**
* Document Tag representation.
*
* This is the main class used by PHPTAL because TAL is a Template Attribute
* Language, other Node kinds are (usefull) toys.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Element extends PHPTAL_Dom_Tree
{
private $name;
public $attributes = array();
public function __construct($name, $attributes)
{
if (!preg_match('/^[a-z_:][a-z0-9._:\x80-\xff-]*$/i',$name)) throw new PHPTAL_Exception("Invalid element name '$name'");
parent::__construct();
$this->name = $name;
$this->attributes = $attributes;
}
public function setXmlnsState(PHPTAL_Dom_XmlnsState $state)
{
$this->_xmlns = $state;
$this->xmlns = $state;
}
public function getName()
{
return $this->name;
}
public function getXmlnsState()
{
return $this->_xmlns;
}
/** Returns true if the element contains specified PHPTAL attribute. */
public function hasAttribute($name)
{
$ns = $this->getNodePrefix();
foreach ($this->attributes as $key=>$value){
if ($this->_xmlns->unAliasAttribute($key) == $name){
return true;
}
if ($ns && $this->_xmlns->unAliasAttribute("$ns:$key") == $name){
return true;
}
}
return false;
}
/** Returns the value of specified PHPTAL attribute. */
public function getAttribute($name)
{
$ns = $this->getNodePrefix();
foreach ($this->attributes as $key=>$value){
if ($this->_xmlns->unAliasAttribute($key) == $name){
return $value;
}
if ($ns && $this->_xmlns->unAliasAttribute("$ns:$key") == $name){
return $value;
}
}
return false;
}
/**
* Returns true if this element or one of its PHPTAL attributes has some
* content to print (an empty text node child does not count).
*/
public function hasRealContent()
{
if (count($this->_children) == 0)
return false;
if (count($this->_children) == 1){
$child = $this->_children[0];
if ($child instanceOf PHPTAL_Dom_Text && $child->getValue() == ''){
return false;
}
}
return true;
}
private function getNodePrefix()
{
$result = false;
if (preg_match('/^(.*?):block$/', $this->name, $m)){
list(,$result) = $m;
}
return $result;
}
private function hasContent()
{
return count($this->_children) > 0;
}
/**
* XMLNS aliases propagated from parent nodes and defined by this node
* attributes.
*/
protected $_xmlns;
}
/**
* @package phptal.dom
*/
class PHPTAL_Dom_ValueNode extends PHPTAL_Dom_Node
{
public function __construct($data)
{
$this->_value = $data;
}
public function getValue()
{
return $this->_value;
}
private $_value;
}
/**
* Document text data representation.
* @package phptal.dom
*/
class PHPTAL_Dom_Text extends PHPTAL_Dom_ValueNode{}
/**
* Preprocessor, etc... representation.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Specific extends PHPTAL_Dom_ValueNode {}
/**
* Comment nodes.
* @package phptal.dom
*/
class PHPTAL_Dom_Comment extends PHPTAL_Dom_ValueNode {}
/**
* Document doctype representation.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Doctype extends PHPTAL_Dom_ValueNode {}
/**
* XML declaration node.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_XmlDeclaration extends PHPTAL_Dom_ValueNode {}
?>

View file

@ -1,154 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Dom/Node.php';
require_once PHPTAL_DIR.'PHPTAL/Dom/XmlParser.php';
require_once PHPTAL_DIR.'PHPTAL/Dom/XmlnsState.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Tales.php';
/**
* Template parser.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_Parser extends PHPTAL_XmlParser
{
const ERR_DOCUMENT_END_STACK_NOT_EMPTY = "Not all elements were closed before end of the document (element stack not empty)";
const ERR_UNSUPPORTED_ATTRIBUTE = "Unsupported attribute '%s'";
const ERR_ELEMENT_CLOSE_MISMATCH = "Tag closure mismatch, expected '%s' but was '%s'";
public function __construct($input_encoding = 'UTF-8')
{
parent::__construct($input_encoding);
$this->_xmlns = new PHPTAL_Dom_XmlnsState();
}
public function getXmlnsState()
{
return $this->_xmlns;
}
public function stripComments($b)
{
$this->_stripComments = $b;
}
public function parseString($src, $filename = '<string>')
{
parent::parseString($src, $filename);
return $this->_tree;
}
public function parseFile($path)
{
parent::parseFile($path);
return $this->_tree;
}
// ~~~~~ XmlParser implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public function onDocumentStart()
{
$this->_tree = new PHPTAL_Dom_Tree();
$this->_tree->setSource($this->getSourceFile(), $this->getLineNumber());
$this->_stack = array();
$this->_current = $this->_tree;
}
public function onDocumentEnd()
{
if (count($this->_stack) > 0) {
$this->raiseError(self::ERR_DOCUMENT_END_STACK_NOT_EMPTY);
}
}
public function onDocType($doctype)
{
$this->pushNode(new PHPTAL_Dom_DocType($doctype));
}
public function onXmlDecl($decl)
{
$this->pushNode(new PHPTAL_Dom_XmlDeclaration($decl));
}
public function onComment($data)
{
if ($this->_stripComments)
return;
$this->pushNode(new PHPTAL_Dom_Comment($data));
}
public function onSpecific($data)
{
$this->pushNode(new PHPTAL_Dom_Specific($data));
}
public function onElementStart($name, $attributes)
{
$this->_xmlns = PHPTAL_Dom_XmlnsState::newElement($this->_xmlns, $attributes);
foreach ($attributes as $key=>$value) {
if (!$this->_xmlns->isValidAttribute($key)) {
$this->raiseError(self::ERR_UNSUPPORTED_ATTRIBUTE, $key);
}
}
$node = new PHPTAL_Dom_Element($name, $attributes);
$node->setXmlnsState($this->getXmlnsState());
$this->pushNode($node);
array_push($this->_stack, $this->_current);
$this->_current = $node;
}
public function onElementData($data)
{
$this->pushNode(new PHPTAL_Dom_Text($data));
}
public function onElementClose($name)
{
if (!$this->_current instanceof PHPTAL_Dom_Element) $this->raiseError("Found closing tag for '$name' where there are no open tags");
if ($this->_current->getName() != $name) {
$this->raiseError(self::ERR_ELEMENT_CLOSE_MISMATCH, $this->_current->getName(), $name);
}
$this->_current = array_pop($this->_stack);
if ($this->_current instanceOf PHPTAL_Dom_Element)
$this->_xmlns = $this->_current->getXmlnsState();
}
private function pushNode(PHPTAL_Dom_Node $node)
{
$node->setSource($this->getSourceFile(), $this->getLineNumber());
$this->_current->addChild($node);
}
private $_tree; /* PHPTAL_Dom_Parser_NodeTree */
private $_stack; /* array<PHPTAL_Dom_Parser_Node> */
private $_current; /* PHPTAL_Dom_Parser_Node */
private $_xmlns; /* PHPTAL_Dom_Parser_XmlnsState */
private $_stripComments = false;
}
?>

View file

@ -1,386 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* Simple sax like xml parser for PHPTAL.
*
* Because PHP Xml parser libraries tends to fail giving a real xml document
* representation (at the time this file was created, it was impossible to
* retrieve doctypes, xml declaration, problem with comments and CDATA) this
* parser was created and can be manipulated to accept some user errors
* like < and < in attribute values or inside text nodes.
*
* @package phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
* @see PHPTAL_Dom_Parser
*/
abstract class PHPTAL_XmlParser
{
// available parser states
const ST_ROOT = 0;
const ST_TEXT = 1;
const ST_LT = 2;
const ST_TAG_NAME = 3;
const ST_TAG_CLOSE = 4;
const ST_TAG_SINGLE = 5;
const ST_TAG_ATTRIBUTES = 6;
const ST_CDATA = 7;
const ST_COMMENT = 8;
const ST_DOCTYPE = 9;
const ST_XMLDEC = 15;
const ST_PREPROC = 10;
const ST_ATTR_KEY = 11;
const ST_ATTR_EQ = 12;
const ST_ATTR_QUOTE = 13;
const ST_ATTR_VALUE = 14;
// exceptions error messages
const ERR_CHARS_BEFORE_DOC_START =
"Characters found before the begining of the document!";
const ERR_EXPECT_VALUE_QUOTE =
"Unexpected '%s' character, expecting attribute single or double quote";
const BOM_STR = "\xef\xbb\xbf";
static $state_names = array(
self::ST_ROOT => 'root node',
self::ST_TEXT => 'text',
self::ST_LT => 'start of tag',
self::ST_TAG_NAME => 'tag name',
self::ST_TAG_CLOSE => 'closing tag',
self::ST_TAG_SINGLE => 'self-closing tag',
self::ST_TAG_ATTRIBUTES => 'tag',
self::ST_CDATA => 'CDATA',
self::ST_COMMENT => 'comment',
self::ST_DOCTYPE => 'doctype',
self::ST_XMLDEC => 'XML declaration',
self::ST_PREPROC => 'preprocessor directive',
self::ST_ATTR_KEY => 'attribute name',
self::ST_ATTR_EQ => 'attribute value',
self::ST_ATTR_QUOTE => 'quoted attribute value',
self::ST_ATTR_VALUE => 'unquoted attribute value',
);
public function __construct()
{
$this->_file = "<string>";
}
public function parseFile($src)
{
if (!file_exists($src)) {
throw new PHPTAL_Exception("file $src not found");
}
$this->parseString(file_get_contents($src), $src);
}
public function parseString($src, $filename = '<string>')
{
$this->_file = $filename;
// remove BOM (utf8 byte order mark)...
if (substr($src,0,3) == self::BOM_STR){
$src = substr($src, 3);
}
$this->_line = 1;
$state = self::ST_ROOT;
$mark = 0;
$len = strlen($src);
$quoteStyle = '"';
$tagname = "";
$attribute = "";
$attributes = array();
$customDoctype = false;
$this->onDocumentStart();
for ($i=0; $i<$len; $i++) {
$c = $src[$i];
if ($c == "\n") $this->_line++;
switch ($state) {
case self::ST_ROOT:
if ($c == '<') {
$mark = $i; // mark tag start
$state = self::ST_LT;
}
else if (!self::isWhiteChar($c)) {
$this->raiseError(self::ERR_CHARS_BEFORE_DOC_START);
}
break;
case self::ST_TEXT:
if ($c == '<') {
if ($mark != $i) {
$this->onElementData(substr($src, $mark, $i-$mark));
}
$mark = $i;
$state = self::ST_LT;
}
break;
case self::ST_LT:
if ($c == '/') {
$mark = $i+1;
$state = self::ST_TAG_CLOSE;
}
else if ($c == '?' and substr($src, $i, 4) == '?xml') {
$state = self::ST_XMLDEC;
}
else if ($c == '?') {
$state = self::ST_PREPROC;
}
else if ($c == '!' and substr($src, $i, 3) == '!--') {
$state = self::ST_COMMENT;
}
else if ($c == '!' and substr($src, $i, 8) == '![CDATA[') {
$state = self::ST_CDATA;
}
else if ($c == '!' and substr($src, $i, 8) == '!DOCTYPE') {
$state = self::ST_DOCTYPE;
}
else if (!self::isAlpha($c)) {
$state = self::ST_TEXT;
}
else {
$mark = $i; // mark node name start
$attributes = array();
$attribute = "";
$state = self::ST_TAG_NAME;
}
break;
case self::ST_TAG_NAME:
if (self::isWhiteChar($c)) {
$tagname = substr($src, $mark, $i-$mark);
$state = self::ST_TAG_ATTRIBUTES;
}
else if ($c == '/') {
$tagname = substr($src, $mark, $i-$mark);
$state = self::ST_TAG_SINGLE;
}
else if ($c == '>') {
$tagname = substr($src, $mark, $i-$mark);
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
$this->onElementStart($tagname, $attributes);
}
break;
case self::ST_TAG_CLOSE:
if ($c == '>') {
$tagname = rtrim(substr($src, $mark, $i-$mark));
$this->onElementClose($tagname);
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_TAG_SINGLE:
if ($c != '>') {
// error
}
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
$this->onElementStart($tagname, $attributes);
$this->onElementClose($tagname);
break;
case self::ST_TAG_ATTRIBUTES:
if ($c == '>') {
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
$this->onElementStart($tagname, $attributes);
}
else if ($c == '/') {
$state = self::ST_TAG_SINGLE;
}
else if (self::isWhiteChar($c)) {
}
else {
$mark = $i; // mark attribute key start
$state = self::ST_ATTR_KEY;
}
break;
case self::ST_COMMENT:
if ($c == '>' and substr($src, $i-2, 2) == '--') {
$this->onComment(substr($src, $mark, $i-$mark+1));
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_CDATA:
if ($c == '>' and substr($src, $i-2, 2) == ']]') {
$this->onSpecific(substr($src, $mark, $i-$mark+1));
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_XMLDEC:
if ($c == '?' && substr($src, $i, 2) == '?>') {
$this->onXmlDecl(substr($src, $mark, $i-$mark+2));
$i++; // skip '>'
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_DOCTYPE:
if ($c == '[') {
$customDoctype = true;
}
else if ($customDoctype && $c == '>' && substr($src, $i-1, 2) == ']>'){
$customDoctype = false;
$this->onDocType(substr($src, $mark, $i-$mark+1));
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
else if (!$customDoctype && $c == '>') {
$customDoctype = false;
$this->onDocType(substr($src, $mark, $i-$mark+1));
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_PREPROC:
if ($c == '>' and $src[$i-1] == '?') {
$this->onSpecific(substr($src, $mark, $i-$mark+1));
$mark = $i+1; // mark text start
$state = self::ST_TEXT;
}
break;
case self::ST_ATTR_KEY:
if (self::isWhiteChar($c)) {
$attribute = substr($src, $mark, $i-$mark);
$state = self::ST_ATTR_EQ;
}
else if ($c == '=') {
$attribute = substr($src, $mark, $i-$mark);
$state = self::ST_ATTR_VALUE;
}
break;
case self::ST_ATTR_EQ:
if ($c == '=') {
$state = self::ST_ATTR_VALUE;
}
break;
case self::ST_ATTR_VALUE:
if (self::isWhiteChar($c)){
}
else if ($c == '"' or $c == '\'') {
$quoteStyle = $c;
$state = self::ST_ATTR_QUOTE;
$mark = $i+1; // mark attribute real value start
}
else {
$err = self::ERR_EXPECT_VALUE_QUOTE;
$err = sprintf($err, $c);
$this->raiseError($err);
}
break;
case self::ST_ATTR_QUOTE:
if ($c == $quoteStyle) {
if (isset($attributes[$attribute])) $this->raiseError("Attribute '$attribute' on '$tagname' is defined more than once");
$attributes[$attribute] = substr($src, $mark, $i-$mark);
$state = self::ST_TAG_ATTRIBUTES;
}
break;
}
}
if ($state == self::ST_TEXT) // allows text past root node, which is in violation of XML spec
{
if ($i > $mark)
{
$text = substr($src, $mark, $i-$mark);
//if (!ctype_space($text)) $this->onElementData($text);
if (!ctype_space($text)) $this->raiseError("Characters found after end of the root element");
}
}
else
{
throw new PHPTAL_Exception("Finished document in unexpected state: ".self::$state_names[$state]." is not finished");
}
$this->onDocumentEnd();
}
public function getSourceFile()
{
return $this->_file;
}
public function getLineNumber()
{
return $this->_line;
}
public static function isWhiteChar($c)
{
return strpos(" \t\n\r\0", $c) !== false;
}
public static function isAlpha($c)
{
$char = strtolower($c);
return ($char >= 'a' && $char <= 'z');
}
public abstract function onDocType($doctype);
public abstract function onXmlDecl($decl);
public abstract function onSpecific($data);
public abstract function onComment($data);
public abstract function onElementStart($name, $attributes);
public abstract function onElementClose($name);
public abstract function onElementData($data);
public abstract function onDocumentStart();
public abstract function onDocumentEnd();
protected function raiseError($errFmt)
{
$args = func_get_args();
$errStr = call_user_func_array('sprintf', $args);
$str = "%s error: %s in %s:%d";
$str = sprintf($str, get_class($this), $errStr, $this->_file, $this->_line);
throw new PHPTAL_Exception($str);
}
private $_file;
private $_line;
private $_source;
}
?>

View file

@ -1,98 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* Stores XMLNS aliases fluctuation in the xml flow.
*
* This class is used to bind a PHPTAL namespace to an alias, for example using
* xmlns:t="http://xml.zope.org/namespaces/tal" and later use t:repeat instead
* of tal:repeat.
*
* @package phptal.dom
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Dom_XmlnsState
{
/** Create a new XMLNS state inheriting provided aliases. */
public function __construct($aliases = array())
{
assert(is_array($aliases));
$this->_aliases = $aliases;
}
/** Returns true if $attName is a valid attribute name, false otherwise. */
public function isValidAttribute($attName)
{
$unaliased = $this->unAliasAttribute($attName);
return PHPTAL_Dom_Defs::getInstance()->isValidAttribute($unaliased);
}
/** Returns true if $attName is a PHPTAL attribute, false otherwise. */
public function isPhpTalAttribute($attName)
{
$unaliased = $this->unAliasAttribute($attName);
return PHPTAL_Dom_Defs::getInstance()->isPhpTalAttribute($unaliased);
}
/** Returns the unaliased name of specified attribute. */
public function unAliasAttribute($attName)
{
if (count($this->_aliases) == 0)
return $attName;
$result = $attName;
foreach ($this->_aliases as $alias => $real){
$result = str_replace("$alias:", "$real:", $result);
}
return $result;
}
/**
* Returns a new XmlnsState inheriting of $currentState if $nodeAttributes contains
* xmlns attributes, returns $currentState otherwise.
*
* This method is used by the PHPTAL parser to keep track of xmlns fluctuation for
* each encountered node.
*/
public static function newElement(PHPTAL_Dom_XmlnsState $currentState, $nodeAttributes)
{
$aliases = array();
foreach ($nodeAttributes as $att => $value){
if (PHPTAL_Dom_Defs::getInstance()->isHandledXmlNs($att, $value)){
preg_match('/^xmlns:(.*?)$/', $att, $m);
list(,$alias) = $m;
$aliases[$alias] = PHPTAL_Dom_Defs::getInstance()->xmlnsToLocalName($value);
}
}
if (count($aliases) > 0){
// inherit aliases with maybe an overwrite
$aliases = array_merge($currentState->_aliases, $aliases);
return new PHPTAL_Dom_XmlnsState($aliases);
}
return $currentState;
}
private $_aliases;
}
?>

View file

@ -1,65 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* @package phptal
*/
class PHPTAL_Exception extends Exception
{
public $srcFile;
public $srcLine;
public function __construct($msg, $srcFile=false, $srcLine=false)
{
parent::__construct($msg);
$this->srcFile = $srcFile;
$this->srcLine = $srcLine;
}
public function __toString()
{
if (empty($this->srcFile)){
return parent::__toString();
}
$res = sprintf('From %s around line %d'."\n", $this->srcFile, $this->srcLine);
$res .= parent::__toString();
return $res;
}
public static function formatted($format /*, ...*/)
{
$args = func_get_args();
$msg = call_user_func('sprintf', $args);
return new PHPTAL_Exception($format);
}
/**
* set new source line/file only if one hasn't been set previously
*/
public function hintSrcPosition($srcFile, $srcLine)
{
if ($srcFile && $this->srcFile === false) $this->srcFile = $srcFile;
if ($srcLine && $this->srcLine === false) $this->srcLine = $srcLine;
}
}
?>

View file

@ -1,64 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Source.php';
require_once PHPTAL_DIR.'PHPTAL/SourceResolver.php';
/**
* @package phptal
*/
class PHPTAL_FileSource implements PHPTAL_Source
{
public function __construct($path)
{
$this->_path = realpath($path);
if ($this->_path === false) throw new PHPTAL_Exception("Unable to normalize path '$path'");
}
public function getRealPath()
{
return $this->_path;
}
public function getLastModifiedTime()
{
return filemtime($this->_path);
}
public function getData()
{
return file_get_contents($this->_path);
}
private $_path;
}
/**
* @package phptal
*/
class PHPTAL_FileSourceResolver implements PHPTAL_SourceResolver
{
public function __construct($repositories)
{
$this->_repositories = $repositories;
}
public function resolve($path)
{
foreach ($this->_repositories as $repository){
$file = $repository . DIRECTORY_SEPARATOR . $path;
if (file_exists($file)){
return new PHPTAL_FileSource($file);
}
}
if (file_exists($path)){
return new PHPTAL_FileSource($path);
}
return null;
}
private $_repositories;
}
?>

View file

@ -1,31 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* @package phptal
*/
interface PHPTAL_Filter
{
public function filter($str);
}
?>

View file

@ -1,143 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/TranslationService.php';
/**
* PHPTAL_TranslationService gettext implementation.
*
* Because gettext is the most common translation library in use, this
* implementation is shipped with the PHPTAL library.
*
* Please refer to the PHPTAL documentation for usage examples.
*
* @package phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_GetTextTranslator implements PHPTAL_TranslationService
{
public function __construct()
{
if (!function_exists('gettext')) throw new PHPTAL_Exception("Gettext not installed");
$this->useDomain("messages"); // PHP bug #21965
}
private $_vars = array();
private $_currentDomain;
private $_encoding = 'UTF-8';
private $_canonicalize = false;
public function setEncoding($enc)
{
$this->_encoding = $enc;
}
/**
* if true, all non-ASCII characters in keys will be converted to C<xxx> form. This impacts performance.
* by default keys will be passed to gettext unmodified.
*/
public function setCanonicalize($bool)
{
$this->_canonicalize = $bool;
}
public function setLanguage()
{
$langs = func_get_args();
foreach ($langs as $langCode){
putenv("LANG=$langCode");
putenv("LC_ALL=$langCode");
putenv("LANGUAGE=$langCode");
if (setlocale(LC_ALL, $langCode)) {
return;
}
}
$err = sprintf('Language(s) code(s) "%s" not supported by your system', join(',', $langs));
throw new PHPTAL_Exception($err);
}
/**
* encoding must be set before calling addDomain
*/
public function addDomain($domain, $path='./locale/')
{
bindtextdomain($domain, $path);
if ($this->_encoding){
bind_textdomain_codeset($domain, $this->_encoding);
}
$this->useDomain($domain);
}
public function useDomain($domain)
{
$old = $this->_currentDomain;
$this->_currentDomain = $domain;
textdomain($domain);
return $old;
}
public function setVar($key, $value)
{
$this->_vars[$key] = $value;
}
public function translate($key, $htmlencode=true)
{
if ($this->_canonicalize) $key = self::_canonicalizeKey($key);
$value = gettext($key);
if ($htmlencode){
$value = @htmlspecialchars($value, ENT_QUOTES, $this->_encoding); // silence unsupported encoding error for ISO-8859-x, which doesn't matter.
}
while (preg_match('/\${(.*?)\}/sm', $value, $m)){
list($src,$var) = $m;
if (!array_key_exists($var, $this->_vars)){
$err = sprintf('Interpolation error, var "%s" not set', $var);
throw new PHPTAL_Exception($err);
}
$value = str_replace($src, $this->_vars[$var], $value);
}
return $value;
}
static function _canonicalizeKey($key_)
{
$result = "";
$key_ = trim($key_);
$key_ = str_replace("\n", "", $key_);
$key_ = str_replace("\r", "", $key_);
for ($i = 0; $i<strlen($key_); $i++){
$c = $key_[$i];
$o = ord($c);
if ($o < 5 || $o > 127){
$result .= 'C<'.$o.'>';
}
else {
$result .= $c;
}
}
return $result;
}
}

View file

@ -1,163 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* @package phptal
*/
abstract class PHPTAL_NamespaceAttribute
{
/**
* @param $name string The attribute name
* @param $priority int Attribute execution priority
*/
public function __construct($name, $priority)
{
$this->_name = $name;
$this->_priority = $priority;
}
/**
* @return string
*/
public function getName()
{
return $this->_name;
}
public function getFullName()
{
return $this->_namespace->getName() . ':' . $this->_name;
}
public function getPriority(){ return $this->_priority; }
public function getNamespace(){ return $this->_namespace; }
public function setNamespace(PHPTAL_Namespace $ns){ $this->_namespace = $ns; }
public function createAttributeHandler(PHPTAL_Php_Element $tag, $expression)
{
return $this->_namespace->createAttributeHandler($this, $tag, $expression);
}
private $_name; /* Attribute name without the namespace: prefix */
private $_priority; /* [0 - 1000] */
private $_namespace; /* PHPTAL_Namespace */
}
/**
* @package phptal
*/
class PHPTAL_NamespaceAttributeSurround extends PHPTAL_NamespaceAttribute
{
public function __construct($name, $priority)
{
parent::__construct($name, $priority);
}
}
/**
* @package phptal
*/
class PHPTAL_NamespaceAttributeReplace extends PHPTAL_NamespaceAttribute
{
public function __construct($name, $priority)
{
parent::__construct($name, $priority);
}
}
/**
* @package phptal
*/
class PHPTAL_NamespaceAttributeContent extends PHPTAL_NamespaceAttribute
{
public function __construct($name, $priority)
{
parent::__construct($name, $priority);
}
}
/**
* @package phptal
*/
abstract class PHPTAL_Namespace
{
public $xmlns;
public $name;
public function __construct($name, $xmlns)
{
$this->_attributes = array();
$this->name = $name;
$this->xmlns = $xmlns;
}
public function getName()
{
return $this->name;
}
public function hasAttribute($attributeName)
{
return array_key_exists(strtolower($attributeName), $this->_attributes);
}
public function getAttribute($attributeName)
{
return $this->_attributes[strtolower($attributeName)];
}
public function addAttribute(PHPTAL_NamespaceAttribute $attribute)
{
$attribute->setNamespace($this);
$this->_attributes[strtolower($attribute->getName())] = $attribute;
}
public function getAttributes()
{
return $this->_attributes;
}
abstract public function createAttributeHandler(PHPTAL_NamespaceAttribute $att, PHPTAL_Php_Element $tag, $expression);
protected $_attributes;
}
/**
* @package phptal
*/
class PHPTAL_BuiltinNamespace extends PHPTAL_Namespace
{
public function createAttributeHandler(PHPTAL_NamespaceAttribute $att, PHPTAL_Php_Element $tag, $expression)
{
$name = $att->getName();
$name = str_replace('-', '', $name);
$class = 'PHPTAL_Php_Attribute_'.$this->getName().'_'.$name;
$result = new $class();
$result->tag = $tag;
$result->name = strtoupper($att->getFullName());
$result->expression = $expression;
return $result;
}
}
?>

View file

@ -1,28 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/I18N/Translate.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/I18N/Name.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/I18N/Domain.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/I18N/Attributes.php';
/**
* @package phptal.namespace
*/
class PHPTAL_Namespace_I18N extends PHPTAL_BuiltinNamespace
{
public function __construct()
{
parent::__construct('i18n', 'http://xml.zope.org/namespaces/i18n');
$this->addAttribute(new PHPTAL_NamespaceAttributeContent('translate', 5));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('name', 5));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('attributes', 10));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('domain', 3));
}
}
PHPTAL_Dom_Defs::getInstance()->registerNamespace(new PHPTAL_Namespace_I18N());
?>

View file

@ -1,28 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/METAL/DefineMacro.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/METAL/UseMacro.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/METAL/DefineSlot.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/METAL/FillSlot.php';
/**
* @package phptal.namespace
*/
class PHPTAL_Namespace_METAL extends PHPTAL_BuiltinNamespace
{
public function __construct()
{
parent::__construct('metal', 'http://xml.zope.org/namespaces/metal');
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('define-macro', 1));
$this->addAttribute(new PHPTAL_NamespaceAttributeReplace('use-macro', 9));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('define-slot', 9));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('fill-slot', 9));
}
}
PHPTAL_Dom_Defs::getInstance()->registerNamespace(new PHPTAL_Namespace_METAL());
?>

View file

@ -1,28 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Namespace.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/PHPTAL/Tales.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/PHPTAL/Debug.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/PHPTAL/Id.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/PHPTAL/Cache.php';
/**
* @package phptal.namespace
*/
class PHPTAL_Namespace_PHPTAL extends PHPTAL_BuiltinNamespace
{
public function __construct()
{
parent::__construct('phptal', 'http://xml.zope.org/namespaces/phptal');
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('tales', -1));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('debug', -2));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('id', 7));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('cache', -3));
}
}
PHPTAL_Dom_Defs::getInstance()->registerNamespace(new PHPTAL_Namespace_PHPTAL());
?>

View file

@ -1,37 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Namespace.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Comment.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Replace.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Content.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Condition.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Attributes.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Repeat.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/Define.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/OnError.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute/TAL/OmitTag.php';
/**
* @package phptal.namespace
*/
class PHPTAL_Namespace_TAL extends PHPTAL_BuiltinNamespace
{
public function __construct()
{
parent::__construct('tal', 'http://xml.zope.org/namespaces/tal');
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('define', 4));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('condition', 6));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('repeat', 8));
$this->addAttribute(new PHPTAL_NamespaceAttributeContent('content', 11));
$this->addAttribute(new PHPTAL_NamespaceAttributeReplace('replace', 9));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('attributes', 9));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('omit-tag', 0));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('comment', 12));
$this->addAttribute(new PHPTAL_NamespaceAttributeSurround('on-error', 2));
}
}
PHPTAL_Dom_Defs::getInstance()->registerNamespace(new PHPTAL_Namespace_TAL());
?>

View file

@ -1,98 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Dom/Node.php';
/**
* Base class for all PHPTAL attributes.
*
* Attributes are first ordered by PHPTAL then called depending on their
* priority before and after the element printing.
*
* An attribute must implements start() and end().
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
abstract class PHPTAL_Php_Attribute
{
const ECHO_TEXT = 'text';
const ECHO_STRUCTURE = 'structure';
/** Attribute name (ie: 'tal:content'). */
public $name;
/** Attribute value specified by the element. */
public $expression;
/** Element using this attribute (xml node). */
public $tag;
/** Called before element printing. */
public abstract function start();
/** Called after element printing. */
public abstract function end();
/**
* Remove structure|text keyword from expression and stores it for later
* doEcho() usage.
*
* $expression = 'stucture my/path';
* $expression = $this->extractEchoType($expression);
*
* ...
*
* $this->doEcho($code);
*/
protected function extractEchoType($expression)
{
$echoType = self::ECHO_TEXT;
$expression = trim($expression);
if (preg_match('/^(text|structure)\s+(.*?)$/ism', $expression, $m)) {
list(, $echoType, $expression) = $m;
}
$this->_echoType = strtolower($echoType);
return trim($expression);
}
protected function doEcho($code)
{
if ($this->_echoType == self::ECHO_TEXT)
$this->tag->generator->doEcho($code);
else
$this->tag->generator->doEchoRaw($code);
}
protected function parseSetExpression($exp)
{
$exp = trim($exp);
// (dest) (value)
if (preg_match('/^([a-z0-9:\-_]+)\s+(.*?)$/i', $exp, $m)){
array_shift($m);
return $m;
}
// (dest)
return array($exp, null);
}
protected $_echoType = PHPTAL_Php_Attribute::ECHO_TEXT;
}
?>

View file

@ -1,107 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:attributes
//
// This attribute will allow us to translate attributes of HTML tags, such
// as the alt attribute in the img tag. The i18n:attributes attribute
// specifies a list of attributes to be translated with optional message
// IDs? for each; if multiple attribute names are given, they must be
// separated by semi-colons. Message IDs? used in this context must not
// include whitespace.
//
// Note that the value of the particular attributes come either from the
// HTML attribute value itself or from the data inserted by tal:attributes.
//
// If an attibute is to be both computed using tal:attributes and translated,
// the translation service is passed the result of the TALES expression for
// that attribute.
//
// An example:
//
// <img src="http://foo.com/logo" alt="Visit us"
// tal:attributes="alt here/greeting"
// i18n:attributes="alt"
// />
//
//
// In this example, let tal:attributes set the value of the alt attribute to
// the text "Stop by for a visit!". This text will be passed to the
// translation service, which uses the result of language negotiation to
// translate "Stop by for a visit!" into the requested language. The example
// text in the template, "Visit us", will simply be discarded.
//
// Another example, with explicit message IDs:
//
// <img src="../icons/uparrow.png" alt="Up"
// i18n:attributes="src up-arrow-icon; alt up-arrow-alttext"
// >
//
// Here, the message ID up-arrow-icon will be used to generate the link to
// an icon image file, and the message ID up-arrow-alttext will be used for
// the "alt" text.
//
/**
* @package phptal.php.attribute
*/
class PHPTAL_Php_Attribute_I18N_Attributes extends PHPTAL_Php_Attribute
{
public function start()
{
// split attributes to translate
$expressions = $this->tag->generator->splitExpression($this->expression);
// foreach attribute
foreach ($expressions as $exp){
list($attribute, $key) = $this->parseSetExpression($exp);
// if the translation key is specified
if ($key != null){
// we use it and replace the tag attribute with the result of
// the translation
$key = str_replace('\'', '\\\'', $key);
$this->tag->attributes[$attribute] = $this->_getTranslationCode("'$key'");
}
else if ($this->tag->isOverwrittenAttribute($attribute)){
$varn = $this->tag->getOverwrittenAttributeVarName($attribute);
$this->tag->attributes[$attribute] = $this->_getTranslationCode($varn);
}
// else if the attribute has a default value
else if ($this->tag->hasAttribute($attribute)){
// we use this default value as the translation key
$key = $this->tag->getAttribute($attribute);
$key = str_replace('\'', '\\\'', $key);
$this->tag->attributes[$attribute] = $this->_getTranslationCode("'$key'");
}
else {
// unable to translate the attribute
throw new PHPTAL_Exception("Unable to translate attribute $attribute");
}
}
}
public function end()
{
}
private function _getTranslationCode($key)
{
$code = '<?php ';
if (preg_match_all('/\$\{(.*?)\}/', $key, $m)){
array_shift($m);
$m = array_shift($m);
foreach ($m as $name){
$code .= "\n".'$_translator->setVar(\''.$name.'\','.phptal_tale($name).');'; // allow more complex TAL expressions
}
$code .= "\n";
}
// notice the false boolean which indicate that the html is escaped
// elsewhere looks like an hack doesn't it ? :)
$result = $this->tag->generator->escapeCode(sprintf('$_translator->translate(%s, false)', $key));
$code .= 'echo '.$result.'?>';
return $code;
}
}
?>

View file

@ -1,24 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:data
//
// Since TAL always returns strings, we need a way in ZPT to translate
// objects, the most obvious case being DateTime objects. The data attribute
// will allow us to specify such an object, and i18n:translate will provide
// us with a legal format string for that object. If data is used,
// i18n:translate must be used to give an explicit message ID, rather than
// relying on a message ID computed from the content.
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Data extends PHPTAL_Php_Attribute
{
public function start(){}
public function end(){}
}
?>

View file

@ -1,41 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:domain
//
// The i18n:domain attribute is used to specify the domain to be used to get
// the translation. If not specified, the translation services will use a
// default domain. The value of the attribute is used directly; it is not
// a TALES expression.
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Domain extends PHPTAL_Php_Attribute
{
public function start()
{
// ensure a domain stack exists or create it
$this->tag->generator->doIf('!isset($__i18n_domains)');
$this->tag->generator->pushCode('$__i18n_domains = array()');
$this->tag->generator->doEnd();
//\''.str_replace(array('\\',"'"),array('\\\\',"\\'"),$expression).'\'
$expression = $this->tag->generator->interpolateTalesVarsInString($this->expression);
// push current domain and use new domain
$code = '$__i18n_domains[] = $_translator->useDomain('.$expression.')';
$this->tag->generator->pushCode($code);
}
public function end()
{
// restore domain
$code = '$_translator->useDomain(array_pop($__i18n_domains))';
$this->tag->generator->pushCode($code);
}
}
?>

View file

@ -1,40 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:name
//
// Name the content of the current element for use in interpolation within
// translated content. This allows a replaceable component in content to be
// re-ordered by translation. For example:
//
// <span i18n:translate=''>
// <span tal:replace='here/name' i18n:name='name' /> was born in
// <span tal:replace='here/country_of_birth' i18n:name='country' />.
// </span>
//
// would cause this text to be passed to the translation service:
//
// "${name} was born in ${country}."
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Name extends PHPTAL_Php_Attribute
{
public function start()
{
$this->tag->generator->pushCode('ob_start()');
}
public function end()
{
$code = '$_translator->setVar(\'%s\', ob_get_contents())';
$code = sprintf($code, $this->expression);
$this->tag->generator->pushCode($code);
$this->tag->generator->pushCode('ob_end_clean()');
}
}
?>

View file

@ -1,38 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:source
//
// The i18n:source attribute specifies the language of the text to be
// translated. The default is "nothing", which means we don't provide
// this information to the translation services.
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Source extends PHPTAL_Php_Attribute
{
public function start()
{
// ensure that a sources stack exists or create it
$this->tag->generator->doIf('!isset($__i18n_sources)');
$this->tag->generator->pushCode('$__i18n_sources = array()');
$this->tag->generator->end();
// push current source and use new one
$code = '$__i18n_sources[] = $_translator->setSource(\'%s\')';
$code = sprintf($code, $this->expression);
$this->tag->generator->pushCode($code);
}
public function end()
{
// restore source
$code = '$_translator->setSource(array_pop($__i18n_sources))';
$this->tag->generator->pushCode($code);
}
}
?>

View file

@ -1,32 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// i18n:target
//
// The i18n:target attribute specifies the language of the translation we
// want to get. If the value is "default", the language negotiation services
// will be used to choose the destination language. If the value is
// "nothing", no translation will be performed; this can be used to suppress
// translation within a larger translated unit. Any other value must be a
// language code.
//
// The attribute value is a TALES expression; the result of evaluating the
// expression is the language code or one of the reserved values.
//
// Note that i18n:target is primarily used for hints to text extraction
// tools and translation teams. If you had some text that should only be
// translated to e.g. German, then it probably shouldn't be wrapped in an
// i18n:translate span.
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Target extends PHPTAL_Php_Attribute
{
public function start(){}
public function end(){}
}
?>

View file

@ -1,97 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// ZPTInternationalizationSupport
//
// i18n:translate
//
// This attribute is used to mark units of text for translation. If this
// attribute is specified with an empty string as the value, the message ID
// is computed from the content of the element bearing this attribute.
// Otherwise, the value of the element gives the message ID.
//
/**
* @package phptal.php.attribute.i18n
*/
class PHPTAL_Php_Attribute_I18N_Translate extends PHPTAL_Php_Attribute
{
public function start()
{
$escape = true;
if (preg_match('/^(text|structure)(?:\s+(.*)|\s*$)/',$this->expression,$m))
{
if ($m[1]=='structure') $escape=false;
$this->expression = isset($m[2])?$m[2]:'';
}
// if no expression is given, the content of the node is used as
// a translation key
if (strlen(trim($this->expression)) == 0){
$key = $this->_getTranslationKey($this->tag, !$escape);
$key = trim(preg_replace('/\s+/sm'.($this->tag->generator->getEncoding()=='UTF-8'?'u':''), ' ', $key));
$code = '\'' . str_replace('\'', '\\\'', $key) . '\'';
}
else {
$code = $this->tag->generator->evaluateExpression($this->expression);
}
$this->_prepareNames($this->tag);
$php = sprintf('echo $_translator->translate(%s,%s);', $code, $escape ? 'true':'false');
$this->tag->generator->pushCode($php);
}
public function end()
{
}
private function _getTranslationKey($tag, $preserve_tags)
{
$result = '';
foreach ($tag->children as $child){
if ($child instanceOf PHPTAL_Php_Text){
$result .= $child->node->getValue();
}
else if ($child instanceOf PHPTAL_Php_Element){
if ($child->hasAttribute('i18n:name')){
$value = $child->getAttribute('i18n:name');
$result .= '${' . $value . '}';
}
else {
if ($preserve_tags)
{
$result .= '<'.$child->name;
foreach($child->attributes as $k => $v)
{
$result .= ' '.$k.'="'.$v.'"';
}
$result .= '>'.$this->_getTranslationKey($child, $preserve_tags).'</'.$child->name.'>';
}
else
{
$result .= $this->_getTranslationKey($child, $preserve_tags);
}
}
}
}
return $result;
}
private function _prepareNames($tag)
{
foreach ($tag->children as $child){
if ($child instanceOf PHPTAL_Php_Element){
if ($child->hasAttribute('i18n:name')){
$child->generate();
}
else {
$this->_prepareNames($child);
}
}
}
}
}
?>

View file

@ -1,71 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// METAL Specification 1.0
//
// argument ::= Name
//
// Example:
//
// <p metal:define-macro="copyright">
// Copyright 2001, <em>Foobar</em> Inc.
// </p>
//
// PHPTAL:
//
// <?php function XXX_macro_copyright( $tpl ) { ? >
// <p>
// Copyright 2001, <em>Foobar</em> Inc.
// </p>
// <?php } ? >
//
/**
* @package phptal.php.attribute.metal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_METAL_DefineMacro extends PHPTAL_Php_Attribute
{
public function start()
{
$macroname = strtr(trim($this->expression),'-','_');
if (!preg_match('/^[a-z0-9_]+$/i', $macroname)){
throw new PHPTAL_Exception('Bad macro name "'.$macroname.'"', $this->tag->getSourceFile(), $this->tag->getSourceLine());
}
$this->tag->generator->doFunction($macroname, '$tpl, $ctx');
$this->tag->generator->doXmlDeclaration();
$this->tag->generator->doDoctype();
$this->tag->generator->doSetVar('$tpl', 'clone $tpl');
$this->tag->generator->doSetVar('$ctx', '$tpl->getContext()');
$this->tag->generator->doSetVar('$glb', '$tpl->getGlobalContext()');
$this->tag->generator->doSetVar('$_translator', '$tpl->getTranslator()');
}
public function end()
{
$this->tag->generator->doEnd();
}
}

View file

@ -1,75 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// METAL Specification 1.0
//
// argument ::= Name
//
// Example:
//
// <table metal:define-macro="sidebar">
// <tr><th>Links</th></tr>
// <tr><td metal:define-slot="links">
// <a href="/">A Link</a>
// </td></tr>
// </table>
//
// PHPTAL: (access to slots may be renamed)
//
// <?php function XXXX_macro_sidebar( $tpl ) { ? >
// <table>
// <tr><th>Links</th></tr>
// <tr>
// <?php if (isset($tpl->slots->links)): ? >
// <?php echo $tpl->slots->links ? >
// <?php else: ? >
// <td>
// <a href="/">A Link</a>
// </td></tr>
// </table>
// <?php } ? >
//
/**
* @package phptal.php.attribute.metal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_METAL_DefineSlot extends PHPTAL_Php_Attribute
{
public function start()
{
$cond = sprintf('$ctx->hasSlot("%s")', $this->expression);
$this->tag->generator->doIf($cond);
$code = sprintf('<?php echo $ctx->getSlot("%s") ?>', $this->expression);
$this->tag->generator->pushHtml($code);
$this->tag->generator->doElse();
}
public function end()
{
$this->tag->generator->doEnd();
}
}
?>

View file

@ -1,75 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// METAL Specification 1.0
//
// argument ::= Name
//
// Example:
//
// <table metal:use-macro="here/doc1/macros/sidebar">
// <tr><th>Links</th></tr>
// <tr><td metal:fill-slot="links">
// <a href="http://www.goodplace.com">Good Place</a><br>
// <a href="http://www.badplace.com">Bad Place</a><br>
// <a href="http://www.otherplace.com">Other Place</a>
// </td></tr>
// </table>
//
// PHPTAL:
//
// 1. evaluate slots
//
// <?php ob_start(); ? >
// <td>
// <a href="http://www.goodplace.com">Good Place</a><br>
// <a href="http://www.badplace.com">Bad Place</a><br>
// <a href="http://www.otherplace.com">Other Place</a>
// </td>
// <?php $tpl->slots->links = ob_get_contents(); ob_end_clean(); ? >
//
// 2. call the macro (here not supported)
//
// <?php echo phptal_macro($tpl, 'master_page.html/macros/sidebar'); ? >
//
/**
* @package phptal.php.attribute.metal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_METAL_FillSlot extends PHPTAL_Php_Attribute
{
public function start()
{
$this->tag->generator->pushCode('ob_start()');
}
public function end()
{
$code = '$ctx->fillSlot("'.$this->expression.'", ob_get_clean())';
$this->tag->generator->pushCode($code);
}
}

View file

@ -1,131 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// METAL Specification 1.0
//
// argument ::= expression
//
// Example:
//
// <hr />
// <p metal:use-macro="here/master_page/macros/copyright">
// <hr />
//
// PHPTAL: (here not supported)
//
// <?php echo phptal_macro( $tpl, 'master_page.html/macros/copyright'); ? >
//
/**
* @package phptal.php.attribute.metal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_METAL_UseMacro extends PHPTAL_Php_Attribute
{
static $ALLOWED_ATTRIBUTES = array(
'metal:fill-slot',
'metal:define-macro',
'tal:define',
);
public function start()
{
$this->pushSlots();
foreach ($this->tag->children as $child){
$this->generateFillSlots($child);
}
$macroname = strtr($this->expression,'-','_');
// local macro (no filename specified) and non dynamic macro name
if (preg_match('/^[a-z0-9_]+$/i', $macroname)) {
$code = sprintf(
'%s%s($tpl, $ctx)',
$this->tag->generator->getFunctionPrefix(),
$macroname
);
$this->tag->generator->pushCode($code);
}
// external macro or ${macroname}, use PHPTAL at runtime to resolve it
else {
$code = $this->tag->generator->interpolateTalesVarsInString($this->expression);
$code = sprintf('<?php $tpl->executeMacro(%s); ?>', $code);
$this->tag->generator->pushHtml($code);
}
$this->popSlots();
}
public function end()
{
}
private function pushSlots()
{
// reset template slots on each macro call ?
//
// NOTE: defining a macro and using another macro on the same tag
// means inheriting from the used macro, thus slots are shared, it
// is a little tricky to understand but very natural to use.
//
// For example, we may have a main design.html containing our main
// website presentation with some slots (menu, content, etc...) then
// we may define a member.html macro which use the design.html macro
// for the general layout, fill the menu slot and let caller templates
// fill the parent content slot without interfering.
if (!$this->tag->hasAttribute('metal:define-macro')){
$this->tag->generator->pushCode('$ctx->pushSlots()');
}
}
private function popSlots()
{
// restore slots if not inherited macro
if (!$this->tag->hasAttribute('metal:define-macro')){
$this->tag->generator->pushCode('$ctx->popSlots()');
}
}
private function generateFillSlots($tag)
{
if (false == ($tag instanceOf PHPTAL_Php_Tree))
return;
// if the tag contains one of the allowed attribute, we generate it
foreach (self::$ALLOWED_ATTRIBUTES as $attribute){
if ($tag->hasAttribute($attribute)){
$tag->generate();
return;
}
}
// recurse
foreach ($tag->children as $child){
$this->generateFillSlots($child);
}
}
}
?>

View file

@ -1,92 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Kornel Lesiński <kornel@aardvarkmedia.co.uk>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/** phptal:cache (note that's not tal:cache) caches element's HTML for a given time. Time is a number with 'd', 'h', 'm' or 's' suffix.
There's optional parameter that defines how cache should be shared. By default cache is not sensitive to template's context at all
- it's shared between all pages that use that template.
You can add per url to have separate copy of given element for every URL.
You can add per expression to have different cache copy for every different value of an expression (which MUST evaluate to a string).
Expression cannot refer to variables defined using tal:define on the same element.
NB:
* phptal:cache blocks can be nested, but outmost block will cache other blocks regardless of their freshness.
* you cannot use metal:fill-slot inside elements with phptal:cache
Examples:
<div phptal:cache="3h">...</div> <!-- <div> to be evaluated at most once per 3 hours. -->
<ul phptal:cache="1d per object/id">...</ul> <!-- <ul> be cached for one day, separately for each object. -->
*/
class PHPTAL_Php_Attribute_PHPTAL_Cache extends PHPTAL_Php_Attribute
{
private $cache_tag;
public function start()
{
if (!preg_match('/^\s*([0-9]+\s*|[a-zA-Z][a-zA-Z0-9_]*\s+)([dhms])\s*(?:\;?\s*per\s+([^;]+)|)\s*$/',$this->expression, $matches))
throw new PHPTAL_Exception("Cache attribute syntax error: ".$this->expression);
$cache_len = $matches[1];
if (!is_numeric($cache_len)) $cache_len = '$ctx->'.$cache_len;
switch($matches[2])
{
case 'd': $cache_len .= '*24'; /* no break */
case 'h': $cache_len .= '*60'; /* no break */
case 'm': $cache_len .= '*60'; /* no break */
}
$this->cache_tag = '"'.addslashes( $this->tag->node->getName() . ':' . $this->tag->node->getSourceLine()).'"';
$cache_per_expression = isset($matches[3])?trim($matches[3]):NULL;
if ($cache_per_expression == 'url')
{
$this->cache_tag .= '.$_SERVER["REQUEST_URI"]';
}
else if ($cache_per_expression == 'nothing') { }
else if ($cache_per_expression)
{
$code = $this->tag->generator->evaluateExpression($cache_per_expression);
if (is_array($code)) { throw new PHPTAL_Exception("Chained expressions in per-cache directive are not supported"); }
$old_cache_tag = $this->cache_tag;
$this->cache_tag = '$ctx->cache_tag_';
$this->tag->generator->doSetVar($this->cache_tag, '('.$code.')."@".' . $old_cache_tag );
}
$cond = '!file_exists(__FILE__.md5('.$this->cache_tag.')) || time() - '.$cache_len.' >= @filemtime(__FILE__.md5('.$this->cache_tag.'))';
$this->tag->generator->doIf($cond);
$this->tag->generator->doEval('ob_start()');
}
public function end()
{
$this->tag->generator->doEval('file_put_contents(__FILE__.md5('.$this->cache_tag.'), ob_get_flush())');
$this->tag->generator->doElse();
$this->tag->generator->doEval('readfile(__FILE__.md5('.$this->cache_tag.'))');
$this->tag->generator->doEnd();
}
}

View file

@ -1,44 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* @package phptal.php.attribute.phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_PHPTAL_DEBUG extends PHPTAL_Php_Attribute
{
public function start()
{
$this->_oldMode = $this->tag->generator->setDebug(true);
}
public function end()
{
$this->tag->generator->setDebug( $this->_oldMode );
}
private $_oldMode;
}
?>

View file

@ -1,66 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* @package phptal.php.attribute.phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_PHPTAL_ID extends PHPTAL_Php_Attribute
{
private $id;
public function start()
{
$this->id = str_replace('"', '\\\"', $this->expression);
// retrieve trigger
$this->tag->generator->doSetVar(
'$trigger',
'$tpl->getTrigger("'.$this->id.'")'
);
// if trigger found and trigger tells to proceed, we execute
// the node content
$cond = '$trigger && '
. '$trigger->start("%s", $tpl) == PHPTAL_Trigger::PROCEED';
$cond = sprintf($cond, $this->id);
$this->tag->generator->doIf($cond);
}
public function end()
{
// end of if PROCEED
$this->tag->generator->doEnd();
// if trigger found, notify the end of the node
$this->tag->generator->doIf('$trigger');
$this->tag->generator->pushCode(
'$trigger->end("'.$this->id.'", $tpl)'
);
$this->tag->generator->doEnd();
}
}
?>

View file

@ -1,60 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* @package phptal.php.attribute.phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_PHPTAL_TALES extends PHPTAL_Php_Attribute
{
public function start()
{
$mode = trim($this->expression);
$mode = strtolower($mode);
if ($mode == '' || $mode == 'default')
$mode = 'tales';
if ($mode != 'php' && $mode != 'tales') {
$err = "Unsupported TALES mode '%s'";
$err = sprintf($err, $mode);
throw new PHPTAL_Exception(
$err,
$this->tag->getSourceFile(),
$this->tag->getSourceLine()
);
}
$this->_oldMode = $this->tag->generator->setTalesMode( $mode );
}
public function end()
{
$this->tag->generator->setTalesMode( $this->_oldMode );
}
private $_oldMode;
}
?>

View file

@ -1,168 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= attribute_statement [';' attribute_statement]*
// attribute_statement ::= attribute_name expression
// attribute_name ::= [namespace ':'] Name
// namespace ::= Name
//
// examples:
//
// <a href="/sample/link.html"
// tal:attributes="href here/sub/absolute_url">
// <textarea rows="80" cols="20"
// tal:attributes="rows request/rows;cols request/cols">
//
// IN PHPTAL: attributes will not work on structured replace.
//
require_once PHPTAL_DIR.'PHPTAL/Php/TalesChainExecutor.php';
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Attributes
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
const ATT_FULL_REPLACE = '$__ATT_';
const ATT_VALUE_REPLACE = '$__att_';
// this regex is used to determine if an attribute is entirely replaced
// by a php variable or if only its value is replaced.
const REGEX_FULL_REPLACE = '/<?php echo \$__ATT_.*? ?>/';
public function start()
{
// split attributes using ; delimiter
$attrs = $this->tag->generator->splitExpression($this->expression);
foreach ($attrs as $exp) {
list($attribute, $expression) = $this->parseSetExpression($exp);
if ($expression) {
$this->prepareAttribute($attribute, $expression);
}
}
}
public function end()
{
}
private function prepareAttribute($attribute, $expression)
{
$code = $this->extractEchoType(trim($expression));
$code = $this->tag->generator->evaluateExpression($code);
// if $code is an array then the attribute value is decided by a
// tales chained expression
if (is_array($code)) {
return $this->prepareChainedAttribute2($attribute, $code);
}
// XHTML boolean attribute does not appear when empty of false
if (PHPTAL_Dom_Defs::getInstance()->isBooleanAttribute($attribute)) {
return $this->prepareBooleanAttribute($attribute, $code);
}
// regular attribute which value is the evaluation of $code
$attkey = self::ATT_VALUE_REPLACE . $this->getVarName($attribute);
if ($this->_echoType == PHPTAL_Php_Attribute::ECHO_STRUCTURE)
$value = $code;
else
$value = $this->tag->generator->escapeCode($code);
$this->tag->generator->doSetVar($attkey, $value);
$this->tag->overwriteAttributeWithPhpValue($attribute, $attkey);
}
private function prepareChainedAttribute2($attribute, $chain)
{
$this->_default = false;
$this->_attribute = $attribute;
if (array_key_exists($attribute, $this->tag->attributes)) {
$this->_default = $this->tag->attributes[$attribute];
}
$this->_attkey = self::ATT_FULL_REPLACE.$this->getVarName($attribute);
$executor = new PHPTAL_Php_TalesChainExecutor($this->tag->generator, $chain, $this);
$this->tag->overwriteAttributeWithPhpValue($attribute, $this->_attkey);
}
private function prepareBooleanAttribute($attribute, $code)
{
$attkey = self::ATT_FULL_REPLACE.$this->getVarName($attribute);
$value = "' $attribute=\"$attribute\"'";
$this->tag->generator->doIf($code);
$this->tag->generator->doSetVar($attkey, $value);
$this->tag->generator->doElse();
$this->tag->generator->doSetVar($attkey, '\'\'');
$this->tag->generator->doEnd();
$this->tag->overwriteAttributeWithPhpValue($attribute, $attkey);
}
private function getVarName($attribute)
{
return strtr($attribute,':-', '__');
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->tag->generator->doSetVar(
$this->_attkey,
"''"
);
$executor->breakChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$code = ($this->_default !== false)
? "' $this->_attribute=\"".str_replace("'",'\\\'',$this->_default)."\"'" // default value
: '\'\''; // do not print attribute
$this->tag->generator->doSetVar($this->_attkey, $code);
$executor->breakChain();
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
if (!$islast) {
$condition = "!phptal_isempty($this->_attkey = $exp)";
}
else {
$condition = "NULL !== ($this->_attkey = $exp)";
}
$executor->doIf($condition);
if ($this->_echoType == PHPTAL_Php_Attribute::ECHO_STRUCTURE)
$value = $this->_attkey;
else
$value = $this->tag->generator->escapeCode($this->_attkey);
$this->tag->generator->doSetVar($this->_attkey, "' $this->_attribute=\"'.$value.'\"'");
}
}
?>

View file

@ -1,40 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* @package phptal.php.attribute.tal
*/
class PHPTAL_Php_Attribute_TAL_Comment extends PHPTAL_Php_Attribute
{
public function start()
{
$this->tag->generator->doComment($this->expression);
}
public function end()
{
}
}
?>

View file

@ -1,101 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
// TAL Specifications 1.4
//
// argument ::= expression
//
// Example:
//
// <p tal:condition="here/copyright"
// tal:content="here/copyright">(c) 2000</p>
//
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
require_once PHPTAL_DIR.'PHPTAL/Php/TalesChainExecutor.php';
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Condition
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
private $expressions = array();
public function start()
{
$code = $this->tag->generator->evaluateExpression($this->expression);
// If it's a chained expression build a new code path
if (is_array($code)) {
$this->expressions = array();
$executor = new PHPTAL_Php_TalesChainExecutor( $this->tag->generator, $code, $this );
return;
}
// Force a falsy condition if the nothing keyword is active
if ($code == PHPTAL_TALES_NOTHING_KEYWORD) {
$code = 'false';
}
$this->tag->generator->doIf($code);
}
public function end()
{
$this->tag->generator->doEnd();
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
// check if the expression is empty
if ( $exp !== 'false' ) {
$this->expressions[] = '!phptal_isempty($__content__ = ' . $exp . ')';
}
if ( $islast ) {
// for the last one in the chain build a ORed condition
$this->tag->generator->doIf( implode(' || ', $this->expressions ) );
// The executor will always end an if so we output a dummy if
$executor->doIf('false');
}
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
// end the chain
$this->talesChainPart( $executor, 'false', true );
$executor->breakChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
throw new PHPTAL_Exception('\'default\' keyword not allowed on condition expressions');
}
}

View file

@ -1,98 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= (['text'] | 'structure') expression
//
// Example:
//
// <p tal:content="user/name">Fred Farkas</p>
//
//
require_once PHPTAL_DIR.'PHPTAL/Php/TalesChainExecutor.php';
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Content
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
public function start()
{
$expression = $this->extractEchoType($this->expression);
$code = $this->tag->generator->evaluateExpression($expression);
if (is_array($code)) {
return $this->generateChainedContent($code);
}
if ($code == PHPTAL_TALES_NOTHING_KEYWORD) {
return;
}
if ($code == PHPTAL_TALES_DEFAULT_KEYWORD) {
return $this->generateDefault();
}
$this->doEcho($code);
}
public function end()
{
}
private function generateDefault()
{
$this->tag->generateContent(true);
}
private function generateChainedContent($code)
{
$executor = new PHPTAL_Php_TalesChainExecutor($this->tag->generator, $code, $this);
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
$executor->doIf('!phptal_isempty($__content__ = '.$exp.')');
$this->doEcho('$__content__');
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->breakChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->generateDefault();
$executor->breakChain();
}
}
?>

View file

@ -1,183 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL spec 1.4 for tal:define content
//
// argument ::= define_scope [';' define_scope]*
// define_scope ::= (['local'] | 'global') define_var
// define_var ::= variable_name expression
// variable_name ::= Name
//
// Note: If you want to include a semi-colon (;) in an expression, it must be escaped by doubling it (;;).*
//
// examples:
//
// tal:define="mytitle template/title; tlen python:len(mytitle)"
// tal:define="global company_name string:Digital Creations, Inc."
//
require_once PHPTAL_DIR.'PHPTAL/Php/TalesChainExecutor.php';
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Define
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
public function start()
{
$expressions = $this->tag->generator->splitExpression($this->expression);
$definesAnyNonGlobalVars = false;
foreach ($expressions as $exp){
list($defineScope, $defineVar, $expression) = $this->parseExpression($exp);
if (!$defineVar) {
continue;
}
$this->_defineScope = $defineScope;
if ($defineScope != 'global') $definesAnyNonGlobalVars = true; // <span tal:define="global foo" /> should be invisible, but <img tal:define="bar baz" /> not
if ($this->_defineScope != 'global' && !$this->_pushedContext){
$this->tag->generator->pushContext();
$this->_pushedContext = true;
}
$this->_defineVar = $defineVar;
if ($expression === null) {
// no expression give, use content of tag as value for newly defined
// var.
$this->bufferizeContent();
continue;
}
$code = $this->tag->generator->evaluateExpression($expression);
if (is_array($code)){
$this->chainedDefine($code);
}
elseif ($code == PHPTAL_TALES_NOTHING_KEYWORD) {
$this->doDefineVarWith('null');
}
else {
$this->doDefineVarWith($code);
}
}
// if the content of the tag was buffered or the tag has nothing to tell, we hide it.
if ($this->_buffered || (!$definesAnyNonGlobalVars && !$this->tag->hasRealContent() && !$this->tag->hasRealAttributes())){
$this->tag->hidden = true;
}
}
public function end()
{
if ($this->_pushedContext){
$this->tag->generator->popContext();
}
}
private function chainedDefine($parts)
{
$executor = new PHPTAL_Php_TalesChainExecutor(
$this->tag->generator, $parts, $this
);
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->doDefineVarWith('null');
$executor->breakChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->bufferizeContent();
$executor->breakChain();
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
if ($this->_defineScope == 'global'){
$executor->doIf('($glb->'.$this->_defineVar.' = '.$exp.') !== null');
}
else {
$executor->doIf('($ctx->'.$this->_defineVar.' = '.$exp.') !== null');
}
}
/**
* Parse the define expression, already splitted in sub parts by ';'.
*/
public function parseExpression($exp)
{
$defineScope = false; // (local | global)
$defineVar = false; // var to define
// extract defineScope from expression
$exp = trim($exp);
if (preg_match('/^(local|global)\s+(.*?)$/ism', $exp, $m)) {
list(,$defineScope, $exp) = $m;
$exp = trim($exp);
}
// extract varname and expression from remaining of expression
list($defineVar, $exp) = $this->parseSetExpression($exp);
if ($exp !== null) $exp = trim($exp);
return array($defineScope, $defineVar, $exp);
}
private function bufferizeContent()
{
if (!$this->_buffered){
$this->tag->generator->pushCode( 'ob_start()' );
$this->tag->generateContent();
$this->tag->generator->pushCode('$__tmp_content__ = ob_get_clean()');
$this->_buffered = true;
}
$this->doDefineVarWith('$__tmp_content__');
}
private function doDefineVarWith($code)
{
if ($this->_defineScope == 'global'){
$this->tag->generator->doSetVar('$glb->'.$this->_defineVar, $code);
}
else {
$this->tag->generator->doSetVar('$ctx->'.$this->_defineVar, $code);
}
}
private $_buffered = false;
private $_defineScope = null;
private $_defineVar = null;
private $_pushedContext = false;
}
?>

View file

@ -1,74 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= [expression]
//
// Example:
//
// <div tal:omit-tag="" comment="This tag will be removed">
// <i>...but this text will remain.</i>
// </div>
//
// <b tal:omit-tag="not:bold">I may not be bold.</b>
//
// To leave the contents of a tag in place while omitting the surrounding
// start and end tag, use the omit-tag statement.
//
// If its expression evaluates to a false value, then normal processing
// of the element continues.
//
// If the expression evaluates to a true value, or there is no
// expression, the statement tag is replaced with its contents. It is up to
// the interface between TAL and the expression engine to determine the
// value of true and false. For these purposes, the value nothing is false,
// and cancellation of the action has the same effect as returning a
// false value.
//
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_OmitTag extends PHPTAL_Php_Attribute
{
public function start()
{
if (trim($this->expression) == ''){
$this->tag->headFootDisabled = true;
}
else {
// print tag header/foot only if condition is false
$cond = $this->tag->generator->evaluateExpression($this->expression);
$this->tag->headFootPrintCondition = '!('.$cond.')';
}
}
public function end()
{
}
}
?>

View file

@ -1,81 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= (['text'] | 'structure') expression
//
// Example:
//
// <p tal:on-error="string: Error! This paragraph is buggy!">
// My name is <span tal:replace="here/SlimShady" />.<br />
// (My login name is
// <b tal:on-error="string: Username is not defined!"
// tal:content="user">Unknown</b>)
// </p>
//
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_OnError extends PHPTAL_Php_Attribute
{
const ERR_VAR = '$__err__';
public function start()
{
$this->tag->generator->doTry();
$this->tag->generator->pushCode('ob_start()');
}
public function end()
{
$this->tag->generator->pushCode('ob_end_flush()');
$this->tag->generator->doCatch('Exception '.self::ERR_VAR);
$this->tag->generator->pushCode('$tpl->addError('.self::ERR_VAR.')');
$this->tag->generator->pushCode('ob_end_clean()');
$expression = $this->extractEchoType($this->expression);
$code = $this->tag->generator->evaluateExpression($expression);
switch ($code) {
case PHPTAL_TALES_NOTHING_KEYWORD:
break;
case PHPTAL_TALES_DEFAULT_KEYWORD:
$this->tag->generator->pushHtml('<pre class="phptalError"');
$this->tag->generator->doEcho(self::ERR_VAR);
$this->tag->generator->pushHtml('</pre>');
break;
default:
$this->doEcho($code);
break;
}
$this->tag->generator->doEnd();
}
}
?>

View file

@ -1,115 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= variable_name expression
// variable_name ::= Name
//
// Example:
//
// <p tal:repeat="txt python:'one', 'two', 'three'">
// <span tal:replace="txt" />
// </p>
// <table>
// <tr tal:repeat="item here/cart">
// <td tal:content="repeat/item/index">1</td>
// <td tal:content="item/description">Widget</td>
// <td tal:content="item/price">$1.50</td>
// </tr>
// </table>
//
// The following information is available from an Iterator:
//
// * index - repetition number, starting from zero.
// * number - repetition number, starting from one.
// * even - true for even-indexed repetitions (0, 2, 4, ...).
// * odd - true for odd-indexed repetitions (1, 3, 5, ...).
// * start - true for the starting repetition (index 0).
// * end - true for the ending, or final, repetition.
// * length - length of the sequence, which will be the total number of repetitions.
//
// * letter - count reps with lower-case letters: "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth.
// * Letter - upper-case version of letter.
// * roman - count reps with lower-case roman numerals: "i", "ii", "iii", "iv", "v", "vi" ...
// * Roman - upper-case version of roman numerals.
///
// * first - true for the first item in a group - see note below
// * lasst - true for the last item in a group - see note below
//
// Note: first and last are intended for use with sorted sequences. They try to
// divide the sequence into group of items with the same value. If you provide
// a path, then the value obtained by following that path from a sequence item
// is used for grouping, otherwise the value of the item is used. You can
// provide the path by appending it to the path from the repeat variable,
// as in "repeat/item/first/color".
//
// PHPTAL: index, number, even, etc... will be stored in the
// $ctx->repeat->'item' object. Thus $ctx->repeat->item->odd
//
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Repeat extends PHPTAL_Php_Attribute
{
const REPEAT = '$__repeat__';
public function start()
{
// alias to repeats handler to avoid calling extra getters on each variable access
$this->tag->generator->doSetVar( self::REPEAT, '$ctx->repeat' );
list( $varName, $expression ) = $this->parseSetExpression( $this->expression );
$code = $this->tag->generator->evaluateExpression( $expression );
$item = '$ctx->' . $varName;
$controller = self::REPEAT . '->' . $varName;
// reset item var into template context
/* // Is this actually needed?
$this->tag->generator->doIf( '!isset('.$this->item.')' );
$this->tag->generator->doSetVar( $this->item, 'false' );
$this->tag->generator->doEnd();
*/
// instantiate controller using expression
$this->tag->generator->doSetVar( $controller, 'new PHPTAL_RepeatController('.$code.')' );
// Lets loop the iterator with a foreach construct
$this->tag->generator->doForeach( $item, $controller );
}
public function end()
{
$this->tag->generator->doEnd();
}
private $item;
private $controller;
}
?>

View file

@ -1,117 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
// TAL Specifications 1.4
//
// argument ::= (['text'] | 'structure') expression
//
// Default behaviour : text
//
// <span tal:replace="template/title">Title</span>
// <span tal:replace="text template/title">Title</span>
// <span tal:replace="structure table" />
// <span tal:replace="nothing">This element is a comment.</span>
//
require_once PHPTAL_DIR.'PHPTAL/Php/TalesChainExecutor.php';
/**
* @package phptal.php.attribute.tal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Attribute_TAL_Replace
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
const REPLACE_VAR = '$__replace__';
public function start()
{
// tal:replace="" => do nothing and ignore node
if (trim($this->expression) == ""){
return;
}
$expression = $this->extractEchoType($this->expression);
$code = $this->tag->generator->evaluateExpression($expression);
// chained expression
if (is_array($code)){
return $this->replaceByChainedExpression($code);
}
// nothing do nothing
if ($code == PHPTAL_TALES_NOTHING_KEYWORD) {
return;
}
// default generate default tag content
if ($code == PHPTAL_TALES_DEFAULT_KEYWORD) {
return $this->generateDefault();
}
// replace tag with result of expression
$this->doEcho($code);
}
public function end()
{
}
private function replaceByChainedExpression($expArray)
{
$executor = new PHPTAL_Php_TalesChainExecutor(
$this->tag->generator, $expArray, $this
);
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->continueChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->generateDefault();
$executor->breakChain();
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
$executor->doIf('!phptal_isempty('.self::REPLACE_VAR.' = '.$exp.')');
$this->doEcho(self::REPLACE_VAR);
}
private function generateDefault()
{
$this->tag->generateSurroundHead();
$this->tag->generateHead();
$this->tag->generateContent();
$this->tag->generateFoot();
$this->tag->generateSurroundFoot();
}
}
?>

View file

@ -1,55 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Php/Node.php';
require_once PHPTAL_DIR.'PHPTAL/Php/State.php';
require_once PHPTAL_DIR.'PHPTAL/Php/CodeWriter.php';
/**
* @package phptal.php
*/
class PHPTAL_Php_CodeGenerator
{
public function __construct($function_name, $source_path)
{
$this->_functionName = $function_name;
$this->_sourceFile = $source_path;
$this->_state = new PHPTAL_Php_State();
$this->_writer = new PHPTAL_Php_CodeWriter($this->_state);
}
public function setOutputMode($mode)
{
$this->_state->setOutputMode($mode);
}
public function setEncoding($enc)
{
$this->_state->setEncoding($enc);
}
public function generate(PHPTAL_Dom_Tree $tree)
{
$treeGen = new PHPTAL_Php_Tree($this->_writer, $tree);
$this->_writer->doComment('Generated by PHPTAL from '.$this->_sourceFile);
$this->_writer->doFunction($this->_functionName, '$tpl, $ctx');
$this->_writer->setFunctionPrefix($this->_functionName . "_");
$this->_writer->doSetVar('$glb', '$tpl->getGlobalContext()');
$this->_writer->doSetVar('$_translator', '$tpl->getTranslator()');
$treeGen->generate();
$this->_writer->doEnd();
}
public function getResult()
{
return $this->_writer->getResult();
}
private $_functionName;
private $_sourceFile;
private $_writer;
private $_state;
}
?>

View file

@ -1,394 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* Helps generate php representation of a template.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_CodeWriter
{
public $_indentation = 0;
public function __construct(PHPTAL_Php_State $state)
{
$this->_state = $state;
}
public function getResult()
{
$this->flush();
$this->_result = trim($this->_result);
return $this->_result;
}
public function setDocType(PHPTAL_Php_Doctype $dt)
{
$this->_doctype = str_replace('\'', '\\\'', $dt->node->getValue());
}
public function setXmlDeclaration(PHPTAL_Php_XmlDeclaration $dt)
{
$this->_xmldeclaration = str_replace('\'', '\\\'', $dt->node->getValue());
}
public function setFunctionPrefix($prefix)
{
$this->_functionPrefix = $prefix;
}
public function getFunctionPrefix()
{
return $this->_functionPrefix;
}
/**
* Returns old tales mode.
*/
public function setTalesMode($mode)
{
return $this->_state->setTalesMode($mode);
}
public function splitExpression($src)
{
preg_match_all('/(?:[^;]+|;;)+/sm', $src, $array);
$array = $array[0];
foreach($array as &$a) $a = str_replace(';;',';',$a);
return $array;
}
public function evaluateExpression($src)
{
return $this->_state->evalTalesExpression($src);
}
public function indent()
{
$this->_indentation ++;
}
public function unindent()
{
$this->_indentation --;
}
public function flush()
{
$this->flushCode();
$this->flushHtml();
}
public function noThrow($bool)
{
if ($bool){
$this->pushCode('$ctx->noThrow(true)');
}
else {
$this->pushCode('$ctx->noThrow(false)');
}
}
public function flushCode()
{
if (count($this->_codeBuffer) == 0)
return;
// special treatment for one code line
if (count($this->_codeBuffer) == 1){
$codeLine = $this->_codeBuffer[0];
// avoid adding ; after } and {
if (!preg_match('/\}|\{\s+$/', $codeLine))
$this->_result .= '<?php '.$codeLine.'; ?>';
else
$this->_result .= '<?php '.$codeLine.' ?>';
$this->_codeBuffer = array();
return;
}
$this->_result .= '<?php '."\n";
foreach ($this->_codeBuffer as $codeLine) {
// avoid adding ; after } and {
if (!preg_match('/\}|\{\s+$/', $codeLine))
$this->_result .= $codeLine . ' ;'."\n";
else
$this->_result .= $codeLine;
}
$this->_result .= '?>';
$this->_codeBuffer = array();
}
public function flushHtml()
{
if (count($this->_htmlBuffer) == 0) return;
$this->_result .= join( '', $this->_htmlBuffer );
$this->_htmlBuffer = array();
}
public function doDoctype()
{
if ($this->_doctype){
$code = '$ctx->setDocType(\''.$this->_doctype.'\')';
$this->pushCode($code);
}
}
public function doXmlDeclaration()
{
if ($this->_xmldeclaration){
$code = '$ctx->setXmlDeclaration(\''.$this->_xmldeclaration.'\')';
$this->pushCode($code);
}
}
public function doFunction($name, $params)
{
$name = $this->_functionPrefix . $name;
$this->pushGeneratorContext();
$this->pushCode("function $name( $params ) {\n");
$this->indent();
array_push($this->_segments, 'function');
}
public function doComment($comment)
{
$comment = str_replace('*/', '* /', $comment);
$this->pushCode("/* $comment */");
}
public function doEval($code)
{
$this->pushCode($code);
}
public function doForeach($out, $source)
{
array_push($this->_segments, 'foreach');
$this->pushCode("foreach ($source as \$__key__ => $out ):");
$this->indent();
}
public function doEnd()
{
$segment = array_pop($this->_segments);
$this->unindent();
if ($segment == 'function') {
$this->pushCode("\n}\n\n");
$functionCode = $this->getResult();
$this->popGeneratorContext();
$this->_result = $functionCode . $this->_result;
}
else if ($segment == 'try')
$this->pushCode('}');
else if ($segment == 'catch')
$this->pushCode('}');
else
$this->pushCode("end$segment");
}
public function doTry()
{
array_push($this->_segments, 'try');
$this->pushCode('try {');
$this->indent();
}
public function doSetVar($varname, $code)
{
$this->pushCode($varname.' = '.$code);
}
public function doCatch($catch)
{
$this->doEnd();
array_push($this->_segments, 'catch');
$code = 'catch(%s) {';
$this->pushCode(sprintf($code, $catch));
$this->indent();
}
public function doIf($condition)
{
array_push($this->_segments, 'if');
$this->pushCode('if ('.$condition.'): ');
$this->indent();
}
public function doElseIf($condition)
{
$this->unindent();
$this->pushCode('elseif ('.$condition.'): ');
$this->indent();
}
public function doElse()
{
$this->unindent();
$this->pushCode('else: ');
$this->indent();
}
public function doEcho($code)
{
$this->flush();
$html = '<?php echo %s ?>';
$html = sprintf($html, $this->escapeCode($code));
$this->pushHtml($html);
}
public function doEchoRaw($code)
{
$this->pushHtml('<?php echo '.$code.' ?>');
}
public function pushHtml($html)
{
$html = $this->_state->interpolateTalesVarsInHtml($html);
$this->flushCode();
array_push($this->_htmlBuffer, $html);
}
public function pushRawHtml($html)
{
$this->flushCode();
array_push($this->_htmlBuffer, $html);
}
public function pushString($str)
{
$this->flushCode();
// replace ${var} inside strings
while (preg_match('/^(.*?)((?<!\$)\$\{[^\}]*?\})(.*?)$/s', $str, $m)){
list(,$before,$expression,$after) = $m;
$before = $this->escapeLTandGT($before);
array_push($this->_htmlBuffer, $before);
$expression = $this->_state->interpolateTalesVarsInHtml($expression);
array_push($this->_htmlBuffer, $expression);
$str = $after;
}
$str = str_replace('$${', '${', $str);
if (strlen($str) > 0){
$str = $this->escapeLTandGT($str);
array_push($this->_htmlBuffer, $str);
}
}
public function pushCode($codeLine)
{
$this->flushHtml();
$codeLine = $this->indentSpaces() . $codeLine;
array_push($this->_codeBuffer, $codeLine);
}
public function escapeLTandGT($str){
$str = str_replace('<', '&lt;', $str);
$str = str_replace('>', '&gt;', $str);
return $str;
}
public function escapeCode($code)
{
return $this->_state->htmlchars($code);
}
public function getEncoding()
{
return $this->_state->getEncoding();
}
public function interpolateTalesVarsInString($src)
{
return $this->_state->interpolateTalesVarsInString($src);
}
public function setDebug($bool)
{
return $this->_state->setDebug($bool);
}
public function isDebugOn()
{
return $this->_state->isDebugOn();
}
public function getOutputMode()
{
return $this->_state->getOutputMode();
}
public function pushContext()
{
$this->pushCode('$ctx = $tpl->pushContext()');
}
public function popContext()
{
$this->pushCode('$ctx = $tpl->popContext()');
}
// ~~~~~ Private members ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private function indentSpaces()
{
return str_repeat("\t", $this->_indent);
}
private function pushGeneratorContext()
{
array_push($this->_contexts, clone $this);
$this->_result = "";
$this->_indent = 0;
$this->_codeBuffer = array();
$this->_htmlBuffer = array();
$this->_segments = array();
}
private function popGeneratorContext()
{
$oldContext = array_pop($this->_contexts);
$this->_result = $oldContext->_result;
$this->_indent = $oldContext->_indent;
$this->_codeBuffer = $oldContext->_codeBuffer;
$this->_htmlBuffer = $oldContext->_htmlBuffer;
$this->_segments = $oldContext->_segments;
}
private $_state;
private $_result = "";
private $_indent = 0;
private $_codeBuffer = array();
private $_htmlBuffer = array();
private $_segments = array();
private $_contexts = array();
private $_functionPrefix = "";
private $_doctype = "";
private $_xmldeclaration = "";
}
?>

View file

@ -1,101 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* @package phptal.php
*/
class PHPTAL_Php_ElementWriter
{
public function __construct(PHPTAL_Php_CodeWriter $writer, PHPTAL_Php_Element $tag)
{
$this->_writer = $writer;
$this->_tag = $tag;
}
public function writeHead()
{
if ($this->_tag->headFootDisabled)
return;
if ($this->_tag->headFootPrintCondition){
$this->_writer->doIf($this->_tag->headFootPrintCondition);
}
$this->_writer->pushHtml('<'.$this->_tag->name);
$this->_writeAttributes();
if ($this->_tag->isEmptyNode()){
$this->_writer->pushHtml('/>');
}
else {
$this->_writer->pushHtml('>');
}
if ($this->_tag->headFootPrintCondition){
$this->_writer->doEnd();
}
}
public function writeFoot()
{
if ($this->_tag->headFootDisabled)
return;
if ($this->_tag->isEmptyNode())
return;
if ($this->_tag->headFootPrintCondition){
$this->_writer->doIf($this->_tag->headFootPrintCondition);
}
$this->_writer->pushHtml('</'.$this->_tag->name.'>');
if ($this->_tag->headFootPrintCondition){
$this->_writer->doEnd();
}
}
public function writeAttributes()
{
$fullreplaceRx = PHPTAL_Php_Attribute_TAL_Attributes::REGEX_FULL_REPLACE;
foreach ($this->_tag->attributes as $key=>$value) {
if (preg_match($fullreplaceRx, $value)){
$this->_writer->pushHtml($value);
}
/*
else if (strpos('<?php', $value) === 0){
$this->_writer->pushHtml(' '.$key.'="');
$this->_writer->pushRawHtml($value);
$this->_writer->pushHtml('"');
}
*/
else {
$this->_writer->pushHtml(' '.$key.'="'.$value.'"');
}
}
}
private $_tag;
private $_writer;
}
?>

View file

@ -1,507 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Dom/Defs.php';
require_once PHPTAL_DIR.'PHPTAL/Php/CodeWriter.php';
require_once PHPTAL_DIR.'PHPTAL/Php/Attribute.php';
/**
* Document node abstract class.
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
abstract class PHPTAL_Php_Node
{
public $node;
public $generator;
public function __construct(PHPTAL_Php_CodeWriter $generator, PHPTAL_Dom_Node $node)
{
$this->generator = $generator;
$this->node = $node;
}
public function getSourceFile()
{
return $this->node->getSourceFile();
}
public function getSourceLine()
{
return $this->node->getSourceLine();
}
public abstract function generate();
}
/**
* Node container.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Tree extends PHPTAL_Php_Node
{
public $children;
public function __construct(PHPTAL_Php_CodeWriter $gen, $node)
{
parent::__construct($gen,$node);
$this->children = array();
foreach ($node->getChildren() as $child){
if ($child instanceOf PHPTAL_Dom_Element){
$gen = new PHPTAL_Php_Element($this->generator, $child);
}
else if ($child instanceOf PHPTAL_Dom_Text){
$gen = new PHPTAL_Php_Text($this->generator, $child);
}
else if ($child instanceOf PHPTAL_Dom_Doctype){
$gen = new PHPTAL_Php_Doctype($this->generator, $child);
}
else if ($child instanceOf PHPTAL_Dom_XmlDeclaration){
$gen = new PHPTAL_Php_XmlDeclaration($this->generator, $child);
}
else if ($child instanceOf PHPTAL_Dom_Specific){
$gen = new PHPTAL_Php_Specific($this->generator, $child);
}
else if ($child instanceOf PHPTAL_Dom_Comment){
$gen = new PHPTAL_Php_Comment($this->generator, $child);
}
else {
throw new PHPTAL_Exception('Unhandled node class '.get_class($child));
}
array_push($this->children, $gen);
}
}
public function generate()
{
try
{
foreach ($this->children as $child){
$child->generate();
}
}
catch(PHPTAL_Exception $e)
{
$e->hintSrcPosition($this->getSourceFile(), $this->getSourceLine());
throw $e;
}
}
}
/**
* Document Tag representation.
*
* This is the main class used by PHPTAL because TAL is a Template Attribute
* Language, other Node kinds are (usefull) toys.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Element extends PHPTAL_Php_Tree
{
const ERR_ATTRIBUTES_CONFLICT =
"Attribute conflict in '%s' at line '%d', '%s' cannot appear with '%s'";
public $name;
public $attributes = array();
public $talAttributes = array();
public $overwrittenAttributes = array();
public $replaceAttributes = array();
public $contentAttributes = array();
public $surroundAttributes = array();
public $headFootDisabled = false;
public $headFootPrintCondition = false;
public $hidden = false;
public function __construct(PHPTAL_Php_CodeWriter $generator, $node)
{
parent::__construct($generator, $node);
$this->name = $node->getName();
$this->attributes = $node->attributes;
$this->xmlns = $node->getXmlnsState();
$this->prepare();
}
private function prepare()
{
$this->prepareAttributes();
$this->separateAttributes();
$this->orderTalAttributes();
}
public function generate()
{
if ($this->generator->isDebugOn()){
$this->generator->pushCode('$ctx->__line = '.$this->getSourceLine());
$this->generator->doComment('tag "'.$this->name.'" from line '.$this->getSourceLine());
}
if (count($this->replaceAttributes) > 0) {
$this->generateSurroundHead();
foreach ($this->replaceAttributes as $att) {
$att->start();
$att->end();
}
$this->generateSurroundFoot();
return;
}
$this->generateSurroundHead();
// a surround tag may decide to hide us (tal:define for example)
if (!$this->hidden){
$this->generateHead();
$this->generateContent();
$this->generateFoot();
}
$this->generateSurroundFoot();
}
/** Returns true if the element contains specified PHPTAL attribute. */
public function hasAttribute($name)
{
return $this->node->hasAttribute($name);
}
/** Returns the value of specified PHPTAL attribute. */
public function getAttribute($name)
{
return $this->node->getAttribute($name);
}
public function isOverwrittenAttribute($name)
{
return array_key_exists($name, $this->overwrittenAttributes);
}
public function getOverwrittenAttributeVarName($name)
{
return $this->overwrittenAttributes[$name];
}
public function overwriteAttributeWithPhpValue($name, $phpVariable)
{
$this->attributes[$name] = '<?php echo '.$phpVariable.' ?>';
$this->overwrittenAttributes[$name] = $phpVariable;
}
/**
* Returns true if this element or one of its PHPTAL attributes has some
* content to print (an empty text node child does not count).
*/
public function hasRealContent()
{
return $this->node->hasRealContent()
|| count($this->contentAttributes) > 0;
}
public function hasRealAttributes()
{
return ((count($this->attributes) - count($this->talAttributes)) > 0) || $this->hasAttribute('tal:attributes');
}
// ~~~~~ Generation methods may be called by some PHPTAL attributes ~~~~~
public function generateSurroundHead()
{
foreach ($this->surroundAttributes as $att) {
$att->start();
}
}
public function generateHead()
{
if ($this->headFootDisabled) return;
if ($this->headFootPrintCondition) {
$this->generator->doIf($this->headFootPrintCondition);
}
$this->generator->pushHtml('<'.$this->name);
$this->generateAttributes();
if ($this->isEmptyNode()){
$this->generator->pushHtml('/>');
}
else {
$this->generator->pushHtml('>');
}
if ($this->headFootPrintCondition) {
$this->generator->doEnd();
}
}
public function generateContent($realContent=false)
{
if ($this->isEmptyNode()){
return;
}
if (!$realContent && count($this->contentAttributes) > 0) {
foreach ($this->contentAttributes as $att) {
$att->start();
$att->end();
}
return;
}
parent::generate();
}
public function generateFoot()
{
if ($this->headFootDisabled)
return;
if ($this->isEmptyNode())
return;
if ($this->headFootPrintCondition) {
$this->generator->doIf($this->headFootPrintCondition);
}
$this->generator->pushHtml( '</'.$this->name.'>' );
if ($this->headFootPrintCondition) {
$this->generator->doEnd();
}
}
public function generateSurroundFoot()
{
for ($i = (count($this->surroundAttributes)-1); $i >= 0; $i--) {
$this->surroundAttributes[$i]->end();
}
}
// ~~~~~ Private members ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private function generateAttributes()
{
// A phptal attribute can modify any node attribute replacing
// its value by a <?php echo $somevalue ?\ >.
//
// The entire attribute (key="value") can be replaced using the
// '$__ATT_' value code, it is very usefull for xhtml boolean
// attributes like selected, checked, etc...
//
// example:
//
// $tag->generator->pushCode(
// '$__ATT_checked = $somecondition ? \'checked="checked"\' : \'\''
// );
// $tag->attributes['checked'] = '<?php echo $__ATT_checked ?\>';
//
$fullreplaceRx = PHPTAL_Php_Attribute_TAL_Attributes::REGEX_FULL_REPLACE;
foreach ($this->attributes as $key=>$value) {
if (preg_match($fullreplaceRx, $value)){
$this->generator->pushHtml($value);
}
else if (strpos($value,'<?php') === 0){
$this->generator->pushHtml(' '.$key.'="');
$this->generator->pushRawHtml($value);
$this->generator->pushHtml('"');
}
else {
$this->generator->pushHtml(' '.$key.'="'.$value.'"');
}
}
}
private function getNodePrefix()
{
$result = false;
if (preg_match('/^(.*?):block$/', $this->name, $m)){
list(,$result) = $m;
}
return $result;
}
private function isEmptyNode()
{
return ($this->generator->getOutputMode() == PHPTAL::XHTML && PHPTAL_Dom_Defs::getInstance()->isEmptyTag($this->name)) ||
($this->generator->getOutputMode() == PHPTAL::XML && !$this->hasContent());
}
private function hasContent()
{
return count($this->children) > 0 || count($this->contentAttributes) > 0;
}
private function prepareAttributes()
{
//TODO: use registered namespaces instead of the raw list
if (preg_match('/^(tal|metal|phptal|i18n):block$/', $this->name, $m)) {
$this->headFootDisabled = true;
list(,$ns) = $m;
$attributes = array();
foreach ($this->attributes as $key=>$value) {
if ($this->xmlns->isPhpTalAttribute("$ns:$key")) {
$attributes["$ns:$key"] = $value;
}
else {
$attributes[$key] = $value;
}
}
$this->attributes = $attributes;
}
}
private function separateAttributes()
{
$attributes = array();
$this->talAttributes = array();
foreach ($this->attributes as $key=>$value) {
// remove handled xml namespaces
if (PHPTAL_Dom_Defs::getInstance()->isHandledXmlNs($key,$value)){
}
else if ($this->xmlns->isPhpTalAttribute($key)) {
$this->talAttributes[$key] = $value;
}
else if (PHPTAL_Dom_Defs::getInstance()->isBooleanAttribute($key)) {
$attributes[$key] = $key;
}
else {
$attributes[$key] = $value;
}
}
$this->attributes = $attributes;
}
private function orderTalAttributes()
{
$attributes = array();
foreach ($this->talAttributes as $key=>$exp){
$name = $this->xmlns->unAliasAttribute($key);
$att = PHPTAL_Dom_Defs::getInstance()->getNamespaceAttribute($name);
if (array_key_exists($att->getPriority(), $attributes)){
$err = sprintf(self::ERR_ATTRIBUTES_CONFLICT,
$this->name,
$this->getSourceLine(),
$key,
$attributes[$att->getPriority()][0]
);
throw new PHPTAL_Exception($err);
}
$attributes[$att->getPriority()] = array($key, $att, $exp);
}
ksort($attributes);
$this->talHandlers = array();
foreach ($attributes as $prio => $dat){
list($key, $att, $exp) = $dat;
$handler = $att->createAttributeHandler($this, $exp);
$this->talHandlers[$prio] = $handler;
if ($att instanceOf PHPTAL_NamespaceAttributeSurround)
$this->surroundAttributes[] = $handler;
else if ($att instanceOf PHPTAL_NamespaceAttributeReplace)
$this->replaceAttributes[] = $handler;
else if ($att instanceOf PHPTAL_NamespaceAttributeContent)
$this->contentAttributes[] = $handler;
else
throw new PHPTAL_Exception("Unknown namespace attribute class ".get_class($att));
}
}
}
/**
* @package phptal.php
*/
class PHPTAL_Php_Comment extends PHPTAL_Php_Node
{
public function generate()
{
$this->generator->pushRawHtml($this->node->getValue());
}
}
/**
* Document text data representation.
* @package phptal.php
*/
class PHPTAL_Php_Text extends PHPTAL_Php_Node
{
public function generate()
{
$this->generator->pushString($this->node->getValue());
}
}
/**
* Comment, preprocessor, etc... representation.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Specific extends PHPTAL_Php_Node
{
public function generate()
{
$this->generator->pushHtml($this->node->getValue());
}
}
/**
* Document doctype representation.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Doctype extends PHPTAL_Php_Node
{
public function __construct(PHPTAL_Php_CodeWriter $generator, $node)
{
parent::__construct($generator, $node);
$this->generator->setDocType($this);
}
public function generate()
{;
$this->generator->doDoctype();
}
}
/**
* XML declaration node.
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_XmlDeclaration extends PHPTAL_Php_Node
{
public function __construct(PHPTAL_Php_CodeWriter $gen, $node)
{
parent::__construct($gen, $node);
$this->generator->setXmlDeclaration($this);
}
public function generate()
{
$this->generator->doXmlDeclaration();
}
}
?>

View file

@ -1,152 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
require_once PHPTAL_DIR.'PHPTAL/Php/Tales.php';
/**
* @package phptal.php
*/
class PHPTAL_Php_State
{
public function __construct()
{
$this->_debug = false;
$this->_talesMode = 'tales';
$this->_encoding = 'UTF-8';
$this->_outputMode = '';
}
public function setDebug($bool)
{
$old = $this->_debug;
$this->_debug = $bool;
return $old;
}
public function isDebugOn()
{
return $this->_debug;
}
public function setTalesMode($mode)
{
$old = $this->_talesMode;
$this->_talesMode = $mode;
return $old;
}
public function getTalesMode()
{
return $this->_talesMode;
}
public function setEncoding($enc)
{
$this->_encoding = $enc;
}
public function getEncoding()
{
return $this->_encoding;
}
public function setOutputMode($mode)
{
$this->_outputMode = $mode;
}
public function getOutputMode()
{
return $this->_outputMode;
}
public function evalTalesExpression($expression)
{
if ($this->_talesMode == 'php')
return PHPTAL_TalesInternal::php($expression);
return phptal_tales($expression);
}
public function interpolateTalesVarsInString($string)
{
if ($this->_talesMode == 'tales'){
return PHPTAL_TalesInternal::string($string);
}
// replace ${var} found in expression
while (preg_match('/(?<!\$)\$\{([^\}]+)\}/ism', $string, $m)){
list($ori, $exp) = $m;
$php = PHPTAL_TalesInternal::php($exp);
$repl = '\'.%s.\'';
$repl = sprintf($repl, $php, $this->_encoding);
$string = str_replace($ori, $repl, $string);
}
$string = str_replace('$${', '${', $string);
return '\''.$string.'\'';
}
private function _interpolateTalesVarsStructure($matches) {
return '<?php echo '.phptal_tale($matches[1]).' ?>';
}
private function _interpolateTalesVarsEscaped($matches) {
return '<?php echo phptal_escape('.phptal_tale($matches[1]).', ENT_QUOTES, \''.$this->_encoding.'\');?>';
}
public function interpolateTalesVarsInHtml($src)
{
if ($this->_talesMode == 'tales'){
$result = preg_replace_callback('/(?<!\$)\$\{structure (.*?)\}/ism', array($this,'_interpolateTalesVarsStructure'), $src);
$result = preg_replace_callback('/(?<!\$)\$\{(.*?)\}/ism', array($this,'_interpolateTalesVarsEscaped'), $result);
$result = str_replace('$${', '${', $result);
return $result;
}
while (preg_match('/(?<!\$)\${(structure )?([^\}]+)\}/ism', $src, $m)){
list($ori, $struct, $exp) = $m;
$php = PHPTAL_TalesInternal::php($exp);
// when structure keyword is specified the output is not html
// escaped
if ($struct){
$repl = '<?php echo '.$php.'; ?>';
}
else {
$repl = '<?php echo '.$this->htmlchars($php).'; ?>';
}
$src = str_replace($ori, $repl, $src);
}
return str_replace('$${','${', $src);
}
public function htmlchars($php)
{
return 'phptal_escape('.$php.', ENT_QUOTES, \''.$this->_encoding.'\')';
}
private $_debug;
private $_talesMode;
private $_encoding;
private $_outputMode;
}
?>

View file

@ -1,135 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
define('PHPTAL_TALES_DEFAULT_KEYWORD', '_DEFAULT_DEFAULT_DEFAULT_DEFAULT_');
define('PHPTAL_TALES_NOTHING_KEYWORD', '_NOTHING_NOTHING_NOTHING_NOTHING_');
// TALES Specification 1.3
//
// Expression ::= [type_prefix ':'] String
// type_prefix ::= Name
//
// Examples:
//
// a/b/c
// path:a/b/c
// nothing
// path:nothing
// python: 1 + 2
// string:Hello, ${username}
//
//
// Builtin Names in Page Templates (for PHPTAL)
//
// * nothing - special singleton value used by TAL to represent a
// non-value (e.g. void, None, Nil, NULL).
//
// * default - special singleton value used by TAL to specify that
// existing text should not be replaced.
//
// * repeat - the repeat variables (see RepeatVariable).
//
function _phptal_tale_wrap($array, $nothrow)
{
if (count($array)==1) return '($ctx->noThrow('.($nothrow?'true':'false').')||1?('.
($array[0]==PHPTAL_TALES_NOTHING_KEYWORD?'NULL':$array[0]).
'):"")';
$expr = array_shift($array);
return "((\$tmp5=$expr) && (\$ctx->noThrow(false)||1)?\$tmp5:"._phptal_tale_wrap($array, $nothrow).')';
}
/** translates array of alternative expressions into single PHP expression. Identical to phptal_tales() for singular expressions. */
function phptal_tale($expression, $nothrow=false)
{
$r = phptal_tales($expression,true);
if (!is_array($r)) return $r;
// this weird ternary operator construct is to execute noThrow inside the expression
return '($ctx->noThrow(true)||1?'._phptal_tale_wrap($r, $nothrow).':"")';
}
function phptal_tales($expression, $nothrow=false)
{
$expression = trim($expression);
// Look for tales modifier (string:, exists:, etc...)
//if (preg_match('/^([-a-z]+):(.*?)$/', $expression, $m)) {
if (preg_match('/^([a-z][-.a-z]*[a-z]):(.*?)$/i', $expression, $m)) {
list(,$typePrefix,$expression) = $m;
}
// may be a 'string'
else if (preg_match('/^\'((?:[^\']|\\\\.)*)\'$/', $expression, $m)) {
$expression = stripslashes($m[1]);
$typePrefix = 'string';
}
// failback to path:
else {
$typePrefix = 'path';
}
// is a registered TALES expression modifier
if(PHPTAL_TalesRegistry::getInstance()->isRegistered($typePrefix)) {
$callback = PHPTAL_TalesRegistry::getInstance()->getCallback($typePrefix);
return call_user_func($callback, $expression, $nothrow);
}
// class method
if (strpos($typePrefix, '.')){
$classCallback = explode('.', $typePrefix, 2);
$callbackName = NULL;
if(!is_callable($classCallback, FALSE, $callbackName)) {
$err = 'Unknown phptal modifier %s function %s does not exists or is not statically callable.';
$err = sprintf($err, $typePrefix, $callbackName);
throw new PHPTAL_Exception($err);
}
$ref = new ReflectionClass($classCallback[0]);
if(!$ref->implementsInterface('PHPTAL_Tales')){
$err = 'Unable to use phptal modifier %s as the class %s does not implement the PHPTAL_Tales interface.';
$err = sprintf($err, $typePrefix, $callbackName);
throw new PHPTAL_Exception($err);
}
return call_user_func($classCallback, $expression, $nothrow);
}
// check if it is implemented via code-generating function
$func = 'phptal_tales_'.str_replace('-','_',$typePrefix);
if (function_exists($func)) {
return $func($expression, $nothrow);
}
// check if it is implemented via runtime function
$runfunc = 'phptal_runtime_tales_'.str_replace('-','_',$typePrefix);
if (function_exists($runfunc)) {
return "$runfunc(".phptal_tale($expression, $nothrow).")";
}
throw new PHPTAL_Exception("Unknown phptal modifier '$typePrefix'. Function '$func' does not exist");
}
// Register internal Tales expression modifiers
require_once PHPTAL_DIR.'PHPTAL/Php/TalesInternal.php';
PHPTAL_TalesInternal::registerInternalTales();
?>

View file

@ -1,99 +0,0 @@
<?php
/**
* @package phptal.php
*/
interface PHPTAL_Php_TalesChainReader
{
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor);
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor);
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $expression, $islast);
}
/**
* @package phptal.php
*/
class PHPTAL_Php_TalesChainExecutor
{
const CHAIN_BREAK = 1;
const CHAIN_CONT = 2;
public function __construct($generator, $chain, $reader)
{
assert(is_array($chain));
$this->_chain = $chain;
$this->_chainStarted = false;
$this->_chainGenerator = $generator;
$this->_reader = $reader;
$this->_executeChain();
}
public function doIf($condition)
{
if ($this->_chainStarted == false){
$this->_chainStarted = true;
$this->_chainGenerator->doIf($condition);
}
else {
$this->_chainGenerator->doElseIf($condition);
}
}
public function doElse()
{
if ($this->_chainStarted){
$this->_chainGenerator->doElse();
}
}
public function breakChain()
{
$this->_state = self::CHAIN_BREAK;
}
public function continueChain()
{
$this->_state = self::CHAIN_CONT;
}
private function _executeChain()
{
$this->_chainGenerator->noThrow(true);
end($this->_chain); $lastkey = key($this->_chain);
foreach ($this->_chain as $key => $exp){
$this->_state = 0;
if ($exp == PHPTAL_TALES_NOTHING_KEYWORD){
$this->_reader->talesChainNothingKeyword($this);
if ($this->_state == self::CHAIN_BREAK)
break;
if ($this->_state == self::CHAIN_CONT)
continue;
}
else if ($exp == PHPTAL_TALES_DEFAULT_KEYWORD){
$this->_reader->talesChainDefaultKeyword($this);
if ($this->_state == self::CHAIN_BREAK)
break;
if ($this->_state == self::CHAIN_CONT)
continue;
}
else {
$this->_reader->talesChainPart($this, $exp, $lastkey === $key);
if ($this->_state == self::CHAIN_BREAK)
break;
if ($this->_state == self::CHAIN_CONT)
continue;
}
}
$this->_chainGenerator->doEnd();
$this->_chainGenerator->noThrow(false);
}
private $_state = 0;
private $_chain;
private $_chainStarted = false;
private $_chainGenerator = null;
}
?>

View file

@ -1,331 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
// Moritz Bechler <mbechler@eenterphace.org>
//
require_once PHPTAL_DIR.'PHPTAL/TalesRegistry.php';
class PHPTAL_TalesInternal implements PHPTAL_Tales {
//
// This function registers all internal expression modifiers
//
static public function registerInternalTales() {
static $registered = false;
if($registered) {
return;
}
$registry = PHPTAL_TalesRegistry::getInstance();
$registry->registerPrefix('not', array(__CLASS__, 'not'));
$registry->registerPrefix('path', array(__CLASS__, 'path'));
$registry->registerPrefix('string', array(__CLASS__, 'string'));
$registry->registerPrefix('php', array(__CLASS__, 'php'));
$registry->registerPrefix('exists', array(__CLASS__, 'exists'));
$registry->registerPrefix('number', array(__CLASS__, 'number'));
$registry->registerPrefix('true', array(__CLASS__, 'true'));
$registered = true;
}
static public function true($src, $nothrow)
{
return sprintf('phptal_true($ctx, %s)', self::string(trim($src), $nothrow));
}
//
// not:
//
// not: Expression
//
// evaluate the expression string (recursively) as a full expression,
// and returns the boolean negation of its value
//
// return boolean based on the following rules:
//
// 1. integer 0 is false
// 2. integer > 0 is true
// 3. an empty string or other sequence is false
// 4. a non-empty string or other sequence is true
// 5. a non-value (e.g. void, None, Nil, NULL, etc) is false
// 6. all other values are implementation-dependent.
//
// Examples:
//
// not: exists: foo/bar/baz
// not: php: object.hasChildren()
// not: string:${foo}
// not: foo/bar/booleancomparable
//
static public function not($expression, $nothrow)
{
return '!(' . phptal_tales($expression, $nothrow) . ')';
}
//
// path:
//
// PathExpr ::= Path [ '|' Path ]*
// Path ::= variable [ '/' URL_Segment ]*
// variable ::= Name
//
// Examples:
//
// path: username
// path: user/name
// path: object/method/10/method/member
// path: object/${dynamicmembername}/method
// path: maybethis | path: maybethat | path: default
//
// PHPTAL:
//
// 'default' may lead to some 'difficult' attributes implementation
//
// For example, the tal:content will have to insert php code like:
//
// if (isset($ctx->maybethis)) {
// echo $ctx->maybethis;
// }
// else if (isset($ctx->maybethat) {
// echo $ctx->maybethat;
// }
// else {
// // process default tag content
// }
//
// @returns string or array
//
static public function path($expression, $nothrow=false)
{
$expression = trim($expression);
if ($expression == 'default') return PHPTAL_TALES_DEFAULT_KEYWORD;
if ($expression == 'nothing') return PHPTAL_TALES_NOTHING_KEYWORD;
if ($expression == '') return PHPTAL_TALES_NOTHING_KEYWORD;
// split OR expressions terminated by a string
if (preg_match('/^(.*?)\s*\|\s*?(string:.*)$/sm', $expression, $m)){
list(, $expression, $string) = $m;
}
// split OR expressions terminated by a 'fast' string
else if (preg_match('/^(.*?)\s*\|\s*\'((?:[^\'\\\\]|\\\\.)*)\'\s*$/sm', $expression, $m)){
list(, $expression, $string) = $m;
$string = 'string:'.stripslashes($string);
}
// split OR expressions
$exps = preg_split('/\s*\|\s*/sm', $expression);
// if (many expressions) or (expressions or terminating string) found then
// generate the array of sub expressions and return it.
if (count($exps) > 1 || isset($string)) {
$result = array();
foreach ($exps as $exp) {
$result[] = phptal_tales(trim($exp), true);
}
if (isset($string)){
$result[] = phptal_tales($string, true);
}
return $result;
}
// only one expression to process
// first evaluate ${foo} inside the expression and threat the expression
// as if it was a string to interpolate
$expression = self::string($expression);
$expression = substr($expression, 1, -1);
$pos = strpos($expression, '/');
// if no sub part for this expression, just optimize the generated code
// and access the $ctx->var
if ($pos === false) {
if (!self::checkExpressionPart($expression)) throw new PHPTAL_Exception("Invalid TALES path: '$expression', expected variable name");
return '$ctx->'.$expression;
}
// otherwise we have to call phptal_path() to resolve the path at runtime
// extract the first part of the expression (it will be the phptal_path()
// $base and pass the remaining of the path to phptal_path()
$next = substr($expression, 0, $pos);
$expression = substr($expression, $pos+1);
if (!self::checkExpressionPart($next)) throw new PHPTAL_Exception("Invalid TALES path: '$next/$expression', expected '$next' to be variable name");
// return php code invoking phptal_path($next, $expression, $notrhow)
return 'phptal_path($ctx->'.$next.', \''.$expression.'\''.($nothrow ? ', true' : '').')';
}
private static function checkExpressionPart($expression)
{
return preg_match('/^(\$?[a-z_][a-z0-9_]*|{.*})$/i',$expression);
}
//
// string:
//
// string_expression ::= ( plain_string | [ varsub ] )*
// varsub ::= ( '$' Path ) | ( '${' Path '}' )
// plain_string ::= ( '$$' | non_dollar )*
// non_dollar ::= any character except '$'
//
// Examples:
//
// string:my string
// string:hello, $username how are you
// string:hello, ${user/name}
// string:you have $$130 in your bank account
//
static public function string($expression, $nothrow=false)
{
// This is a simple parser which evaluates ${foo} inside
// 'string:foo ${foo} bar' expressions, it returns the php code which will
// print the string with correct interpollations.
// Nothing special there :)
$inPath = false;
$inAccoladePath = false;
$lastWasDollar = false;
$result = '';
$len = strlen($expression);
for ($i=0; $i<$len; $i++) {
$c = $expression[$i];
switch ($c) {
case '$':
if ($lastWasDollar) {
$lastWasDollar = false;
}
else {
$lastWasDollar = true;
$c = '';
}
break;
case '\\':
$c = '\\\\';
break;
case '\'':
$c = '\\\'';
break;
case '{':
if ($lastWasDollar) {
$lastWasDollar = false;
$inAccoladePath = true;
$subPath = '';
$c = '';
}
break;
case '}':
if ($inAccoladePath) {
$inAccoladePath = false;
$subEval = self::path($subPath);
if (is_array($subEval)) {
$err = 'cannot use | operator in evaluated expressions';
throw new PHPTAL_Exception($err);
}
$result .= "'." . $subEval . ".'";
$subPath = '';
$lastWasDollar = false;
$c = '';
}
break;
default:
if ($lastWasDollar) {
$lastWasDollar = false;
$inPath = true;
$subPath = $c;
$c = '';
}
else if ($inAccoladePath) {
$subPath .= $c;
$c = '';
}
else if ($inPath) {
$t = strtolower($c);
if (($t >= 'a' && $t <= 'z') || ($t >= '0' && $t <= '9') || ($t == '_')){
$subPath .= $c;
$c = '';
}
else {
$inPath = false;
$subEval = self::path($subPath);
if (is_array($subEval)) {
$err = 'cannot use | operator in evaluated expressions';
throw new PHPTAL_Exception($err);
}
$result .= "'." . $subEval . ".'";
}
}
break;
}
$result .= $c;
}
if ($inPath){
$subEval = self::path($subPath);
if (is_array($subEval)){
$err = 'cannot use | operator in evaluated expressions';
throw new PHPTAL_Exception($err);
}
$result .= "'." . $subEval . ".'";
}
return '\''.$result.'\'';
}
/**
* php: modifier.
*
* Transform the expression into a regular PHP expression.
*/
static public function php($src)
{
require_once PHPTAL_DIR.'PHPTAL/Php/Transformer.php';
return PHPTAL_Php_Transformer::transform($src, '$ctx->');
}
/**
* exists: modifier.
*
* Returns the code required to invoke phptal_exists() on specified path.
*/
static public function exists($src, $nothrow)
{
return sprintf('phptal_exists($ctx, %s)', self::string(trim($src), $nothrow));
}
/**
* number: modifier.
*
* Returns the number as is.
*/
static public function number($src, $nothrow)
{
return trim($src);
}
}
?>

View file

@ -1,384 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* Tranform php: expressions into their php equivalent.
*
* This transformer produce php code for expressions like :
*
* - a.b["key"].c().someVar[10].foo()
* - (a or b) and (c or d)
* - not myBool
* - ...
*
* The $prefix variable may be changed to change the context lookup.
*
* example:
*
* $res = PHPTAL_Php_Transformer::transform('a.b.c[x]', '$ctx->');
* $res == '$ctx->a->b->c[$ctx->x]';
*
* @package phptal.php
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_Php_Transformer
{
const ST_NONE = 0;
const ST_STR = 1; // 'foo'
const ST_ESTR = 2; // "foo ${x} bar"
const ST_VAR = 3; // abcd
const ST_NUM = 4; // 123.02
const ST_EVAL = 5; // ${somevar}
const ST_MEMBER = 6; // abcd.x
const ST_STATIC = 7; // class::[$]static|const
const ST_DEFINE = 8; // @MY_DEFINE
public static function transform( $str, $prefix='$' )
{
//
// Here comes the good old state machine.
// TODO: benchmark this version and then benchmark a refactored version
// with states behaviour separated into methods, keep the fastest.
//
$len = strlen($str);
$state = self::ST_NONE;
$result = '';
$i = 0;
$inString = false;
$backslashed = false;
$instanceOf = false;
$eval = false;
for ($i = 0; $i <= $len; $i++) {
if ($i == $len) $c = "\0";
else $c = $str[$i];
switch ($state) {
// no state defined, just eat char and see what to do with it.
case self::ST_NONE:
// begin of eval without {
if ($c == '$' && $i < $len && self::isAlpha($str[$i+1])){
$state = self::ST_EVAL;
$mark = $i+1;
$result .= $prefix.'{';
}
// that an alphabetic char, then it should be the begining
// of a var
else if (self::isAlpha($c) || $c==='_') {
$state = self::ST_VAR;
$mark = $i;
}
// begining of double quoted string
else if ($c == '"') {
$state = self::ST_ESTR;
$mark = $i;
$inString = true;
}
// begining of single quoted string
else if ($c == '\'') {
$state = self::ST_STR;
$mark = $i;
$inString = true;
}
// closing a method, an array access or an evaluation
else if ($c == ')' || $c == ']' || $c == '}') {
$result .= $c;
// if next char is dot then an object member must
// follow
if ($i < $len-1 && $str[$i+1] == '.') {
$result .= '->';
$state = self::ST_MEMBER;
$mark = $i+2;
$i+=2;
}
}
// @ is an access to some defined variable
else if ($c == '@') {
$state = self::ST_DEFINE;
$mark = $i+1;
}
// character we don't mind about
else {
$result .= $c;
}
break;
// $xxx
case self::ST_EVAL:
if (!self::isVarNameChar($c)){
$result .= $prefix . substr($str, $mark, $i-$mark);
$result .= '}';
$state = self::ST_NONE;
}
break;
// single quoted string
case self::ST_STR:
if ($c == '\\') {
$backslashed = true;
}
else if ($backslashed) {
$backslashed = false;
}
// end of string, back to none state
else if ($c == '\'') {
$result .= substr( $str, $mark, $i-$mark+1 );
$inString = false;
$state = self::ST_NONE;
}
break;
// double quoted string
case self::ST_ESTR:
if ($c == '\\') {
$backslashed = true;
}
else if ($backslashed) {
$backslashed = false;
}
// end of string, back to none state
else if ($c == '"') {
$result .= substr( $str, $mark, $i-$mark+1 );
$inString = false;
$state = self::ST_NONE;
}
// instring interpolation, search } and transform the
// interpollation to insert it into the string
else if ($c == '$' && $i < $len && $str[$i+1] == '{') {
$result .= substr( $str, $mark, $i-$mark ) . '{';
$sub = 0;
for ($j = $i; $j<$len; $j++) {
if ($str[$j] == '{') {
$sub++;
}
elseif ($str[$j] == '}' && (--$sub) == 0) {
$part = substr( $str, $i+2, $j-$i-2 );
$result .= self::transform($part, $prefix);
$i = $j;
$mark = $i;
}
}
}
break;
// var state
case self::ST_VAR:
if (self::isVarNameChar($c)) {
}
// end of var, begin of member (method or var)
else if ($c == '.') {
$result .= $prefix . substr( $str, $mark, $i-$mark );
$result .= '->';
$state = self::ST_MEMBER;
$mark = $i+1;
}
// static call, the var is a class name
else if ($c == ':') {
$result .= substr( $str, $mark, $i-$mark+1 );
$mark = $i+1;
$i++;
$state = self::ST_STATIC;
break;
}
// function invocation, the var is a function name
else if ($c == '(') {
$result .= substr( $str, $mark, $i-$mark+1 );
$state = self::ST_NONE;
}
// array index, the var is done
else if ($c == '[') {
if ($str[$mark]==='_') { // superglobal?
$result .= '$' . substr( $str, $mark, $i-$mark+1 );
}
else {
$result .= $prefix . substr( $str, $mark, $i-$mark+1 );
}
$state = self::ST_NONE;
}
// end of var with non-var-name character, handle keywords
// and populate the var name
else {
$var = substr( $str, $mark, $i-$mark );
$low = strtolower($var);
// boolean and null
if ($low == 'true' || $low == 'false' || $low == 'null') {
$result .= $var;
}
// lt, gt, ge, eq, ...
else if (array_key_exists($low, self::$TranslationTable)){
$result .= self::$TranslationTable[$low];
}
// instanceof keyword
else if ($low == 'instanceof'){
$result .= $var;
$instanceOf = true;
}
// previous was instanceof
else if ($instanceOf){
// last was instanceof, this var is a class name
$result .= $var;
$instanceOf = false;
}
// regular variable
else {
$result .= $prefix . $var;
}
$i--;
$state = self::ST_NONE;
}
break;
// object member
case self::ST_MEMBER:
if (self::isVarNameChar($c)) {
}
// eval mode ${foo}
else if ($c == '$') {
$result .= '{' . $prefix;
$mark++;
$eval = true;
}
// end of var member var, begin of new member
else if ($c == '.') {
$result .= substr( $str, $mark, $i-$mark );
if ($eval) { $result .='}'; $eval = false; }
$result .= '->';
$mark = $i+1;
$state = self::ST_MEMBER;
}
// begin of static access
else if ($c == ':') {
$result .= substr( $str, $mark, $i-$mark+1 );
if ($eval) { $result .='}'; $eval = false; }
$state = self::ST_STATIC;
break;
}
// the member is a method or an array
else if ($c == '(' || $c == '[') {
$result .= substr( $str, $mark, $i-$mark+1 );
if ($eval) { $result .='}'; $eval = false; }
$state = self::ST_NONE;
}
// regular end of member, it is a var
else {
$result .= substr( $str, $mark, $i-$mark );
if ($eval) { $result .='}'; $eval = false; }
$state = self::ST_NONE;
$i--;
}
break;
// wait for separator
case self::ST_DEFINE:
if (self::isVarNameChar($c)) {
}
else {
$state = self::ST_NONE;
$result .= substr( $str, $mark, $i-$mark );
$i--;
}
break;
// static call, can be const, static var, static method
// Klass::$static
// Klass::const
// Kclass::staticMethod()
//
case self::ST_STATIC:
if (self::isVarNameChar($c)) {
}
// static var
else if ($c == '$') {
}
// end of static var which is an object and begin of member
else if ($c == '.') {
$result .= substr( $str, $mark, $i-$mark );
$result .= '->';
$mark = $i+1;
$state = self::ST_MEMBER;
}
// end of static var which is a class name
else if ($c == ':') {
$result .= substr( $str, $mark, $i-$mark+1 );
$state = self::ST_STATIC;
break;
}
// static method or array
else if ($c == '(' || $c == '[') {
$result .= substr( $str, $mark, $i-$mark+1 );
$state = self::ST_NONE;
}
// end of static var or const
else {
$result .= substr( $str, $mark, $i-$mark );
$state = self::ST_NONE;
$i--;
}
break;
// numeric value
case self::ST_NUM:
if (!self::isDigitCompound($c)) {
$result .= substr( $str, $mark, $i-$mark );
$state = self::ST_NONE;
}
break;
}
}
return trim($result);
}
private static function isAlpha($c)
{
$c = strtolower($c);
return $c >= 'a' && $c <= 'z';
}
private static function isDigitCompound($c)
{
return ($c >= '0' && $c <= '9' || $c == '.');
}
private static function isVarNameChar($c)
{
return self::isAlpha($c) || ($c >= '0' && $c <= '9') || $c == '_';
}
private static $TranslationTable = array(
'not' => '!',
'ne' => '!=',
'and' => '&&',
'or' => '||',
'lt' => '<',
'gt' => '>',
'ge' => '>=',
'le' => '<=',
'eq' => '==',
);
}
?>

View file

@ -1,477 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* Stores tal:repeat information during template execution.
*
* An instance of this class is created and stored into PHPTAL context on each
* tal:repeat usage.
*
* repeat/item/index
* repeat/item/number
* ...
* are provided by this instance.
*
* 'repeat' is an StdClass instance created to handle RepeatControllers,
* 'item' is an instance of this class.
*
* @package phptal
* @author Laurent Bedubourg <lbedubourg@motion-twin.com>
*/
class PHPTAL_RepeatController implements Iterator
{
private $key;
private $current;
private $valid;
private $validOnNext;
protected $iterator;
protected $index;
protected $end;
protected $length;
/**
* Construct a new RepeatController.
*
* @param $source array, string, iterator, iterable.
*/
public function __construct($source)
{
if ( is_string($source) ) {
$this->iterator = new ArrayIterator( str_split($source) ); // FIXME: invalid for UTF-8 encoding, use preg_match_all('/./u') trick
} else if ( is_array($source) ) {
$this->iterator = new ArrayIterator($source);
} else if ( $source instanceof IteratorAggregate ) {
$this->iterator = $source->getIterator();
} else if ( $source instanceof Iterator ) {
$this->iterator = $source;
} else if ( $source instanceof SimpleXMLElement) { // has non-unique keys!
$array = array();
foreach ( $source as $v ) {
$array[] = $v;
}
$this->iterator = new ArrayIterator($array);
} else if ( $source instanceof Traversable || $source instanceof DOMNodeList ) {
// PDO Statements for example implement the engine internal Traversable
// interface. To make it fully iterable we traverse the set to populate
// an array which will be actually used for iteration.
$array = array();
foreach ( $source as $k=>$v ) {
$array[$k] = $v;
}
$this->iterator = new ArrayIterator($array);
} else {
$this->iterator = new ArrayIterator( array() );
}
// Try to find the set length
$this->length = 0;
if ( $this->iterator instanceof Countable ) {
$this->length = count($this->iterator);
} else if ( is_object($this->iterator) ) {
// This should be removed since there is already the Countable interface in PHP5
if ( method_exists( $this->iterator, 'size' ) ) {
$this->length = $this->iterator->size();
} else if ( method_exists( $this->iterator, 'length' ) ) {
$this->length = $this->iterator->length();
}
}
$this->groups = new PHPTAL_RepeatController_Groups();
$this->rewind();
}
/**
* Returns the current element value in the iteration
*
* @return Mixed The current element value
*/
public function current()
{
return $this->current;
}
/**
* Returns the current element key in the iteration
*
* @return String/Int The current element key
*/
public function key()
{
return $this->key;
}
/**
* Tells if the iteration is over
*
* @return bool True if the iteration is not finished yet
*/
public function valid()
{
$valid = $this->valid || $this->validOnNext;
$this->validOnNext = $this->valid;
return $valid;
}
/**
* Restarts the iteration process going back to the first element
*
*/
public function rewind()
{
$this->index = 0;
$this->end = false;
$this->iterator->rewind();
// Prefetch the next element
if ( $this->iterator->valid() ) {
$this->validOnNext = true;
$this->prefetch();
} else {
$this->validOnNext = false;
}
// Notify the grouping helper of the change
$this->groups->reset();
}
/**
* Fetches the next element in the iteration and advances the pointer
*
*/
public function next()
{
$this->index++;
// Prefetch the next element
$this->prefetch();
// Notify the grouping helper of the change
$this->groups->reset();
}
/**
* Gets an object property
*
* @return $var Mixed The variable value
*/
public function __get( $var )
{
switch ( $var ) {
case 'index':
case 'end':
case 'length':
return $this->$var;
case 'number':
return $this->index + 1;
case 'start':
return $this->index === 0;
case 'even':
return ($this->index % 2) === 0;
case 'odd':
return ($this->index % 2) === 1;
case 'key':
return $this->key();
case 'letter':
return strtolower( $this->int2letter($this->index+1) );
case 'Letter':
return strtoupper( $this->int2letter($this->index+1) );
case 'roman':
return strtolower( $this->int2roman($this->index+1) );
case 'Roman':
return strtoupper( $this->int2roman($this->index+1) );
case 'first':
// Compare the current one with the previous in the dictionary
$res = $this->groups->first( $this->current );
return is_bool($res) ? $res : $this->groups;
case 'last':
// Compare the next one with the dictionary
$res = $this->groups->last( $this->iterator->current() );
return is_bool($res) ? $res : $this->groups;
default:
throw new PHPTAL_Exception( "Unable to find part '$var' in repeater controller" );
}
}
/**
* Fetches the next element from the source data store and
* updates the end flag if needed.
*
* @access protected
*/
protected function prefetch()
{
$this->valid = true;
$this->key = $this->iterator->key();
$this->current = $this->iterator->current();
$this->iterator->next();
if ( !$this->iterator->valid() ) {
$this->valid = false;
$this->end = true;
}
}
/**
* Converts an integer number (1 based) to a sequence of letters
*
* @param $int Int The number to convert
* @return String The letters equivalent as a, b, c-z ... aa, ab, ac-zz ...
* @access protected
*/
protected function int2letter( $int )
{
$lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$size = strlen($lookup);
$letters = '';
while ( $int > 0 ) {
$int--;
$letters = $lookup[$int % $size] . $letters;
$int = floor($int / $size);
}
return $letters;
}
/**
* Converts an integer number (1 based) to a roman numeral
*
* @param $int Int The number to convert
* @return String The roman numeral
* @access protected
*/
protected function int2roman( $int )
{
$lookup = array(
'1000' => 'M',
'900' => 'CM',
'500' => 'D',
'400' => 'CD',
'100' => 'C',
'90' => 'XC',
'50' => 'L',
'40' => 'XL',
'10' => 'X',
'9' => 'IX',
'5' => 'V',
'4' => 'IV',
'1' => 'I',
);
$roman = '';
foreach ( $lookup as $max => $letters ) {
while ( $int >= $max ) {
$roman .= $letters;
$int -= $max;
}
}
return $roman;
}
}
/**
* Keeps track of variable contents when using grouping in a path (first/ and last/)
*
* @package phptal
* @author Ivбn Montes <drslump@pollinimini.net>
*/
class PHPTAL_RepeatController_Groups {
protected $dict = array();
protected $cache = array();
protected $data = null;
protected $vars = array();
protected $branch;
public function __construct()
{
$this->dict = array();
$this->reset();
}
/**
* Resets the result caches. Use it to signal an iteration in the loop
*
*/
public function reset()
{
$this->cache = array();
}
/**
* Checks if the data passed is the first one in a group
*
* @param $data Mixed The data to evaluate
* @return Mixed True if the first item in the group, false if not and
* this same object if the path is not finished
*/
public function first( $data )
{
if ( !is_array($data) && !is_object($data) && !is_null($data) ) {
if ( !isset($this->cache['F']) ) {
$hash = md5($data);
if ( !isset($this->dict['F']) || $this->dict['F'] !== $hash ) {
$this->dict['F'] = $hash;
$res = true;
} else {
$res = false;
}
$this->cache['F'] = $res;
}
return $this->cache['F'];
}
$this->data = $data;
$this->branch = 'F';
$this->vars = array();
return $this;
}
/**
* Checks if the data passed is the last one in a group
*
* @param $data Mixed The data to evaluate
* @return Mixed True if the last item in the group, false if not and
* this same object if the path is not finished
*/
public function last( $data )
{
if ( !is_array($data) && !is_object($data) && !is_null($data) ) {
if ( !isset($this->cache['L']) ) {
$hash = md5($data);
if (empty($this->dict['L'])) {
$this->dict['L'] = $hash;
$res = false;
} else if ( $this->dict['L'] !== $hash ) {
$this->dict['L'] = $hash;
$res = true;
} else {
$res = false;
}
$this->cache['L'] = $res;
}
return $this->cache['L'];
}
$this->data = $data;
$this->branch = 'L';
$this->vars = array();
return $this;
}
/**
* Handles variable accesses for the tal path resolver
*
* @param $var String The variable name to check
* @return Mixed An object/array if the path is not over or a boolean
*
* @todo replace the phptal_path() with custom code
*/
public function __get( $var )
{
// When the iterator item is empty we just let the tal
// expression consume by continuously returning this
// same object which should evaluate to true for 'last'
if ( is_null($this->data) ) {
return $this;
}
// Find the requested variable
$value = @phptal_path( $this->data, $var, true );
// Check if it's an object or an array
if ( is_array($value) || is_object($value) ) {
// Move the context to the requested variable and return
$this->data = $value;
$this->addVarName( $var );
return $this;
}
// get a hash of the variable contents
$hash = md5( $value );
// compute a path for the variable to use as dictionary key
$path = $this->branch . $this->getVarPath() . $var;
// If we don't know about this var store in the dictionary
if ( !isset($this->cache[$path]) ) {
if ( !isset($this->dict[$path]) ) {
$this->dict[$path] = $hash;
$res = $this->branch === 'F';
} else {
// Check if the value has changed
if ( $this->dict[$path] !== $hash ) {
$this->dict[$path] = $hash;
$res = true;
} else {
$res = false;
}
}
$this->cache[$path] = $res;
}
return $this->cache[$path];
}
/**
* Adds a variable name to the current path of variables
*
* @param $varname String The variable name to store as a path part
* @access protected
*/
protected function addVarName( $varname )
{
$this->vars[] = $varname;
}
/**
* Returns the current variable path separated by a slash
*
* @return String The current variable path
* @access protected
*/
protected function getVarPath()
{
return implode('/', $this->vars) . '/';
}
}

View file

@ -1,16 +0,0 @@
<?php
/**
* @package phptal
*/
interface PHPTAL_Source
{
/** Returns string, unique path identifying the template source. */
public function getRealPath();
/** Returns long, the template source last modified time. */
public function getLastModifiedTime();
/** Returns string, the template source. */
public function getData();
}
?>

View file

@ -1,16 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Source.php';
/**
* @package phptal
*/
interface PHPTAL_SourceResolver
{
/**
* Returns PHPTAL_Source or null.
*/
public function resolve($path);
}
?>

View file

@ -1,34 +0,0 @@
<?php
require_once PHPTAL_DIR.'PHPTAL/Source.php';
/**
* @package phptal
*/
class PHPTAL_StringSource implements PHPTAL_Source
{
public function __construct($data, $realpath)
{
$this->_data = $data;
$this->_realpath = $realpath;
}
public function getLastModifiedTime()
{
if (file_exists($this->_realpath))
return @filemtime($this->_realpath);
return 0;
}
public function getData()
{
return $this->_data;
}
public function getRealPath()
{
return $this->_realpath;
}
}
?>

View file

@ -1,7 +0,0 @@
<?php
interface PHPTAL_Tales
{
}
?>

View file

@ -1,109 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Moritz Bechler <mbechler@eenterphace.org>
//
require_once PHPTAL_DIR.'PHPTAL/Tales.php';
/**
* Global registry of TALES expression modifiers
*
*/
class PHPTAL_TalesRegistry {
static $instance;
static public function initialize() {
self::$instance = new PHPTAL_TalesRegistry();
}
/**
* Enter description here...
*
* @return PHPTAL_TalesRegistry
*/
static public function getInstance() {
if(!(self::$instance instanceof PHPTAL_TalesRegistry)) {
self::initialize();
}
return self::$instance;
}
protected function __construct() {
}
/**
*
* Expects an either a function name or an array of class and method as
* callback.
*
* @param unknown_type $prefix
* @param unknown_type $callback
*/
public function registerPrefix($prefix, $callback) {
if($this->isRegistered($prefix)) {
throw new PHPTAL_Exception(sprintf('Expression modifier "%s" is already registered.',$prefix));
}
// Check if valid callback
if(is_array($callback)) {
$class = new ReflectionClass($callback[0]);
if(!$class->isSubclassOf('PHPTAL_Tales')) {
throw new PHPTAL_Exception('The class you want to register does not implement "PHPTAL_Tales".');
}
$method = new ReflectionMethod($callback[0], $callback[1]);
if(!$method->isStatic()) {
throw new PHPTAL_Exception('The method you want to register is not static.');
}
// maybe we want to check the parameters the method takes
} else {
if(!function_exists($callback)) {
throw new PHPTAL_Exception('The function you are trying to register does not exist.');
}
}
$this->_callbacks[$prefix] = $callback;
}
public function isRegistered($prefix) {
return (array_key_exists($prefix, $this->_callbacks));
}
public function getCallback($prefix) {
if(!$this->isRegistered($prefix)) {
throw new PHPTAL_Exception(sprintf('Expression modifier "%s" is not registered.', $prefix));
}
return $this->_callbacks[$prefix];
}
private $_callbacks = array();
}
?>

View file

@ -1,41 +0,0 @@
<?php
/**
* @package phptal
*/
interface PHPTAL_TranslationService
{
/**
* Set the target language for translations.
*
* When set to '' no translation will be done.
*
* You can specify a list of possible language for exemple :
*
* setLanguage('fr_FR', 'fr_FR@euro')
*/
function setLanguage();
/**
* PHPTAL will inform translation service what encoding page uses.
* Output of translate() must be in this encoding.
*/
function setEncoding($encoding);
/**
* Set the domain to use for translations.
*/
function useDomain($domain);
/**
* Set an interpolation var.
*/
function setVar($key, $value);
/**
* Translate a gettext key and interpolate variables.
*/
function translate($key, $htmlescape=true);
}
?>

View file

@ -1,36 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
//
// Copyright (c) 2004-2005 Laurent Bedubourg
//
// 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
//
// Authors: Laurent Bedubourg <lbedubourg@motion-twin.com>
//
/**
* @package phptal
*/
interface PHPTAL_Trigger
{
const SKIPTAG = 1;
const PROCEED = 2;
public function start($id, $tpl);
public function end($id, $tpl);
}
?>

View file

@ -20,5 +20,3 @@ class Adapter
} }
} }
} }
?>

View file

@ -78,5 +78,3 @@ class FileRecord
return isset($this->file['title']) ? $this->file['title'] : $this->getName(); return isset($this->file['title']) ? $this->file['title'] : $this->getName();
} }
} }
?>

View file

@ -1,583 +0,0 @@
<?php
require_once 'core/path.php';
require_once 'core/file.php';
interface IFileSystem
{
// Операции над файлами
public function makeDirectory($name);
public function deleteDirectory($name);
public function deleteFile($name);
public function renameFile($source, $destination);
public function copyFile($source, $destination);
public function moveUploadedFile($source, $destination);
// deleteDirectoryRecursive
public function isDir($name);
public function readFile($source);
public function writeFile($source, $content);
// Содержание директории
public function directoryFiles($name);
public function directoryFilesRecursive($name);
}
interface IFileControl
{
public function commitFile($name, $who, $message);
public function readFileVersion($name, $version = false);
// Информация о файле
public function getFileLog($name);
public function getFileInfo($name);
}
// Реальная файловая система
class FileSystem implements IFileSystem
{
protected $hidden = array('.', '..');
protected $visible = null;
public function __construct()
{
}
public function setVisibleFiles(array $visible)
{
$this->visible = $visible;
}
public function setHiddenFiles(array $hidden)
{
$this->hidden = array_merge($this->hidden, $hidden);
}
/**
*
*/
public function makeDirectory($name)
{
if (file_exists($name) === false) {
mkdir($name);
}
}
/**
*
*/
public function makeFile($name)
{
if (file_exists($name) === false) {
file_put_contents($name, '');
}
}
/**
*
*/
public function deleteDirectory($name)
{
rmdir($name);
}
/**
*
*/
public function deleteDirectoryRecursive($name)
{
if ($handle = opendir($name)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
$sf = $name . DIRECTORY_SEPARATOR . $file;
if (is_dir($sf) && !is_link($sf)) {
self::deleteDirectoryRecursive($sf);
} else {
unlink($sf);
}
}
}
closedir($handle);
@rmdir($name);
}
}
/**
*
*/
public function deleteFile($name)
{
if (file_exists($name)) {
unlink($name);
}
}
// При перемещении или все файлы если есть совпадения переписываются
/**
*
*/
public function renameFile($source, $destination)
{
rename($source, $destination);
}
/**
*
*/
public function copyFile($source, $destination)
{
copy($source, $destination);
}
/**
*
*/
public function copyDirectory($source, $destination)
{
if (is_dir($source)) {
if (! file_exists($destination)) mkdir($destination);
$handle = opendir($source);
while (false !== ($file = readdir($handle))) {
$entry = $source . DIRECTORY_SEPARATOR . $file;
if (is_dir($entry)) {
self::copyDirectory($entry, $destination . DIRECTORY_SEPARATOR . $file);
} else {
copy($entry, $destination . DIRECTORY_SEPARATOR . $file);
}
}
}
}
/**
*
*/
public function moveUploadedFile($source, $destination)
{
move_uploaded_file($source, $destination);
}
/**
*
*/
public function isVisible($file)
{
if (in_array(basename($file), $this->hidden) === true) {
return false;
}
return ($this->isDir($file) || $this->visible == null) || in_array(pathinfo($file, PATHINFO_EXTENSION), $this->visible);
}
/**
*
*/
public function directoryFiles($name)
{
$result = array();
$files = scandir($name);
foreach ($files as $file) {
$fullname = $name . DIRECTORY_SEPARATOR . $file;
if ($this->isVisible($fullname)) {
$result [$file] = new FileRecord(array(), $fullname);
}
}
return $result;
}
/**
*
*/
public function readFile($name)
{
return file_get_contents($name);
}
/**
*
*/
public function writeFile($name, $content)
{
file_put_contents($name, $content);
}
/**
*
*/
public function directoryFilesRecursive($name)
{
}
function isDir($name)
{
return is_dir($name);
}
}
// То что хранится в базе данных
class EFileSystem implements IFileSystem, IFileControl
{
protected $basepath;
protected $db;
public function __construct($basepath, $db, $fs)
{
$this->basepath = $basepath;
$this->db = $db;
$this->fs = $fs;
}
/*function createExtendRecord($index)
{
static $fileSQL = "INSERT INTO file (id_record) VALUES (?)";
$query = $this->db->prepareStatement($fileSQL);
$query->setString(1, $index);
$query->executeQuery();
}*/
private function createRecord($name, $type, $path)
{
static $recordSQL = "INSERT INTO files (filename, idfile, lastrevdate, filepath, filetype) VALUES (?, ?, ?, ?, ?)";
$last = $this->db->getIdGenerator();
$index = $last->getId('files_idfile_seq');
$query = $this->db->prepareStatement($recordSQL);
$query->setString(1, $name);
$query->setInt(2, $index);
$query->setInt(3, 0);
$query->setString(4, $path);
$query->setString(5, $type);
$query->executeQuery();
/*if ($type == 0) {
$this->createExtendRecord($index);
}*/
return $index;
}
function setVisibleFiles(array $visible)
{
$this->fs->setVisibleFiles($visible);
}
function setHiddenFiles(array $hidden)
{
$this->fs->setHiddenFiles($hidden);
}
public function getFullPath($name)
{
return Path::join($this->basepath, $name);
}
private function getRecordId($name, $path)
{
static $recordSQL = "SELECT idfile FROM files WHERE filename = ? AND filepath = ?";
$query = $this->db->prepareStatement($recordSQL);
$query->setString(1, $name);
$query->setString(2, $path);
$result = $query->executeQuery();
if ($result->next()) {
$index = $result->getInt('idfile');
return $index;
}
return false; // Может лучше кидать исключение ??
}
function getIdFromPath($name)
{
return $this->getRecordId(basename($name), self::getPathName($name));
}
// Создание новой директории
public function makeDirectory($name)
{
$path = new Path($name);
$fullpath = $this->basepath;
$temp_path = '';
foreach ($path->getParts() as $subpath)
{
$index = $this->getRecordId($subpath, $temp_path);
if ($index === false) {
$index = $this->createRecord($subpath, 1, $temp_path);
}
$temp_path = Path::join($temp_path, $subpath);
}
$this->fs->makeDirectory($this->getFullPath($name));
}
public function isDir($name)
{
return $this->fs->isDir($this->getFullPath($name));
}
// Переименование файла или директории все изменения должны записываться в базу чтобы можно было сделать отмену !!!
public function renameFile($source, $destination)
{
// При перемещении файлы могут совпадать
$stmt = $this->db->prepareStatement('UPDATE files SET filepath = ?, filename = ? WHERE filepath = ? AND filename = ?');
$stmt->setString(1, self::getPathName($destination));
$stmt->setString(2, basename($destination));
$stmt->setString(3, self::getPathName($source));
$stmt->setString(4, basename($source));
$stmt->executeQuery();
if ($this->isDir($source)) {
$length = strlen($from) + 1;
$stmt = $this->db->prepareStatement("UPDATE file
SET filepath = '?' || substr(filepath, ?) WHERE filepath LIKE (?) OR filepath LIKE (? || '/%')");
$stmt->setString(1, $destination);
$stmt->setInt(2, $length);
$stmt->setString(3, $source);
$stmt->setString(4, $source);
}
$this->fs->renameFile($this->getFullPath($source), $this->getFullPath($destination));
}
// Копирование файла или директории
public function copyFile($source, $destination)
{
// При копировании файлы могут совпадать
$stmt = $this->db->prepareStatement('INSERT INTO files (filepath, filename, lastrevdate) VALUES (?, ?, ?)');
$stmt->setString(1, self::getPathName($destination));
$stmt->setString(2, basename($destination));
$stmt->setString(3, time());
$stmt->executeQuery();
if ($this->isDir($source)) {
$stmt = $this->db->prepareStatement("INSERT INTO files (filepath, filename, lastrevdate)
SELECT '?' || substr(filepath, ?) AS filepath, filename, lastrevdate WHERE WHERE filepath LIKE (?) OR filepath LIKE (? || '/%')");
$stmt->setString(1, $destination);
$stmt->setInt(2, $length);
$stmt->setString(3, $source);
$stmt->setString(4, $source);
}
$this->fs->copyFile($this->getFullPath($source), $this->getFullPath($destination));
}
private function getPathName($name)
{
$path = dirname($name);
return ($path == '.') ? '' : $path;
}
public function makeFile($name)
{
$base = self::getPathName($name);
$this->makeDirectory($base);
$filename = basename($name);
$index = $this->getRecordId($filename, $base);
if ($index === false) {
$index = $this->createRecord($filename, 0, $base);
}
$this->fs->makeFile($this->getFullPath($name));
}
public function readFile($name)
{
return $this->fs->readFile($this->getFullPath($name));
}
public function readFileVersion($name, $revision = false)
{
if ($revision === false) {
return $this->readFile($name);
} else {
$id_file = $this->getIdFromPath($name);
$query = $this->db->prepareStatement("SELECT * FROM history WHERE revision = ? AND idfile = ?");
$query->setInt(1, $revision);
$query->setInt(2, $id_file);
$file = $query->executeQuery();
if ($file->next()) {
return gzuncompress($file->getBlob('content'));
}
}
return null;
}
public function writeFile($name, $content)
{
$this->makeFile($name);
$this->fs->writeFile($this->getFullPath($name), $content);
}
public function getLastRevision($name)
{
$id_file = $this->getIdFromPath($name);
$stmt = $this->db->prepareStatement("SELECT * FROM history WHERE revision IN (SELECT MAX(revision) AS lastrev FROM history WHERE idfile = ?)");
$stmt->setInt(1, $id_file);
$rev = $stmt->executeQuery();
if ($rev->next()) {
return $rev;
}
return false;
}
/**
*
*/
public function commitFile($name, $owner, $message)
{
$id_file = $this->getIdFromPath($name);
$content = $this->readFile($name);
$stmt = $this->db->prepareStatement("SELECT MAX(revision) AS lastrev FROM history WHERE idfile = ?");
$stmt->setInt(1, $id_file);
$rev = $stmt->executeQuery();
$revision = ($rev->next()) ? $rev->getInt('lastrev') + 1 : 1;
$query = $this->db->prepareStatement("INSERT INTO history (content, owner, revsummary, revdate, revision, idfile) VALUES (?, ?, ?, ?, ?, ?)");
$query->setBlob(1, gzcompress($content));
$query->setString(2, $owner);
$query->setString(3, $message);
$query->setInt(4, time());
$query->setInt(5, $revision);
$query->setInt(6, $id_file);
$query->executeQuery();
}
/**
*
*/
public function getFileDifference($name, $revision1, $revision2 = false)
{
$first = $this->readFileVersion($name, $revision1);
$second = $this->readFileVersion($name, $revision2);
}
/**
*
*/
public function getFileLog($name)
{
$id_file = $this->getIdFromPath($name);
$query = $this->db->prepareStatement("SELECT revision,revsummary,owner,revdate FROM history WHERE idfile = ? ORDER BY revision");
$query->setInt(1, $id_file);
$list = $query->executeQuery();
return iterator_to_array($list->getIterator());
}
public function directoryFiles($name)
{
$result = $this->fs->directoryFiles($this->getFullPath($name));
/* Список файлов из базы данных */
$query = $this->db->prepareStatement("SELECT * FROM files WHERE filepath = ?");
$query->setString(1, $name);
$list = $query->executeQuery();
foreach ($list as $file) {
$fullpath = $this->getFullPath($name . DIRECTORY_SEPARATOR . $file['filename']);
if ($this->fs->isVisible($fullpath)) {
$file['state'] =
((isset($result[$file['filename']])) ?
(($file['lastrevdate'] > $file['change']) ? 'exclamation' : 'unchanged')
: 'expected');
$record = new FileRecord($file, $fullpath);
$result [$file['filename']] = $record;
}
}
return $result;
}
public function getFileInfo($name)
{
$index = $this->getIdFromPath($name);
$fullpath = $this->basepath . DIRECTORY_SEPARATOR . $name;
if ($index !== false) {
$query = $this->db->prepareStatement("SELECT * FROM files AS r LEFT JOIN filemeta AS f ON r.idfile = f.id_record WHERE r.idfile = ?");
$query->setInt(1, $index);
$list = $query->executeQuery();
$list->next();
$file = $list->getRow();
$file['state'] = (file_exists($fullpath) ? 'unchanged' : 'expected');
$result = new FileRecord($file, $fullpath);
} else {
$result = new FileRecord(array(), $fullpath);
}
return $result;
}
public function setFileInfo($name, Collection $list)
{
$index = $this->getIdFromPath($name);
if ($index !== false) {
$stmt = $this->db->prepareStatement("UPDATE files SET title = ? WHERE idfile = ?");
$stmt->setString(1, $list->get('title'));
$stmt->setInt(2, $index);
$stmt->executeQuery();
/*if (some($list, array('keywords', 'author', 'description'))) {
$hasfile = $this->db->executeQuery("SELECT * FROM file WHERE id_record = $index");
if(!$hasfile->next()) {
static $fileSQL = "INSERT INTO file (id_record) VALUES (?)";
$query = $this->db->prepareStatement($fileSQL);
$query->setString(1, $index);
$query->executeQuery();
}
$query = $this->db->prepareStatement("UPDATE file SET keywords = ?, author = ?, description = ? WHERE id_record = ?");
$query->setString(1, $list->get('keywords'));
$query->setString(2, $list->get('author'));
$query->setString(3, $list->get('description'));
$query->setInt(4, $index);
$query->executeQuery();
}*/
}
}
/**
* Удаляем директорию если она не пустая
*/
function deleteDirectory($name)
{
$index = $this->getIdFromPath($name);
$query = $this->db->prepareStatement("SELECT COUNT(*) AS col FROM files WHERE filepath = (?) OR filepath LIKE(? || '/%')");
$query->setString(1, $name);
$query->setString(2, $name);
$result = $query->executeQuery();
$result->next();
if ($index && $result->getInt('col') == 0) {
$query = $this->db->prepareStatement("DELETE FROM files WHERE idfile = ?");
$query->setInt(1, $index);
$query->executeQuery();
}
$this->fs->deleteDirectory($this->getFullPath($name));
}
function deleteFile($name)
{
$index = $this->getIdFromPath($name);
if ($index) {
$query = $this->db->prepareStatement("DELETE FROM history WHERE idfile = ?;
DELETE FROM filemeta WHERE id_record = ?;DELETE FROM files WHERE idfile = ?");
$query->setInt(1, $index);
$query->setInt(2, $index);
$query->setInt(3, $index);
$query->executeQuery();
}
$this->fs->deleteFile($this->getFullPath($name));
}
function moveUploadedFile($source, $destination)
{
$this->fs->moveUploadedFile($source, $this->getFullPath($destination));
$this->makeFile($destination);
}
function directoryFilesRecursive($name)
{
$files = $this->fs->directoryFilesRecursive($this->getFullPath($name));
$query = $this->db->prepareStatement("DELETE FROM files WHERE filepath = (?) OR filepath LIKE (? || '/%')");
$query->setString(1, $name);
$query->setString(2, $name);
$query->executeQuery();
}
}

View file

@ -1,335 +0,0 @@
<?php
/**
* Deprecated !!!!
*/
require_once 'core/adapter.php';
/**
* Новое API для Форм
* $form = new Form ();
* $form->render () -> html,
* $form->adjust ($scheme);
* $form->input ($name, $type, $label, );
* $form->set($name, $value);
* $form->get($name); -> value
* $form->parse ($request),
* $form->validate () -> boolean,
* $form->values () -> pair[key] = value
*/
/**
* Элемент формы
* @package core
*/
class TField {
protected $_value; // Форматированное значение поля
var $label; // Метка поля
var $rule = array ();// Правила для проверки поля
var $value; // Форматированное Значение поля
// var $default; // Значение по умолчанию
var $error = false; // в XRule Правила для проверки значений
var $error_msg = "Поле не может быть пустым";
var $type; // Каждому типу элемента соответствует макрос TAL
public function __construct ($input) {
// $this->deafult = null;
$this->require = false;
// Инициализация свойст обьетка
foreach ($input as $key => $value) {
$this->$key = $value;
}
}
public function __toString () {
return $this->value;
}
public function isValid ($name) {
if ($this->require == true && empty($this->value)) {
$this->error = true;
return false;
}
$this->setValue ($this->value);
return true;
}
// Добавить методы getString, setString ??
function setValue ($value) {
$this->_value = $value;
$this->value = $value;
}
function getValue () {
return $this->_value;
}
}
/**
* Поле ввода Input
* @package core
*/
class TInput extends TField {
public function __construct ($input) {
parent::__construct ($input);
$this->setValue ("");
}
}
// checkbox
class TCheckbox extends TField {
public $checked = false;
public function __construct ($input) {
parent::__construct ($input);
$this->setValue (1);
}
function setValue ($value) {
$this->_value = intval ($value);
$this->value = 1;
if ($this->_value == 1) $this->checked = true; else $this->checked = false;
}
}
/**
* Выбор из одного элемента
*/
class TSelect1 extends TField {
var $options = array ();
public function __construct ($input) {
parent::__construct ($input);
$this->setValue (0);
}
function setValue ($value) {
$this->_value = $value;
$this->value = $value;
foreach ($this->options as $key => $o) {
$this->options[$key]['selected'] = ($this->options[$key]['value'] == $this->_value);
}
}
}
class TSelectGroup extends TField {
var $groups = array ();
public function __construct ($input) {
parent::__construct ($input);
$this->setValue (0);
}
function setValue ($value) {
$this->_value = $value;
$this->value = $value;
foreach ($this->groups as $gkey => $o) {
foreach ($this->groups[$gkey]['options'] as $key => $v) {
$this->groups[$gkey]['options'][$key]['selected'] = ($this->groups[$gkey]['options'][$key]['value'] == $this->_value);
}
}
}
}
/**
* Поле с датой
* @package core
*/
class TDate extends TField {
var $error_msg = "Неверный формат даты";
var $separator = ".";
public function __construct ($input) {
parent::__construct ($input);
$this->setValue (time ());
}
function isValid ($name) {
$value = $this->value;
if ($tmp = explode(".", $value, 3)) {
if ($tmp[1] && $tmp[0] && $tmp[2]) {
if (checkdate ($tmp[1], $tmp[0], $tmp[2])) {
$this->setValue (mktime (0, 0, 0, $tmp[1], $tmp[0], $tmp[2]));
return true;
}
}
}
$this->error = true;
return false;
}
function setValue ($value) {
$this->_value = $value;
$this->value = date ("d.m.Y", $value);
}
}
class TTime extends TField {
var $error_msg = "Неверный формат времени";
public function __construct ($input) {
parent::__construct ($input);
$this->setValue (mktime(0, 0, 0, 11, 30, 1999));
}
function isValid ($name) {
$value = $this->value;
if ($tmp = explode(":", $value, 2)) {
if ($this->checktime ($tmp[0], $tmp[1])) {
$this->setValue (mktime ($tmp[0], $tmp[1], 0, 0, 0, 0));
return true;
}
}
$this->error = true;
return false;
}
function checktime($hour, $minute) {
if ($hour > -1 && $hour < 24 && $minute > -1 && $minute < 60) {
return true;
}
}
function setValue ($value) {
$this->_value = $value;
$this->value = date ("H:i", $value);
}
}
/* *
* Текстовое поле
* @package core
*/
class TTextArea extends TField {
public function __construct ($input) {
parent::__construct ($input);
$this->setValue ("");
}
}
/**
* Поле для ввода пароля
* @package core
*/
class TSecret extends TField {
public function __construct ($input) {
parent::__construct ($input);
$this->setValue ("");
}
}
class TUpload extends TField {
public $types = array ();
public function __construct ($input) {
parent::__construct ($input);
$this->setValue ("");
}
public function setValue ($value) {
$this->_value = basename ($value);
$this->value = $value;
}
}
/**
* Форма для ввода
* @package core
*/
class TForm {
var $field = array ();
var $action = "";
var $method = 'post';
var $request;
var $replace;
public function __construct ($request) {
$this->uid = get_form_uid ();
$this->constructor = array (
'input' => 'TInput',
'checkbox' => 'TCheckbox',
'date' => 'TDate',
'time' => 'TTime',
'textarea' => 'TTextArea',
'select' => 'TSelect',
'select1' => 'TSelect1',
'selgroup' => 'TSelectGroup',
'secret' => 'TSecret',
'upload' => 'TUpload'
);
$this->request = $request;
}
function get ($name) {
return $this->field [$name]->getValue ();
}
function addFieldObject ($name, $el) {
$this->field [$name] = $el;
}
/**
* Метод должен проверять значения полей формы полсле заполнения
* Проверка правильности заполнения формы и установка значений
*/
function isValid () {
$haveErrors = false;
foreach ($this->field as $name => $el) { // ссылка
if ($this->field [$name] instanceof TUpload) {
// print_r ($_POST);
$filename = $this->request->getRawData ('files', $name);
if ((bool) $filename['name']) {
$this->field [$name]->value = $filename['name'];
} else {
$this->field [$name]->value = $this->request->getRawData ($this->method, $name."_file");
}
} else {
$this->field [$name]->value = $this->request->getRawData ($this->method, $name);
}
if (!$this->field [$name]->isValid($name)) {
$haveErrors = true;
}
}
return !$haveErrors;
}
/**
* Добавляет одно поле ввода на форму
*/
public function addField ($init) {
assert ($init['type']);
assert ($init['name']);
$constructor = $this->constructor[$init['type']];
$el = new $constructor ($init);
$el->type = $init['type'];
$this->addFieldObject ($init['name'], $el);
return $el;
}
/**
* Добавляет спсок полей для формы
* @param array $list
*/
public function addFieldList ($list) {
foreach ($list as $init) {
$this->addField ($init);
}
}
/**
* Заполняет форму данными из коллекции
* Для обьектов и массивов можно использовать Adapter pattern
* @param object $data
* @param array $schema Связь между элементами формы и свойствами обьекта
*/
public function fill ($data) {
foreach ($this->field as $name => $el) {
$this->field [$name]->setValue ($data->get ($name));
}
}
}
?>

View file

@ -176,5 +176,3 @@ class TForm
$this->field[$name]->setValue($value); $this->field[$name]->setValue($value);
} }
} }
?>

View file

@ -83,4 +83,3 @@ class HFile {
} }
} }
?>

View file

@ -10,4 +10,3 @@ class Point
} }
} }
?>

View file

@ -49,5 +49,3 @@ class Rectangle
return new Point((($base->left + $base->right) - ($this->left + $this->right)) / 2, $base->bottom - $this->height); return new Point((($base->left + $base->right) - ($this->left + $this->right)) / 2, $base->bottom - $this->height);
} }
} }
?>

View file

@ -26,5 +26,3 @@ class ModelFactory
return $model; return $model;
} }
} }
?>

View file

@ -7,4 +7,3 @@ class Meta
{ {
} }
?>

View file

@ -203,4 +203,3 @@ class Query
} }
} }
?>

View file

@ -1,865 +0,0 @@
// Version: 0.8
// ANTLR Version: 2.7.2
// Date: 2003.08.25
//
// Description: This is a MS SQL Server 2000 SELECT statement grammar.
//
// =======================================================================================
// Author: Tomasz Jastrzebski
// Contact: tdjastrzebski@yahoo.com
// Working parser/lexer generated based on this grammar will available for some time at:
// http://jastrzebski.europe.webmatrixhosting.net/mssqlparser.aspx
options {
language = "CSharp";
}
// PARSER ********************************************************************************
class SqlParser extends Parser;
options {
k = 2;
}
// starting rule
statement
: selectStatement (SEMICOLON)? EOF
;
selectStatement
:
queryExpression
(computeClause)?
(forClause)?
(optionClause)?
;
queryExpression
: subQueryExpression (unionOperator subQueryExpression)* (orderByClause)?
;
subQueryExpression
:
querySpecification
| LPAREN queryExpression RPAREN
;
querySpecification
:
selectClause
(fromClause)?
(whereClause)?
(groupByClause (havingClause)? )?
;
selectClause
: SELECT (ALL | DISTINCT)? (TOP Integer (PERCENT)? (WITH TIES)? )? selectList
;
whereClause
: WHERE searchCondition
;
orderByClause
: ORDER BY expression (ASC | DESC)? (COMMA expression (ASC | DESC)? )*
;
groupByClause
: GROUP BY (ALL)? expression (COMMA expression)* (WITH (CUBE | ROLLUP) )?
;
havingClause
: HAVING searchCondition
;
optionClause
: OPTION LPAREN queryHint (COMMA queryHint)* RPAREN
;
queryHint
:
(HASH | ORDER) GROUP
| (CONCAT | HASH | MERGE) UNION
| (LOOP | MERGE | HASH) JOIN
| FAST Integer
| FORCE ORDER
| MAXDOP Integer
| ROBUST PLAN
| KEEP PLAN
| KEEPFIXED PLAN
| EXPAND VIEWS
;
forClause
:
FOR (
BROWSE
| XML (RAW | AUTO | EXPLICIT) (COMMA XMLDATA)? (COMMA ELEMENTS)? (COMMA BINARY BASE64)
)
;
computeClause
:
COMPUTE
// only allowed functions are: AVG, COUNT, MAX, MIN, STDEV, STDEVP, VAR, VARP, SUM
identifier LPAREN expression RPAREN
(COMMA identifier LPAREN expression RPAREN)*
(BY expression (COMMA expression)* )?
;
searchCondition
: subSearchCondition ( (AND | OR) subSearchCondition )*
;
subSearchCondition
:
(NOT)? (
(LPAREN searchCondition RPAREN) => LPAREN searchCondition RPAREN
| predicate
)
;
predicate
:
(
expression (
// expression comparisonOperator expression
comparisonOperator (
expression
| (ALL | SOME | ANY) LPAREN selectStatement RPAREN
)
| IS (NOT)? NULL
| (NOT)? (
LIKE expression (ESCAPE expression)? // only single char
| BETWEEN expression AND expression
| IN LPAREN (
(selectStatement) => selectStatement
| expression (COMMA expression)*
) RPAREN
)
| CONTAINS LPAREN (dbObject | STAR) COMMA (stringLiteral | Variable) RPAREN
| FREETEXT LPAREN (dbObject | STAR) COMMA (stringLiteral | Variable) RPAREN
)
| EXISTS LPAREN selectStatement RPAREN
)
;
selectList
: selectItem ( COMMA selectItem )*
;
selectItem
:
STAR // "*, *" is a valid select list
| (
// starts with: "alias = column_name"
(alias2) => (
(alias2 dbObject COMMA) => alias2 column
| (alias2 dbObject (binaryOperator | LPAREN)) => alias2 expression
| (alias2 column) => alias2 column
| (alias2 expression) => alias2 expression
)
// all table columns: "table.*"
| (tableColumns) => tableColumns
// some shortcuts:
| (dbObject (alias1)? COMMA) => column (alias1)?
| (dbObject (binaryOperator | LPAREN) ) => expression (alias1)?
// less obvious cases:
| (column) => column (alias1)?
| (expression) => expression (alias1)?
)
;
fromClause
: FROM tableSource (COMMA tableSource)*
;
tableSource
: subTableSource (joinedTable)*
;
subTableSource
:
(
LPAREN (
(joinedTables) => joinedTables RPAREN
| (queryExpression) => queryExpression RPAREN alias1 // "derived table", mandatory alias
)
| (function) => function (alias1)?
| dbObject (alias1)? ( (WITH)? LPAREN tableHint (COMMA tableHint)* RPAREN )?
| Variable (alias1)?
| (CONTAINSTABLE | FREETEXTTABLE) LPAREN
dbObject COMMA (dbObject | STAR) COMMA (stringLiteral | Variable) (COMMA Integer)?
RPAREN (alias1)?
| COLON COLON function (alias1)? // built-in function
)
;
joinedTable
:
CROSS JOIN subTableSource
// "joinHint JOIN" is invalid join expression
| ( (INNER | (LEFT | RIGHT | FULL) (OUTER)? ) (joinHint)? )? JOIN tableSource ON searchCondition
;
joinedTables
: subTableSource (joinedTable)+
;
joinHint
:
LOOP
| HASH
| MERGE
| REMOTE
;
tableHint
:
INDEX (
LPAREN (identifier | Integer) ( COMMA (identifier | Integer) )* RPAREN
| ASSIGNEQUAL identifier // old index hint syntax
)
| FASTFIRSTROW
| HOLDLOCK
| NOLOCK
| PAGLOCK
| READCOMMITED
| READPAST
| READUNCOMMITED
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
;
collate
: COLLATE identifier
;
alias1
: // alias name can also be single-quoted literal (but not for table names)
(AS)? (
identifier
| stringLiteral
| keywordAsIdentifier
)
;
alias2
:
(
identifier
| stringLiteral
| keywordAsIdentifier
)
ASSIGNEQUAL
;
tableColumns
:
o:dbObject DOT_STAR
;
column
:
(PLUS)* // "++column_name" is valid and updatable column name
(
dbObject
// for expression like "(column)" SQL Server returns updatable column
| LPAREN column RPAREN
)
(collate)? // it is not well documented but COLLATE can be used almost anywhere ...
;
expression
: // current definition ignores operator precedence
subExpression (binaryOperator subExpression)*
;
subExpression
:
(unaryOperator)?
(
constant
| Variable
| (function) => function
| LPAREN (
(selectStatement) => selectStatement // select statement returning a single value
| expression
) RPAREN
| dbObject // column
| parameterlessFunction
| caseFunction
| castFunction
)
(collate)? // it is not well documented but COLLATE can be used almost everywhere ...
;
// todo: create a separate rule for aggregate functions
function
: // LEFT and RIGHT keywords are also function names
(dbObject | LEFT | RIGHT) LPAREN (
expression (COMMA expression)*
| STAR // aggregate functions like Count(), Checksum() accept "*" as a parameter
| (ALL | DISTINCT) (STAR | expression) // aggregate function
| Variable ASSIGNEQUAL expression (COMMA Variable ASSIGNEQUAL expression)*
)?
RPAREN
;
caseFunction
: CASE (
expression (WHEN expression THEN expression)+
| (WHEN searchCondition THEN expression)+ // boolean expression
)
(ELSE expression)? END
;
castFunction
: CAST LPAREN expression AS identifier (LPAREN Integer (COMMA Integer)? RPAREN)? RPAREN
;
dbObject
// server.catalog.schema.object
// server.catalog..object
:
(identifier | IDENTITYCOL | ROWGUIDCOL | keywordAsIdentifier) (
DOT (identifier | IDENTITYCOL | ROWGUIDCOL | keywordAsIdentifier)
| (DOT DOT) => DOT DOT (identifier | IDENTITYCOL | ROWGUIDCOL | keywordAsIdentifier)
)*
;
parameterlessFunction
: // any others ?
CURRENT_TIMESTAMP
| CURRENT_USER
| SESSION_USER
| SYSTEM_USER
;
systemVariable
:
F_CONNECTIONS
| F_CPU_BUSY
| F_CURSOR_ROWS
| F_DATEFIRST
| F_DBTS
| F_ERROR
| F_FETCH_STATUS
| F_IDENTITY
| F_IDLE
| F_IO_BUSY
| F_LANGID
| F_LANGUAGE
| F_LOCK_TIMEOUT
| F_MAX_CONNECTIONS
| F_MAX_PRECISION
| F_NESTLEVEL
| F_OPTIONS
| F_PACK_RECEIVED
| F_PACK_SENT
| F_PACKET_ERRORS
| F_PROCID
| F_REMSERVER
| F_ROWCOUNT
| F_SERVERNAME
| F_SERVICENAME
| F_SPID
| F_TEXTSIZE
| F_TIMETICKS
| F_TOTAL_ERRORS
| F_TOTAL_READ
| F_TOTAL_WRITE
| F_TRANCOUNT
| F_VERSION
;
keywordAsIdentifier
:
(
AUTO
| BASE64
| BINARY
| CAST
| CONCAT
| CUBE
| ELEMENTS
| EXPAND
| EXPLICIT
| FAST
| FASTFIRSTROW
| FORCE
| HASH
| KEEP
| KEEPFIXED
| LOOP
| MAXDOP
| MERGE
| NOLOCK
| PAGLOCK
| RAW
| READCOMMITED
| READPAST
| READUNCOMMITED
| REMOTE
| REPEATABLEREAD
| ROBUST
| ROLLUP
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| TIES
| UPDLOCK
| VIEWS
| XLOCK
| XML
| XMLDATA
)
;
stringLiteral
:
UnicodeStringLiteral
| ASCIIStringLiteral
;
identifier
:
NonQuotedIdentifier
| QuotedIdentifier
;
constant
: Integer | Real | NULL | stringLiteral | HexLiteral | Currency | ODBCDateTime | systemVariable
;
unaryOperator
: PLUS | MINUS | TILDE
;
binaryOperator
: arithmeticOperator | bitwiseOperator
;
arithmeticOperator
: PLUS | MINUS | STAR | DIVIDE | MOD
;
bitwiseOperator
: AMPERSAND | TILDE | BITWISEOR | BITWISEXOR
;
comparisonOperator
:
ASSIGNEQUAL | NOTEQUAL1 | NOTEQUAL2 | LESSTHANOREQUALTO1 | LESSTHANOREQUALTO2
| LESSTHAN | GREATERTHANOREQUALTO1 | GREATERTHANOREQUALTO2 | GREATERTHAN
;
logicalOperator
: ALL | AND | ANY | BETWEEN | EXISTS | IN | LIKE | NOT | OR | SOME
;
unionOperator
: UNION (ALL)?
;
// LEXER *********************************************************************************
class SqlLexer extends Lexer;
options {
testLiterals = false;
k = 2;
caseSensitive = false;
caseSensitiveLiterals = false;
charVocabulary='\u0000'..'\uFFFE';
}
tokens {
ADD = "add" ;
ALL = "all" ;
ALTER = "alter" ;
AND = "and" ;
ANY = "any" ;
AS = "as" ;
ASC = "asc" ;
AUTHORIZATION = "authorization" ;
AUTO = "auto" ;
BACKUP = "backup" ;
BASE64 = "base64" ;
BEGIN = "begin" ;
BETWEEN = "between" ;
BINARY = "binary" ;
BREAK = "break" ;
BROWSE = "browse" ;
BULK = "bulk" ;
BY = "by" ;
CASCADE = "cascade" ;
CASE = "case" ;
CAST = "cast" ;
CHECK = "check" ;
CHECKPOINT = "checkpoint" ;
CLOSE = "close" ;
CLUSTERED = "clustered" ;
// COALESCE = "coalesce" ;
COLLATE = "collate" ;
COLUMN = "column" ;
COMMIT = "commit" ;
COMPUTE = "compute" ;
CONCAT = "concat" ;
CONSTRAINT = "constraint" ;
CONTAINS = "contains" ;
CONTAINSTABLE = "containstable" ;
CONTINUE = "continue" ;
// CONVERT = "convert" ;
CREATE = "create" ;
CROSS = "cross" ;
CUBE = "cube" ;
CURRENT = "current" ;
CURRENT_DATE = "current_date" ;
CURRENT_TIME = "current_time" ;
CURRENT_TIMESTAMP = "current_timestamp" ;
CURRENT_USER = "current_user" ;
CURSOR = "cursor" ;
DATABASE = "database" ;
DBCC = "dbcc" ;
DEALLOCATE = "deallocate" ;
DECLARE = "declare" ;
DEFAULT = "default" ;
DELETE = "delete" ;
DENY = "deny" ;
DESC = "desc" ;
DISK = "disk" ;
DISTINCT = "distinct" ;
DISTRIBUTED = "distributed" ;
DOUBLE = "double" ;
DROP = "drop" ;
// DUMMY = "dummy" ;
DUMP = "dump" ;
ELEMENTS = "elements" ;
ELSE = "else" ;
END = "end" ;
ERRLVL = "errlvl" ;
ESCAPE = "escape" ;
EXCEPT = "except" ;
EXEC = "exec" ;
EXECUTE = "execute" ;
EXISTS = "exists" ;
EXIT = "exit" ;
EXPAND = "expand" ;
EXPLICIT = "explicit" ;
FAST = "fast" ;
FASTFIRSTROW = "fastfirstrow" ;
FETCH = "fetch" ;
FILE = "file" ;
FILLFACTOR = "fillfactor" ;
FOR = "for" ;
FORCE = "force" ;
FOREIGN = "foreign" ;
FREETEXT = "freetext" ;
FREETEXTTABLE = "freetexttable" ;
FROM = "from" ;
FULL = "full" ;
FUNCTION = "function" ;
GOTO = "goto" ;
GRANT = "grant" ;
GROUP = "group" ;
HASH = "hash" ;
HAVING = "having" ;
HOLDLOCK = "holdlock" ;
IDENTITY = "identity" ;
IDENTITY_INSERT = "identity_insert" ;
IDENTITYCOL = "identitycol" ;
IF = "if" ;
IN = "in" ;
INDEX = "index" ;
INNER = "inner" ;
INSERT = "insert" ;
INTERSECT = "intersect" ;
INTO = "into" ;
IS = "is" ;
JOIN = "join" ;
KEEP = "keep" ;
KEEPFIXED = "keepfixed" ;
KEY = "key" ;
KILL = "kill" ;
LEFT = "left" ;
LIKE = "like" ;
LINENO = "lineno" ;
LOAD = "load" ;
LOOP = "loop" ;
MAXDOP = "maxdop" ;
MERGE = "merge" ;
NATIONAL = "national" ;
NOCHECK = "nocheck" ;
NOLOCK = "nolock" ;
NONCLUSTERED = "nonclustered" ;
NOT = "not" ;
NULL = "null" ;
// NULLIF = "nullif" ;
OF = "of" ;
OFF = "off" ;
OFFSETS = "offsets" ;
ON = "on" ;
OPEN = "open" ;
OPENDATASOURCE = "opendatasource" ;
OPENQUERY = "openquery" ;
OPENROWSET = "openrowset" ;
OPENXML = "openxml" ;
OPTION = "option" ;
OR = "or" ;
ORDER = "order" ;
OUTER = "outer" ;
OVER = "over" ;
PAGLOCK = "paglock" ;
PERCENT = "percent" ;
PLAN = "plan" ;
PRECISION = "precision" ;
PRIMARY = "primary" ;
PRINT = "print" ;
PROC = "proc" ;
PROCEDURE = "procedure" ;
PUBLIC = "public" ;
RAISERROR = "raiserror" ;
RAW = "raw" ;
READ = "read" ;
READCOMMITED = "readcommited" ;
READPAST = "readpast" ;
READTEXT = "readtext" ;
READUNCOMMITED = "readuncommited" ;
RECONFIGURE = "reconfigure" ;
REFERENCES = "references" ;
REMOTE = "remote" ;
REPEATABLEREAD = "repeatableread" ;
REPLICATION = "replication" ;
RESTORE = "restore" ;
RESTRICT = "restrict" ;
RETURN = "return" ;
REVOKE = "revoke" ;
RIGHT = "right" ;
ROBUST = "robust" ;
ROLLBACK = "rollback" ;
ROLLUP = "rollup" ;
ROWCOUNT = "rowcount" ;
ROWGUIDCOL = "rowguidcol" ;
ROWLOCK = "rowlock" ;
RULE = "rule" ;
SAVE = "save" ;
SCHEMA = "schema" ;
SELECT = "select" ;
SERIALIZABLE = "serializable" ;
SESSION_USER = "session_user" ;
SET = "set" ;
SETUSER = "setuser" ;
SHUTDOWN = "shutdown" ;
SOME = "some" ;
STATISTICS = "statistics" ;
SYSTEM_USER = "system_user" ;
TABLE = "table" ;
TABLOCK = "tablock" ;
TABLOCKX = "tablockx" ;
TEXTSIZE = "textsize" ;
THEN = "then" ;
TIES = "ties" ;
TO = "to" ;
TOP = "top" ;
TRAN = "tran" ;
TRANSACTION = "transaction" ;
TRIGGER = "trigger" ;
TRUNCATE = "truncate" ;
TSEQUAL = "tsequal" ;
UNION = "union" ;
UNIQUE = "unique" ;
UPDATE = "update" ;
UPDATETEXT = "updatetext" ;
UPDLOCK = "updlock" ;
USE = "use" ;
USER = "user" ;
VALUES = "values" ;
VARYING = "varying" ;
VIEW = "view" ;
VIEWS = "views" ;
WAITFOR = "waitfor" ;
WHEN = "when" ;
WHERE = "where" ;
WHILE = "while" ;
WITH = "with" ;
WRITETEXT = "writetext" ;
XLOCK = "xlock" ;
XML = "xml" ;
XMLDATA = "xmldata" ;
// system variables
F_CONNECTIONS = "@@connections" ;
F_CPU_BUSY = "@@cpu_busy" ;
F_CURSOR_ROWS = "@@cursor_rows" ;
F_DATEFIRST = "@@datefirst" ;
F_DBTS = "@@dbts" ;
F_ERROR = "@@error" ;
F_FETCH_STATUS = "@@fetch_status" ;
F_IDENTITY = "@@identity" ;
F_IDLE = "@@idle" ;
F_IO_BUSY = "@@io_busy" ;
F_LANGID = "@@langid" ;
F_LANGUAGE = "@@language" ;
F_LOCK_TIMEOUT = "@@lock_timeout" ;
F_MAX_CONNECTIONS = "@@max_connections" ;
F_MAX_PRECISION = "@@max_precision" ;
F_NESTLEVEL = "@@nestlevel" ;
F_OPTIONS = "@@options" ;
F_PACK_RECEIVED = "@@pack_received" ;
F_PACK_SENT = "@@pack_sent" ;
F_PACKET_ERRORS = "@@packet_errors" ;
F_PROCID = "@@procid" ;
F_REMSERVER = "@@remserver" ;
F_ROWCOUNT = "@@rowcount" ;
F_SERVERNAME = "@@servername" ;
F_SERVICENAME = "@@servicename" ;
F_SPID = "@@spid" ;
F_TEXTSIZE = "@@textsize" ;
F_TIMETICKS = "@@timeticks" ;
F_TOTAL_ERRORS = "@@total_errors" ;
F_TOTAL_READ = "@@total_read" ;
F_TOTAL_WRITE = "@@total_write" ;
F_TRANCOUNT = "@@trancount" ;
F_VERSION = "@@version" ;
}
// Operators
protected DOT:; // generated as a part of Number rule
COLON : ':' ;
COMMA : ',' ;
SEMICOLON : ';' ;
LPAREN : '(' ;
RPAREN : ')' ;
//LSQUARE : '[' ;
//RSQUARE : ']' ;
ASSIGNEQUAL : '=' ;
NOTEQUAL1 : "<>" ;
NOTEQUAL2 : "!=" ;
LESSTHANOREQUALTO1 : "<=" ;
LESSTHANOREQUALTO2 : "!>" ;
LESSTHAN : "<" ;
GREATERTHANOREQUALTO1 : ">=" ;
GREATERTHANOREQUALTO2 : "!<" ;
GREATERTHAN : ">" ;
DIVIDE : '/' ;
PLUS : '+' ;
MINUS : '-' ;
STAR : '*' ;
MOD : '%' ;
AMPERSAND : '&' ;
TILDE : '~' ;
BITWISEOR : '|' ;
BITWISEXOR : '^' ;
DOT_STAR : ".*" ;
Whitespace
: (' ' | '\t' | '\n' | '\r')
{ _ttype = Token.SKIP; }
;
// COMMENTS
SingleLineComment
: "--"( ~('\r' | '\n') )*
{ _ttype = Token.SKIP; }
;
MultiLineComment
: "/*" (~'*')* '*' ('*' | ( ~('*' | '/') (~'*')* '*') )* '/'
{ _ttype = Token.SKIP; }
;
// LITERALS
protected
Letter
: 'a'..'z' | '_' | '#' | '@' | '\u0080'..'\ufffe'
;
protected
Digit
: '0'..'9'
;
protected
Integer :;
protected
Real :;
protected
Exponent
: 'e' ( '+' | '-' )? (Digit)+
;
Number
:
( (Digit)+ ('.' | 'e') ) => (Digit)+ ( '.' (Digit)* (Exponent)? | Exponent) { _ttype = Real; }
| '.' { _ttype = DOT; } ( (Digit)+ (Exponent)? { _ttype = Real; } )?
| (Digit)+ { _ttype = Integer; }
| "0x" ('a'..'f' | Digit)* { _ttype = HexLiteral; } // "0x" is valid hex literal
;
protected
Currency
: // generated as a part of NonQuotedIdentifier rule
('$' | '\u00a3'..'\u00a5' | '\u09f2'..'\u09f3' | '\u0e3f' | '\u20a0'..'\u20a4' | '\u20a6'..'\u20ab')
((Digit)+ ('.' (Digit)* )? | '.' (Digit)+)
;
ODBCDateTime
: '{' (Whitespace)? ("ts" | 't' | 'd') (Whitespace)?
('n')? '\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )* (Whitespace)? '}'
;
NonQuotedIdentifier
options { testLiterals = true; }
:
(Currency) => Currency { _ttype = Currency; }
| ('a'..'z' | '_' | '#' | '\u0080'..'\ufffe') (Letter | Digit)* // first char other than '@'
;
QuotedIdentifier
:
(
'[' (~']')* ']' (']' (~']')* ']')*
| '"' (~'"')* '"' ('"' (~'"')* '"')*
)
;
Variable
// test for literals in case of a function begining with '@' (eg. "@@ERROR")
options { testLiterals = true; }
: '@' (Letter | Digit)+
;
ASCIIStringLiteral
:
'\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
UnicodeStringLiteral
:
'n' '\'' (~'\'')* '\'' ( '\'' (~'\'')* '\'' )*
;
// Numeric Constants
protected
HexLiteral // generated as a part of Number rule
: // "0x" ('0'..'9' | 'a'..'f')*
;

View file

@ -12,4 +12,3 @@ class Table
public $condition; public $condition;
} }
?>

View file

@ -1,741 +0,0 @@
<?php
/**
* Spyc -- A Simple PHP YAML Class
* @version 0.3
* @author Chris Wanstrath <chris@ozmm.org>
* @author Vlad Andersen <vlad@oneiros.ru>
* @link http://spyc.sourceforge.net/
* @copyright Copyright 2005-2006 Chris Wanstrath
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @package Spyc
*/
/**
* The Simple PHP YAML Class.
*
* This class can be used to read a YAML file and convert its contents
* into a PHP array. It currently supports a very limited subsection of
* the YAML spec.
*
* Usage:
* <code>
* $parser = new Spyc;
* $array = $parser->load($file);
* </code>
* @package Spyc
*/
class Spyc {
/**#@+
* @access private
* @var mixed
*/
private $_haveRefs;
private $_allNodes;
private $_allParent;
private $_lastIndent;
private $_lastNode;
private $_inBlock;
private $_isInline;
private $_dumpIndent;
private $_dumpWordWrap;
private $_containsGroupAnchor = false;
private $_containsGroupAlias = false;
private $path;
private $result;
private $LiteralBlockMarkers = array ('>', '|');
private $LiteralPlaceHolder = '___YAML_Literal_Block___';
private $SavedGroups = array();
/**#@+
* @access public
* @var mixed
*/
public $_nodeId;
/**
* Load YAML into a PHP array statically
*
* The load method, when supplied with a YAML stream (string or file),
* will do its best to convert YAML in a file into a PHP array. Pretty
* simple.
* Usage:
* <code>
* $array = Spyc::YAMLLoad('lucky.yaml');
* print_r($array);
* </code>
* @access public
* @return array
* @param string $input Path of YAML file or string containing YAML
*/
public static function YAMLLoad($input) {
$Spyc = new Spyc;
return $Spyc->load($input);
}
/**
* Dump YAML from PHP array statically
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML. Pretty simple. Feel free to
* save the returned string as nothing.yaml and pass it around.
*
* Oh, and you can decide how big the indent is and what the wordwrap
* for folding is. Pretty cool -- just pass in 'false' for either if
* you want to use the default.
*
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
* you can turn off wordwrap by passing in 0.
*
* @access public
* @return string
* @param array $array PHP array
* @param int $indent Pass in false to use the default, which is 2
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
*/
public static function YAMLDump($array,$indent = false,$wordwrap = false) {
$spyc = new Spyc;
return $spyc->dump($array,$indent,$wordwrap);
}
/**
* Dump PHP array to YAML
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML. Pretty simple. Feel free to
* save the returned string as tasteful.yaml and pass it around.
*
* Oh, and you can decide how big the indent is and what the wordwrap
* for folding is. Pretty cool -- just pass in 'false' for either if
* you want to use the default.
*
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
* you can turn off wordwrap by passing in 0.
*
* @access public
* @return string
* @param array $array PHP array
* @param int $indent Pass in false to use the default, which is 2
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
*/
public function dump($array,$indent = false,$wordwrap = false) {
// Dumps to some very clean YAML. We'll have to add some more features
// and options soon. And better support for folding.
// New features and options.
if ($indent === false or !is_numeric($indent)) {
$this->_dumpIndent = 2;
} else {
$this->_dumpIndent = $indent;
}
if ($wordwrap === false or !is_numeric($wordwrap)) {
$this->_dumpWordWrap = 40;
} else {
$this->_dumpWordWrap = $wordwrap;
}
// New YAML document
$string = "---\n";
// Start at the base of the array and move through it.
foreach ($array as $key => $value) {
$string .= $this->_yamlize($key,$value,0);
}
return $string;
}
/**
* Attempts to convert a key / value array item to YAML
* @access private
* @return string
* @param $key The name of the key
* @param $value The value of the item
* @param $indent The indent of the current node
*/
private function _yamlize($key,$value,$indent) {
if (is_array($value)) {
// It has children. What to do?
// Make it the right kind of item
$string = $this->_dumpNode($key,NULL,$indent);
// Add the indent
$indent += $this->_dumpIndent;
// Yamlize the array
$string .= $this->_yamlizeArray($value,$indent);
} elseif (!is_array($value)) {
// It doesn't have children. Yip.
$string = $this->_dumpNode($key,$value,$indent);
}
return $string;
}
/**
* Attempts to convert an array to YAML
* @access private
* @return string
* @param $array The array you want to convert
* @param $indent The indent of the current level
*/
private function _yamlizeArray($array,$indent) {
if (is_array($array)) {
$string = '';
foreach ($array as $key => $value) {
$string .= $this->_yamlize($key,$value,$indent);
}
return $string;
} else {
return false;
}
}
/**
* Returns YAML from a key and a value
* @access private
* @return string
* @param $key The name of the key
* @param $value The value of the item
* @param $indent The indent of the current node
*/
private function _dumpNode($key,$value,$indent) {
// do some folding here, for blocks
if (strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false) {
$value = $this->_doLiteralBlock($value,$indent);
} else {
$value = $this->_doFolding($value,$indent);
}
if (is_bool($value)) {
$value = ($value) ? "true" : "false";
}
$spaces = str_repeat(' ',$indent);
if (is_int($key)) {
// It's a sequence
$string = $spaces.'- '.$value."\n";
} else {
// It's mapped
$string = $spaces.$key.': '.$value."\n";
}
return $string;
}
/**
* Creates a literal block for dumping
* @access private
* @return string
* @param $value
* @param $indent int The value of the indent
*/
private function _doLiteralBlock($value,$indent) {
$exploded = explode("\n",$value);
$newValue = '|';
$indent += $this->_dumpIndent;
$spaces = str_repeat(' ',$indent);
foreach ($exploded as $line) {
$newValue .= "\n" . $spaces . trim($line);
}
return $newValue;
}
/**
* Folds a string of text, if necessary
* @access private
* @return string
* @param $value The string you wish to fold
*/
private function _doFolding($value,$indent) {
// Don't do anything if wordwrap is set to 0
if ($this->_dumpWordWrap === 0) {
return $value;
}
if (strlen($value) > $this->_dumpWordWrap) {
$indent += $this->_dumpIndent;
$indent = str_repeat(' ',$indent);
$wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
$value = ">\n".$indent.$wrapped;
}
return $value;
}
/* LOADING FUNCTIONS */
private function load($input) {
$Source = $this->loadFromSource($input);
if (empty ($Source)) return array();
$this->path = array();
$this->result = array();
for ($i = 0; $i < count($Source); $i++) {
$line = $Source[$i];
$lineIndent = $this->_getIndent($line);
$this->path = $this->getParentPathByIndent($lineIndent);
$line = $this->stripIndent($line, $lineIndent);
if ($this->isComment($line)) continue;
if ($literalBlockStyle = $this->startsLiteralBlock($line)) {
$line = rtrim ($line, $literalBlockStyle . "\n");
$literalBlock = '';
$line .= $this->LiteralPlaceHolder;
while ($this->literalBlockContinues($Source[++$i], $lineIndent)) {
$literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle);
}
$i--;
}
$lineArray = $this->_parseLine($line);
if ($literalBlockStyle)
$lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
$this->addArray($lineArray, $lineIndent);
}
return $this->result;
}
private function loadFromSource ($input) {
if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
return file($input);
$foo = explode("\n",$input);
foreach ($foo as $k => $_) {
$foo[$k] = trim ($_, "\r");
}
return $foo;
}
/**
* Finds and returns the indentation of a YAML line
* @access private
* @return int
* @param string $line A line from the YAML file
*/
private function _getIndent($line) {
if (!preg_match('/^ +/',$line,$match)) return 0;
if (!empty($match[0])) return strlen ($match[0]);
return 0;
}
/**
* Parses YAML code and returns an array for a node
* @access private
* @return array
* @param string $line A line from the YAML file
*/
private function _parseLine($line) {
if (!$line) return array();
$line = trim($line);
if (!$line) return array();
$array = array();
if ($group = $this->nodeContainsGroup($line)) {
$this->addGroup($line, $group);
$line = $this->stripGroup ($line, $group);
}
if ($this->startsMappedSequence($line))
return $this->returnMappedSequence($line);
if ($this->startsMappedValue($line))
return $this->returnMappedValue($line);
if ($this->isArrayElement($line))
return $this->returnArrayElement($line);
return $this->returnKeyValuePair($line);
}
/**
* Finds the type of the passed value, returns the value as the new type.
* @access private
* @param string $value
* @return mixed
*/
private function _toType($value) {
if (strpos($value, '#') !== false)
$value = trim(preg_replace('/#(.+)$/','',$value));
if (preg_match('/^("(.*)"|\'(.*)\')/',$value,$matches)) {
$value = (string)preg_replace('/(\'\'|\\\\\')/',"'",end($matches));
$value = preg_replace('/\\\\"/','"',$value);
} elseif (preg_match('/^\\[(.+)\\]$/',$value,$matches)) {
// Inline Sequence
// Take out strings sequences and mappings
$explode = $this->_inlineEscape($matches[1]);
// Propogate value array
$value = array();
foreach ($explode as $v) {
$value[] = $this->_toType($v);
}
} elseif (strpos($value,': ')!==false && !preg_match('/^{(.+)/',$value)) {
// It's a map
$array = explode(': ',$value);
$key = trim($array[0]);
array_shift($array);
$value = trim(implode(': ',$array));
$value = $this->_toType($value);
$value = array($key => $value);
} elseif (preg_match("/{(.+)}$/",$value,$matches)) {
// Inline Mapping
// Take out strings sequences and mappings
$explode = $this->_inlineEscape($matches[1]);
// Propogate value array
$array = array();
foreach ($explode as $v) {
$array = $array + $this->_toType($v);
}
$value = $array;
} elseif (strtolower($value) == 'null' or $value == '' or $value == '~') {
$value = null;
} elseif (preg_match ('/^[0-9]+$/', $value)) {
$value = (int)$value;
} elseif (in_array(strtolower($value),
array('true', 'on', '+', 'yes', 'y'))) {
$value = true;
} elseif (in_array(strtolower($value),
array('false', 'off', '-', 'no', 'n'))) {
$value = false;
} elseif (is_numeric($value)) {
$value = (float)$value;
} else {
// Just a normal string, right?
// $value = trim(preg_replace('/#(.+)$/','',$value));
}
// print_r ($value);
return $value;
}
/**
* Used in inlines to check for more inlines or quoted strings
* @access private
* @return array
*/
private function _inlineEscape($inline) {
// There's gotta be a cleaner way to do this...
// While pure sequences seem to be nesting just fine,
// pure mappings and mappings with sequences inside can't go very
// deep. This needs to be fixed.
$saved_strings = array();
// Check for strings
$regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
if (preg_match_all($regex,$inline,$strings)) {
$saved_strings = $strings[0];
$inline = preg_replace($regex,'YAMLString',$inline);
}
unset($regex);
// Check for sequences
if (preg_match_all('/\[(.+)\]/U',$inline,$seqs)) {
$inline = preg_replace('/\[(.+)\]/U','YAMLSeq',$inline);
$seqs = $seqs[0];
}
// Check for mappings
if (preg_match_all('/{(.+)}/U',$inline,$maps)) {
$inline = preg_replace('/{(.+)}/U','YAMLMap',$inline);
$maps = $maps[0];
}
$explode = explode(', ',$inline);
// Re-add the sequences
if (!empty($seqs)) {
$i = 0;
foreach ($explode as $key => $value) {
if (strpos($value,'YAMLSeq') !== false) {
$explode[$key] = str_replace('YAMLSeq',$seqs[$i],$value);
++$i;
}
}
}
// Re-add the mappings
if (!empty($maps)) {
$i = 0;
foreach ($explode as $key => $value) {
if (strpos($value,'YAMLMap') !== false) {
$explode[$key] = str_replace('YAMLMap',$maps[$i],$value);
++$i;
}
}
}
// Re-add the strings
if (!empty($saved_strings)) {
$i = 0;
foreach ($explode as $key => $value) {
while (strpos($value,'YAMLString') !== false) {
$explode[$key] = preg_replace('/YAMLString/',$saved_strings[$i],$value, 1);
++$i;
$value = $explode[$key];
}
}
}
return $explode;
}
private function literalBlockContinues ($line, $lineIndent) {
if (!trim($line)) return true;
if ($this->_getIndent($line) > $lineIndent) return true;
return false;
}
private function addArray ($array, $indent) {
$key = key ($array);
if (!isset ($array[$key])) return false;
if ($array[$key] === array()) { $array[$key] = ''; };
$value = $array[$key];
// Unfolding inner array tree as defined in $this->_arrpath.
//$_arr = $this->result; $_tree[0] = $_arr; $i = 1;
$tempPath = Spyc::flatten ($this->path);
eval ('$_arr = $this->result' . $tempPath . ';');
if ($this->_containsGroupAlias) {
do {
if (!isset($this->SavedGroups[$this->_containsGroupAlias])) { echo "Bad group name: $this->_containsGroupAlias."; break; }
$groupPath = $this->SavedGroups[$this->_containsGroupAlias];
eval ('$value = $this->result' . Spyc::flatten ($groupPath) . ';');
} while (false);
$this->_containsGroupAlias = false;
}
// Adding string or numeric key to the innermost level or $this->arr.
if ($key)
$_arr[$key] = $value;
else {
if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
}
$this->path[$indent] = $key;
eval ('$this->result' . $tempPath . ' = $_arr;');
if ($this->_containsGroupAnchor) {
$this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
$this->_containsGroupAnchor = false;
}
}
private function flatten ($array) {
$tempPath = array();
if (!empty ($array)) {
foreach ($array as $_) {
if (!is_int($_)) $_ = "'$_'";
$tempPath[] = "[$_]";
}
}
//end ($tempPath); $latestKey = key($tempPath);
$tempPath = implode ('', $tempPath);
return $tempPath;
}
private function startsLiteralBlock ($line) {
$lastChar = substr (trim($line), -1);
if (in_array ($lastChar, $this->LiteralBlockMarkers))
return $lastChar;
return false;
}
private function addLiteralLine ($literalBlock, $line, $literalBlockStyle) {
$line = $this->stripIndent($line);
$line = str_replace ("\r\n", "\n", $line);
if ($literalBlockStyle == '|') {
return $literalBlock . $line;
}
if (strlen($line) == 0) return $literalBlock . "\n";
// echo "|$line|";
if ($line != "\n")
$line = trim ($line, "\r\n ") . " ";
return $literalBlock . $line;
}
private function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
foreach ($lineArray as $k => $_) {
if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
$lineArray[$k] = rtrim ($literalBlock, " \r\n");
}
return $lineArray;
}
private function stripIndent ($line, $indent = -1) {
if ($indent == -1) $indent = $this->_getIndent($line);
return substr ($line, $indent);
}
private function getParentPathByIndent ($indent) {
if ($indent == 0) return array();
$linePath = $this->path;
do {
end($linePath); $lastIndentInParentPath = key($linePath);
if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
} while ($indent <= $lastIndentInParentPath);
return $linePath;
}
private function clearBiggerPathValues ($indent) {
if ($indent == 0) $this->path = array();
if (empty ($this->path)) return true;
foreach ($this->path as $k => $_) {
if ($k > $indent) unset ($this->path[$k]);
}
return true;
}
private function isComment ($line) {
if (preg_match('/^#/', $line)) return true;
return false;
}
private function isArrayElement ($line) {
if (!$line) return false;
if ($line[0] != '-') return false;
if (strlen ($line) > 3)
if (substr($line,0,3) == '---') return false;
return true;
}
private function isHashElement ($line) {
if (!preg_match('/^(.+?):/', $line, $matches)) return false;
$allegedKey = $matches[1];
if ($allegedKey) return true;
//if (substr_count($allegedKey, )
return false;
}
private function isLiteral ($line) {
if ($this->isArrayElement($line)) return false;
if ($this->isHashElement($line)) return false;
return true;
}
private function startsMappedSequence ($line) {
if (preg_match('/^-(.*):$/',$line)) return true;
}
private function returnMappedSequence ($line) {
$array = array();
$key = trim(substr(substr($line,1),0,-1));
$array[$key] = '';
return $array;
}
private function returnMappedValue ($line) {
$array = array();
$key = trim(substr($line,0,-1));
$array[$key] = '';
return $array;
}
private function startsMappedValue ($line) {
if (preg_match('/^(.*):$/',$line)) return true;
}
private function returnKeyValuePair ($line) {
$array = array();
if (preg_match('/^(.+):/',$line,$key)) {
// It's a key/value pair most likely
// If the key is in double quotes pull it out
if (preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
$value = trim(str_replace($matches[1],'',$line));
$key = $matches[2];
} else {
// Do some guesswork as to the key and the value
$explode = explode(':',$line);
$key = trim($explode[0]);
array_shift($explode);
$value = trim(implode(':',$explode));
}
// Set the type of the value. Int, string, etc
$value = $this->_toType($value);
if (empty($key)) {
$array[] = $value;
} else {
$array[$key] = $value;
}
}
return $array;
}
private function returnArrayElement ($line) {
if (strlen($line) <= 1) return array(array()); // Weird %)
$array = array();
$value = trim(substr($line,1));
$value = $this->_toType($value);
$array[] = $value;
return $array;
}
private function nodeContainsGroup ($line) {
if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
if (preg_match('/^(&[^ ]+)/', $line, $matches)) return $matches[1];
if (preg_match('/^(\*[^ ]+)/', $line, $matches)) return $matches[1];
if (preg_match('/(&[^" ]+$)/', $line, $matches)) return $matches[1];
if (preg_match('/(\*[^" ]+$)/', $line, $matches)) return $matches[1];
return false;
}
private function addGroup ($line, $group) {
if (substr ($group, 0, 1) == '&') $this->_containsGroupAnchor = substr ($group, 1);
if (substr ($group, 0, 1) == '*') $this->_containsGroupAlias = substr ($group, 1);
//print_r ($this->path);
}
private function stripGroup ($line, $group) {
$line = trim(str_replace($group, '', $line));
return $line;
}
}
?>

View file

@ -120,4 +120,3 @@ class Drawing
} }
} }
} }
?>

View file

@ -435,4 +435,3 @@ class ExcelDocument {
} }
} }
?>

View file

@ -30,4 +30,3 @@ function generatePassword($length = 9, $strength = 0) {
return $password; return $password;
} }
?>

View file

@ -204,4 +204,3 @@ class TemplateImage
} }
} }
?>

View file

@ -1,36 +0,0 @@
<?php
require_once 'core/widgets/widget.php';
/**
* Класс для создания диалоговых окон, типа поиска и настройки таблицы
*/
class Dialog extends Widget
{
protected $title;
protected $action;
private $friend;
function setFriend(Widget $friend)
{
$this->friend = $friend->getName();
}
function getPostCode()
{
return $this->getName() . ".setFriend(" . $this->friend . ");";
}
function setTitle($title)
{
$this->title = $title;
}
function setAction($action)
{
$this->action = forceUrl($action);
}
}
?>

View file

@ -1,39 +0,0 @@
<?php
require_once 'core/widgets/listtable.php';
/**
* Класс для генерации таблицы
*/
class FileBrowser extends ListTable
{
private $friend;
public function setType($type)
{
$this->setData('type', $type);
}
function setHeader($header)
{
$this->setData('table', $header);
}
function setFriend(Widget $friend)
{
$this->friend = $friend->getName();
}
function getPostCode()
{
if ($this->friend) {
return $this->getName() . ".setFriend(" . $this->friend . ");";
}
return "";
}
function postMake() {
$this->view->addScriptRaw($this->getPostCode(), true); // CompositeView
}
}
?>

View file

@ -1,71 +0,0 @@
<?php
require_once 'core/widgets/widget.php';
require_once 'core/functions.php';
/**
* Класс для генерации таблицы
*/
class ListTable extends Widget // MenuTable
{
private $visible = null;
private $menu;
function setUp()
{
$this->menu = array();
$this->template = "table";
}
/**
* Устанавливает формат таблицы, структуру $header см. table.js
*/
function setHeader($header)
{
$this->setData('table', $header);
}
function setView($visible)
{
$this->visible = $visible;
}
function setAction($action)
{
$this->setData('list', forceUrl($action));
}
function addMenuItem($href, $name, $to = 'item')
{
if ($href) {
if ($to === true) $to = 'all';
if (! isset($this->menu[$to])) {
$this->menu[$to] = array('group' => $to, 'all' => ($to == 'all'), 'items' => array());
}
$this->menu[$to]['items'][] = array('href' => $href, 'name' => $name);
}
}
function make(Controller $parent)
{
$view = $this->visible;
if (is_null($view)) {
$view = array('left' => key_values('key', $this->data['table']), 'right' => array());
}
$this->setData('setup', $view);
foreach ($this->menu as &$menu) {
foreach ($menu['items'] as &$item) {
$item['href'] = forceUrl($item['href']);
}
}
$this->setData('menu', array_keys($this->menu));
parent::make($parent);
$this->view->menus = $this->menu;
}
}
?>

View file

@ -1,38 +0,0 @@
<?php
/**
* Список ссылок
*/
class SimpleMenu
{
private $items = array();
/**
* Добавление элемента меню
* @param $href Обьект ссылки или строка, ссылка должна быть сгенерирована при генерации страницы, т.к может зависеть от параметров
* которые могут измениться при создании страницы, поэтому передается ссылка на функцию (отложенная/ленивая ссылка)
* @param $name Подпись к ссылке
*/
function addMenuItem(/*. url .*/ $href,/*. string .*/ $name)
{
if($href) { // если ссылка пустая то элемент не добовляется
$this->items[] = array('href' => $href, 'name' => ucfirst($name)); // menu_item
}
}
/**
* Массив ссылок
* @return Массив
*/
function getItems()
{
foreach ($this->items as &$item) {
if (is_callable($item['href'])) {
$item['href'] = call_user_func($item['href']);
}
}
return $this->items;
}
}
?>

View file

@ -1,30 +0,0 @@
<?php
require_once 'core/widgets/widget.php';
require_once 'core/widgets/menu.php';
/**
* Компонент для генерации меню
*/
class PageMenu extends Widget
{
private $menu;
function setUp()
{
$this->menu = new SimpleMenu();
$this->template = "menu";
}
function addMenuItem($name, $value)
{
$this->menu->addMenuItem($name, $value);
}
function postMake()
{
$this->view->items = $this->menu->getItems();
}
}
?>

View file

@ -1,16 +0,0 @@
<?php
require_once 'core/widgets/widget.php';
/**
* Отображение постраничности
*/
class Pages extends Widget // Selector
{
function setUp()
{
$this->template = "pages";
}
}
?>

View file

@ -1,32 +0,0 @@
<?php
require_once 'core/widgets/dialog.php';
class SearchDialog extends Dialog
{
private $fields;
function setUp()
{
$this->template = "search";
}
function addFields($fields)
{
$this->fields = $fields;
}
function postMake()
{
$form = new TForm (); // Показывем форму
$form->addFieldList ($this->fields); // Разделить форму поиска и редактирования
$this->view->form = $form;
$this->view->action = $this->action;
$this->view->title = $this->title;
$this->view->addScriptRaw($this->getPostCode(), true); // CompositeView
}
}
?>

View file

@ -1,20 +0,0 @@
<?php
require_once 'core/widgets/dialog.php';
class SetupDialog extends Dialog
{
function setUp()
{
$this->template = "setup";
}
function postMake()
{
$this->view->action = $this->action;
$this->view->title = $this->title;
$this->view->addScriptRaw($this->getPostCode(), true); // CompositeView
}
}
?>

View file

@ -1,17 +0,0 @@
<?php
require_once 'core/widgets/widget.php';
/**
* Компонент для генерации Дерева
*/
class Tree extends Widget
{
public function setUp()
{
$this->template = "tree";
}
// Добавление ветки дерева
}
?>

View file

@ -1,87 +0,0 @@
<?php
require_once 'core/json.php';
function forceUrl($name)
{
if(is_callable($name)) {
return call_user_func($name);
}
return $name;
}
/**
* Класс для генерации и управления активными компонентами страницы
* Компонент состоит из следующих частей
* PHP - Управление компонентом (Генерация, Инициализация, Обработка событий)
* HTML - Необходимые шаблоны
* CSS - Стили
* Javascript - Клиентская часть управления компонентом
*/
class Widget
{
private static $prefix = "_g";
private static $idx = 0;
private $id;
public $data = array();
public $view;
protected $template;
public function __construct()
{
$this->id = self::$idx ++;
$this->setUp();
}
function setUp()
{
}
public function getName()
{
return self::$prefix . intval($this->id);
}
/**
* Генерация кода инициализации компонента на стороне клиента
*/
public function getCodeBefore()
{
$result =
// "alert('".$this->getName()."');" .
"var " . $this->getName() . " = new " . get_class($this) . "("
. json::encode($this->data) . ");";
return $result;
}
public function setData($name, $value)
{
$this->data[$name] = $value;
}
public function getCodeAfter()
{
return $this->getName() . ".appendTo(document.getElementById('" . $this->getName() . "'));\n";
}
public function postMake()
{
}
/**
* Генерация компонента
*/
function make(Controller $parent)
{
$this->view = $parent->getView($this->template); // Controller
$this->view->index = $this->getName();
foreach ($this->data as $name => $value) {
$this->view->set($name, $value);
}
$this->view->addScriptRaw($this->getCodeBefore(), true);
$this->postMake();
$this->view->addScriptRaw($this->getCodeAfter(), true);
}
}
?>

View file

@ -1,16 +1,11 @@
<?php <?php
/*.
require_module 'standard';
require_module 'zip';
.*/
/** /**
* Расширение класса ZipArchive с возможность архивирования директории * Расширение класса ZipArchive с возможность архивирования директории
*/ */
class ZipFile extends ZipArchive class ZipFile extends ZipArchive
{ {
private function addDirDo(/*. string.*/ $location, /*. string .*/ $name) private function addDirDo($location, $name)
{ {
assert(is_string($location) && is_string($name)); assert(is_string($location) && is_string($name));
@ -29,7 +24,7 @@ class ZipFile extends ZipArchive
} }
} }
public function addDir(/*. string.*/ $location, /*. string .*/ $name) public function addDir($location, $name)
{ {
assert(is_string($location) && is_string($name)); assert(is_string($location) && is_string($name));
@ -37,5 +32,3 @@ class ZipFile extends ZipArchive
$this->addDirDo($location, $name); $this->addDirDo($location, $name);
} }
} }
?>

View file

@ -80,6 +80,3 @@ function not_ctype_alpha ($ch)
{ {
return !ctype_alpha($ch); return !ctype_alpha($ch);
} }
?>

View file

@ -82,5 +82,3 @@ class Index
} }
} }
} }
?>

View file

@ -89,5 +89,3 @@ class Lexer
$this->token = $this->getToken(); $this->token = $this->getToken();
} }
} }
?>

View file

@ -95,4 +95,3 @@ class Search
} }
} }
?>

View file

@ -99,4 +99,3 @@ class Searcher {
} }
} }
?>

View file

@ -178,4 +178,3 @@ class Stemmer {
return $word; return $word;
} }
} }
?>