File: /home/mmickelson/theflexguy.com/wp-content/themes/vanilla/PHPTAL/Php/Node.php
<?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();
}
}
?>