<?php
/** @see FLY_TagBuilder_RenderMode */
require_once 'FLY/TagBuilder/RenderMode.php';
/**
* This class can be used to generate HTML tags programmatically.
*
* It can compose the definition of an HTML tag, its attributes, CSS styles and tag content.<br>
* Once defined, the class can return the HTML for the specified tag.<br>
*
* @package FLY
* @author Yves Feupi Lepatio
*/
class FLY_TagBuilder
{
/**
* Name of the HTML tag.
* @var string
*/
protected $_tagName = '';
/**
* Inner content of the tag.
* @var string
*/
protected $_innerHtml = '';
/**
* Tag's attributes.
* @var array
*/
protected $_attributes = array();
/**
* Standard inline tags.
* @var array
*/
protected $_inlineTags = array (
'meta', 'link', 'img', 'br', 'input', 'hr'
);
/**
* Gets the tag name.
*
* @return string
*/
public function getTagName()
{
return $this->_tagName;
}
/**
* Gets all tag's attributes.
*
* The returned array can be structured like this:
* array('attr_1', 'attr_2', ...)
*
* @return array Returns the array of the attributes; an empty array otherwise.
*/
public function getAttributes()
{
return $this->_attributes;
}
/**
* Sets the inner content of the tag.
*
* @param string $html
* @return FLY_TagBuilder
*/
public function setInnerHtml($html)
{
$this->_innerHtml = (string) $html;
return $this;
}
/**
* Creates a new tag.
*
* @param string $tagName The name of the tag.
* @throws InvalidArgumentException if the tag name is malformed
* @return void
*/
public function __construct($tagName)
{
if ( ! preg_match('/^[a-z][a-z0-9]*$/i', $tagName))
{
throw new InvalidArgumentException('`' . $tagName . '` is not a valid tag name');
}
$this->_tagName = strtolower($tagName);
}
/**
* Static method for initialization.
*
* @param string $tagName The name of the tag.
* @return FLY_TagBuilder
*/
public static function CreateTagBuilder($tagName)
{
return new self($tagName);
}
/**
* toString()
*
* @param int $renderMode The int must be a const of {@link FLY_TagBuilder_RenderMode}.
* Note: The default value is <code>FLY_TagBuilder_RenderMode::NORMAL</code>.
* @return string
*/
public function toString($renderMode = FLY_TagBuilder_RenderMode::NORMAL)
{
$result = '<' . $this->_tagName . $this->_buildAttributes();
switch ($renderMode)
{
case FLY_TagBuilder_RenderMode::END_TAG:
$result = '</' . $this->_tagName . '>';
break;
case FLY_TagBuilder_RenderMode::SELF_CLOSING:
$result .= ' />';
break;
case FLY_TagBuilder_RenderMode::START_TAG:
$result .= '>';
break;
case FLY_TagBuilder_RenderMode::NORMAL:
default:
$result .= $this->_isInlineTag($this->_tagName)
? ' />'
: sprintf('>%s</%s>', $this->_innerHtml, $this->_tagName);
break;
}
return $result;
}
/**
* _isInlineTag()
*
* @param string $tagName
* @return bool
*/
protected function _isInlineTag($tagName)
{
return in_array($tagName, $this->_inlineTags);
}
/**
* Returns the attributes formatted like they are in a tag. e.g: class="bg title" src=""
*
* @return string
*/
protected function _buildAttributes()
{
if (0 == count($this->_attributes))
{
return '';
}
$result = '';
if ($this->hasAttribute('id'))
{
$result .= sprintf(' id="%s"', $this->_attributes['id']);
}
if ($this->hasAttribute('class'))
{
$result .= sprintf(' class="%s"', $this->_attributes['class']);
}
$this->removeAttributes(array('id', 'class'));
foreach ($this->_attributes as $name => $value)
{
$result .= sprintf(' %s="%s"', $name, $value);
}
return $result;
}
/**
* removeAttributes()
*
* @return FLY_TagBuilder
*/
public function removeAttributes(array $names)
{
foreach ($names as $name)
{
$this->removeAttribute($name);
}
return $this;
}
/**
* removeAttribute()
*
* @name string $name
* @return FLY_TagBuilder
*/
public function removeAttribute($name)
{
if ($this->hasAttribute($name))
{
unset($this->_attributes[$name]);
}
return $this;
}
/**
* hasAttribute()
*
* @return bool
*/
public function hasAttribute($name)
{
$bool = array_key_exists($name, $this->_attributes);
return $bool;
}
/**
* Merges the attributes.
*
* @param array $attributes A collection of pairs ("attributeName" => "value")
* @param bool $replaceExisting Replace existing attribute or not
* @return FLY_TagBuilder
* @throws InvalidArgumentException if the attribute name is malformed
*/
public function mergeAttributes(array $attributes, $replaceExisting = true)
{
foreach ($attributes as $name => $value)
{
$this->mergeAttribute($name, $value, $replaceExisting);
}
return $this;
}
/**
* Merges the attribute.
*
* @param string $name The attribute name
* @param string $value The attribute value
* @param bool $replaceExisting Replace existing attribute or not
* @return FLY_TagBuilder
* @throws InvalidArgumentException if the attribute name is malformed
*/
public function mergeAttribute($name, $value, $replaceExisting = true)
{
if ( ! preg_match('/^[a-z][a-z0-9]+$/i', $name))
{
throw new InvalidArgumentException('The attribute name `' . $name . '` is not well-named');
}
$name = strtolower($name);
$value = trim($value);
if (($name == 'class') && ! $replaceExisting)
{
$this->addCssClass($value);
}
if ($replaceExisting || ! $this->hasAttribute($name))
{
$this->_attributes[$name] = $value;
}
return $this;
}
/**
* Adds CSS value.
*
* @param string $value
* @return FLY_TagBuilder
*/
public function addCssClass($value)
{
$value = str_replace('\s+', ' ', trim($value));
if ($this->hasAttribute('class') && ($value != ''))
{
$cssValues = preg_split('/ /', $value);
foreach ($cssValues as $cssValue)
{
if (false === strpos($this->_attributes['class'], $cssValue))
{
$this->_attributes['class'] .= ' ' . $cssValue;
}
}
}
else
{
$this->_attributes['class'] = $value;
}
return $this;
}
/**
* Removes CSS class.
*
* @param string $value
* @return FLY_TagBuilder
*/
public function removeCssClass($value)
{
$value = str_replace('\s+', ' ', trim($value));
if ($this->hasAttribute('class') && ($value != ''))
{
$cssValues = preg_split('/ /', $value);
foreach ($cssValues as $cssValue)
{
if (false !== strpos($this->_attributes['class'], $cssValue))
{
$this->_attributes['class'] = preg_replace(
"/^(?:{$cssValue}\s)?(.*?)(?:\s{$cssValue})?(.*?)(?:\s{$cssValue})?$/",
'$1$2',
$this->_attributes['class']
);
}
}
}
return $this;
}
}