<?php
 
/**
 
 * Class for generating head section of an web page. Elements 
 
 * that can be generated are title, meta-tags, CSS files paths, 
 
 * JavaScript files paths and path to the favicon image. 
 
 *
 
 * @license    GNU General Public License (GPL)
 
 * @author    Nikola Posa, www.nikolaposa.in.rs
 
 */
 
class HeadSection
 
{    
 
    const APPEND  = 'APPEND';
 
    const PREPEND = 'PREPEND';
 
    const SET       = 'SET';
 
    
 
    /**
 
     * Title of an web page.
 
     *
 
     * @var string
 
     */
 
    protected $title = '';
 
    
 
    /**
 
     * Meta tags array which has meta-tag's names as indexes, and 
 
     * meta-tag's contents as values.
 
     *
 
     * @var array
 
     */
 
    protected $meta = array(); 
 
    
 
    /**
 
     * This attribute can be a string or array of strings which 
 
     * represents paths to CSS files (i.e. files/style.css).
 
     *
 
     * @var mixed
 
     */
 
    protected $css = array();
 
    
 
    /**
 
     * This attribute can be string or array of strings which 
 
     * represents paths to JavaScript files (i.e. files/test.js).
 
     *
 
     * @var mixed
 
     */
 
    protected $js = array(); 
 
    
 
    /**
 
     * Path to the favicon image (i.e. images/favicon.ico).
 
     *
 
     * @var string
 
     */
 
    protected $favicon;
 
    
 
    /**
 
     * Whether to generate opened and closed <head> tags.
 
     *
 
     * @var bool
 
     */
 
    private $startingTags = true;
 
    
 
    /**
 
     * Content-Type meta-tag.
 
     *
 
     * @var string
 
     */
 
    private $contentType = 'text/html; charset=UTF-8';
 
    
 
    /**
 
     * Indentation of output, this will usually be some spaces.
 
     *
 
     * @var string
 
     */
 
    private $indent = '';
 
    
 
    /**
 
     * Constructor
 
     *
 
     * @param array Options (startingTags, contentType, indent).
 
     * @param array Head section elements as key=>value pairs.
 
     * @return HeadSection
 
     */
 
    public function __construct($options = array(), $elements = array())
 
    {
 
        $this->setOptions($options);
 
        
 
        $this->setElements($elements);
 
    }
 
    
 
    /**
 
     * Sets values to head section elements.
 
     *
 
     * @param array Head section elements as key=>value pairs.
 
     * @return void
 
     */
 
    public function setElements(array $elements)
 
    {
 
        foreach ($elements as $key=>$value) {
 
            $methodName = 'add' . ucfirst($key);
 
            if (method_exists($this, $methodName)) {
 
                $this->$methodName($value);
 
            }
 
        }
 
    }
 
    
 
    /**
 
     * Sets values to head section elements.
 
     *
 
     * @param array Head section elements as key=>value pairs.
 
     * @return void
 
     */
 
    public function setOptions(array $options)
 
    {
 
        foreach ($options as $key=>$value) {
 
            $methodName = 'set' . ucfirst($key);
 
            if (method_exists($this, $methodName)) {
 
                $this->$methodName($value);
 
            }
 
        }
 
    }
 
    
 
    /**
 
     * Sets $startingTags flag.
 
     *
 
     * @param bool True or false.
 
     * @return void
 
     */
 
    public function setStartingTags($flag)
 
    {
 
        $this->startingTags = (bool)$flag;
 
    }
 
    
 
    /**
 
     * Sets $contentType.
 
     *
 
     * @param string Content-type meta-tag content value.
 
     * @return void
 
     */
 
    public function setContentType($contentType)
 
    {
 
        if ($contentType !== null) {
 
            $contentType = (string)$contentType;
 
        }
 
        
 
        $this->contentType = $contentType;
 
    }
 
    
 
    /**
 
     * Sets indent.
 
     *
 
     * @param int|string True or false.
 
     * @return void
 
     */
 
    public function setIndent($indent)
 
    {
 
        $this->indent = $this->getWhitespace($indent);
 
    }
 
    
 
    /**
 
     * Generate whitespace, based on $indent.
 
     * 
 
     * @param int|string Indent (whitespaces or integer).
 
     * @return string
 
     */
 
    protected function getWhitespace($indent)
 
    {
 
        if (is_int($indent)) {
 
            $indent = str_repeat(' ', $indent);
 
        }
 
 
        return (string) $indent;
 
    }
 
    
 
    /**
 
     * Sets title in head section.
 
     *
 
     * @param string Head section title.
 
     * @param string Mode (append, prepend, set).
 
     * @param bool Whether to escape this head section element.
 
     * @return void
 
     */
 
    public function addTitle($value, $mode = 'APPEND', $escape = true)
 
    {
 
        $value = (string)$value;
 
        
 
        $this->add('title', $value, $mode);
 
        
 
        if ($escape === true) {
 
            $this->title = $this->escape($this->title);
 
        }
 
    }
 
 
    /**
 
     * Function for adding meta-tags.
 
     *
 
     * @param array Meta-tags.
 
     * @param string Mode (append, prepend, set).
 
     * @param bool Whether to escape this head section element.
 
     * @return void
 
     */
 
    public function addMeta($value, $mode = 'APPEND', $escape = true)
 
    {
 
        
 
        if (is_array($value) && !isset($value['name'])) {
 
            foreach ($value as $val) {
 
                $this->add('meta', $val, $mode, false);
 
            }
 
        }
 
        else {
 
            if ($mode == self::SET) {
 
                $this->meta = array($value);
 
            }
 
            else {
 
                $this->add('meta', $value, $mode, false);
 
            }
 
        }
 
        
 
        if ($escape === true) {
 
            $this->meta = $this->escape($this->meta);
 
        }
 
    }
 
    
 
    /**
 
     * Function for adding path(s) to CSS files.
 
     *
 
     * @param mixed Path(s) to CSS files.
 
     * @param string Mode (append, prepend, set).
 
     * @return void
 
     */
 
    public function addCss($value, $mode = 'APPEND')
 
    {
 
        $this->add('css', $value, $mode);
 
    }
 
    
 
    /**
 
     * Function for adding path(s) to JS files.
 
     *
 
     * @param mixed Path(s) to JS files.
 
     * @param string Mode (append, prepend, set).
 
     * @return void
 
     */
 
    public function addJs($value, $mode = 'APPEND')
 
    {
 
        $this->add('js', $value, $mode);
 
    }
 
    
 
    /**
 
     * Sets path to favicon image.
 
     *
 
     * @param string Path to favicon image.
 
     * @return void
 
     */
 
    public function addFavicon($value)
 
    {
 
        $value = (string)$value;
 
        
 
        $this->favicon = $value;
 
    }
 
    
 
    /**
 
     * Used for adding title, meta-tags, css and js paths. This 
 
     * function appends, prepends or setts value to some of those 
 
     * elements, base on $mode parametar.
 
     *
 
     * @param string Name of an element in head section.
 
     * @param string Value that will be added.
 
     * @param string Mode (append, prepend, set).
 
     * @param bool Whether to recursively pass through all values in case $value is an array.
 
     * @return void
 
     */
 
    protected function add($element, $value, $mode, $recursive = true)
 
    {
 
        if (is_array($value) && $mode != self::SET && $recursive == true) {
 
            foreach ($value as $val) {
 
                $this->add($element, $val, $mode, $recursive);
 
            }
 
        }
 
        else {
 
            $methodName = strtolower($mode);
 
            if (method_exists($this, $methodName)) {
 
                $this->$methodName($element, $value);
 
            }
 
        }
 
    }
 
    
 
    /**
 
     * Appends value to some element of head section.
 
     *
 
     * @param string Name of an element in head section.
 
     * @param string Value that will be added.
 
     * @return void
 
     */
 
    protected function append($element, $value)
 
    {
 
        if (is_string($this->$element)) {
 
            $this->$element .= $value;
 
        }
 
        elseif (is_array($this->$element)) {
 
            array_push($this->$element, $value);
 
        }
 
    }
 
    
 
    /**
 
     * Prepends value to some element of head section.
 
     *
 
     * @param string Name of an element in head section.
 
     * @param string Value that will be added.
 
     * @return void
 
     */
 
    protected function prepend($element, $value)
 
    {
 
        if (is_string($this->$element)) {
 
            $this->$element .= $value;
 
        }
 
        elseif (is_array($this->$element)) {
 
            array_unshift($this->$element, $value);
 
        }
 
    }
 
    
 
    /**
 
     * Sets value to some element of head section.
 
     *
 
     * @param string Name of an element in head section.
 
     * @param string Value that will be added.
 
     * @return void
 
     */
 
    protected function set($element, $value)
 
    {
 
        if (is_array($this->$element) && is_string($value)) {
 
            $this->$element = array($value);
 
        }
 
        else {
 
            $this->$element = $value;
 
        }
 
    }
 
    
 
    /**
 
     * Escapes some value.
 
     *
 
     * @param mixed String or array with strings to escape.
 
     * @return string
 
     */
 
    protected function escape($value)
 
    {
 
        if (is_array($value)) {
 
            foreach ($value as &$val) {
 
                $val = $this->escape($val);
 
            }
 
        }
 
        elseif (is_string($value)) {
 
            $value = htmlentities($value, null, 'UTF-8');
 
        }
 
        
 
        return $value;
 
    }
 
    
 
    /**
 
     * Generates head section.
 
     *
 
     * @param string|int $indent
 
     * @return string
 
     */
 
    public function render($indent = null)
 
    { 
 
        $output = '';
 
        
 
        $indent = ($indent !== null) ? $this->getWhitespace($indent) : $this->indent;
 
    
 
        //You can change this first $output .= if you want to.
 
        if ($this->startingTags == true) {
 
        $output .= '
 
        
 
<head>
 
';
 
        }
 
    
 
        if (strlen($this->title) > 0) {
 
            $output .= $indent . '<title>' . $this->title . '</title>';
 
            $output .= "\n\n";
 
        }
 
        
 
        if ($this->contentType !== null) {    
 
            $output .= $indent . '<meta http-equiv="Content-Type" content="' . $this->contentType . '" />'; 
 
            $output .= "\n\n";
 
        }
 
        
 
        if (!empty($this->meta)) {
 
            foreach ($this->meta as $tag) {
 
                if (isset($tag['name']) && isset($tag['content'])) {
 
                    $output .= $indent . '<meta name= "' . $tag['name'] . '" content = "' . $tag['content'] . '" />';
 
                    $output .= "\n";
 
                }
 
            }
 
            
 
            $output .= "\n";
 
        }
 
        
 
        if (!empty($this->css)) {
 
            foreach($this->css as $path) {
 
                $output .= $indent . '<link href = "' . $path . '" rel = "stylesheet" type = "text/css" />';
 
                $output .= "\n";
 
            }
 
            
 
            $output .= "\n";
 
        }
 
    
 
        if (isset($this->favicon)) {
 
            $output .= $indent . '<link href = "' . $this->favicon . '" rel = "shortcut icon" type = "image/x-icon" />';
 
            $output .= "\n\n";
 
        }
 
    
 
        if (!empty($this->js)) {
 
            foreach($this->js as $path) {
 
                $output .= $indent . '<script type = "text/javascript" src = "' . $path . '"></script>';
 
                $output .= "\n";
 
            }
 
        }
 
    
 
        if ($this->startingTags == true) {
 
            $output .= '</head>';
 
        }
 
 
        return $output;
 
    }
 
    
 
    /**
 
     * Redefinded toString() method, that defines how object of
 
     * this class will be outputed when it is converted to a string.
 
     *
 
     * @return string
 
     */
 
    public function __toString()
 
    {
 
        return $this->render();        
 
    }
 
}
 
?>
 
 |