Файл: cobisja/BootHelp/src/Helpers/Html/Html.php
Строк: 327
<?php
/**
 * BootHelp - PHP Helpers for Bootstrap
 *
 * (The MIT License)
 *
 * Copyright (c) 2015 Jorge Cobis <jcobis@gmail.com / http://twitter.com/cobisja>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
namespace cobisjaBootHelpHelpersHtml;
use cobisjaBootHelpHelpersHtmlHtmlAttribute;
use cobisjaBootHelpHelpersHtmlHtmlContent;
/**
 * Class Html: Handle of logic related to HTML generation base on a BootHelp helper.
 */
class Html
{
    const SPACE = ' ';
    /**
     * @var string Type of html tag.
     */
    private $type;
    /**
     * @var array Attributes associated to html tag.
     */
    private $attributes = [];
    /**
     * @var mixed Inner content of html tag.
     */
    private $content;
    /**
     * Build an Html instance.
     *
     * @param string $type type of html tag.
     * @param mixed  $attributes attributes of html tag (ussualy an array).
     * @param mixed  $content inner content of html tag
     */
    public function __construct($type, $attributes, $content = '')
    {
        $this->setType($type);
        $this->setAttributes($attributes);
        $this->setContent($content);
    }
    /**
     * Returns type of html tag.
     *
     * @return string type of html.
     */
    public function getType()
    {
        return $this->type;
    }
    /**
     * Returns Attributes of html tag.
     *
     * @return mixed whole set of attributes.
     */
    public function getAttributes()
    {
        return (0 === count($this->attributes)) ? '' : $this->attributes;
    }
    /**
     * Return a string representing the html attributes.
     *
     * @return string string representation of the whole set of attributes.
     */
    public function getAttributesToString()
    {
        $attributes = $this->getAttributes();
        if (is_array($attributes)) {
            $attributes_string = join(
                self::SPACE,
                array_map(
                    function ($attribute) {
                        return (string) $attribute;
                    },
                    $attributes
                )
            );
        } else {
            $attributes_string = $attributes;
        }
        return $attributes_string;
    }
    /**
     * Returns an array containing the html attributes.
     *
     * @return array array of attributes.
     */
    public function getAttributesToArray()
    {
        $attrs = [];
        array_map(
            function ($attribute) use (&$attrs) {
                $attrs[$attribute->getName()] = $attribute->getValue();
            },
            $this->getAttributes()
        );
        return $attrs;
    }
    /**
     * Returns the indicated attribute's value
     *
     * @param string $name attribute's name.
     * @param array  $options options to specify format of the value to return.
     * 
     * @return mixed value of specific attribute.
     */
    public function getAttribute($name, array $options = [])
    {
        $attribute_value = str_replace('"', '', $this->getAttributeWithValue($name));
        return isset($options['as']) &&
            'array' === $options['as'] ? explode(self::SPACE, $attribute_value) : $attribute_value;
    }
    /**
     * Indicates if an given attribute with a especific value exists.
     *
     * @param string $name name of html attribute.
     * @param mixed  $with_value values associated with the html attribute asked for.
     * 
     * @return boolean true if exists, false otherwise.
     */
    public function hasAttribute($name, $with_value)
    {
        return !is_null($this->getAttributeWithValue($name, $with_value));
    }
    /**
     * Return inner html tag content.
     *
     * @return mixed whole content of html object.
     */
    public function getContent()
    {
        return $this->content;
    }
    /**
     * Sets html tag type.
     *
     * @param string $type type of html tag.
     */
    public function setType($type)
    {
        $this->type = $type;
    }
    /**
     * Sets html attributes.
     *
     * @param array $attributes html tag attributes.
     */
    public function setAttributes($attributes)
    {
        !is_array($attributes) ? $attributes = [] : null;
        foreach ($attributes as $name => $value) {
            $this->attributes[] = new HtmlAttribute($name, $value);
        }
    }
    /**
     * Sets inner html tag content.
     *
     * @param mixed $content inner html tag content.
     */
    public function setContent($content)
    {
        $this->content = new HtmlContent($content);
    }
    /**
     * Test if an html instance "is a" specific html tag with specific attributes.
     *
     * @param string $type type of html tag is searching for.
     * @param mixed  $attributes specific attributes for html tag that is searching for.
     * 
     * @return boolean true on success, false otherwise.
     */
    public function isA($type, $attributes = [])
    {
        return $type === $this->type && $this->hasAttributesOfType($this, $attributes);
    }
    /**
     * Tells if there is any child of specific type with specific attributes.
     *
     * @param string $type type of html tag.
     * @param mixed  $attributes attributes associated to html tag.
     * 
     * @return boolean true if exists, otherwise false.
     */
    public function hasAChildOfType($type, $attributes = [])
    {
        $result = false;
        $children = $this->getChildren();
        foreach ($children as $child) {
            if ($child instanceof Html) {
                $result = $type === $child->getType() && $this->hasAttributesOfType($child, $attributes);
                if (true === $result) {
                    break;
                }
            }
        }
        return $result;
    }
    /**
     * Tells the number of children that belongs to especific html tag.
     *
     * @return int number of children.
     */
    public function numberOfChildren()
    {
        return $this->content->length();
    }
    /**
     * Returns html tag children.
     *
     * @return mixed whole set of children.
     */
    public function getChildren()
    {
        return $this->content->getContent();
    }
    /**
     * Returns the html tag child specified.
     *
     * @param int $id number of child.
     * 
     * @return mixed html object that represents a html's child.
     */
    public function getChild($id)
    {
        $children = $this->content->getContent();
        return isset($children[$id]) ? $children[$id] : null;
    }
    /**
     * Helper to get the string form of Html object.
     *
     * @return string string representation of html object.
     */
    public function toString()
    {
        return trim((string) $this);
    }
    /**
     * Magic method to get the string for Html object.
     *
     * @return string string representation of html object.
     */
    public function __toString()
    {
        $html_string = '<' . trim(
            $this->type . self::SPACE . $this->getAttributesToString()
        ) . '>' . $this->content . '</' . $this->type . ">n";
        
        return $html_string;
    }
    /**
     * Test if a html objects have a specific set of attributes
     *
     * @param mixed $html_object html object.
     * @param mixed $attributes attributes is searching for.
     * 
     * @return boolean true on success, false otherwise.
     */
    private function hasAttributesOfType($html_object, $attributes)
    {
        if (0 === count($attributes)) {
            return true;
        }
        $html = $html_object->getAttributesToArray();
        $mock_html = (new Html('undefined', $attributes))->getAttributesToArray();
        array_walk(
            $mock_html,
            function (&$value, $attribute) use ($html) {
                $value = isset($html[$attribute]) &&
                    count($value) === count($html[$attribute]) &&
                    (0 === count(array_diff($html[$attribute], $value)));
            }
        );
        return 1 === count(array_unique(array_values($mock_html))) && array_values($mock_html)[0];
    }
    /**
     * Returns string value of a specific html object attribute.
     *
     * @param string $name attribute name.
     * @param mixed  $with_value value associated to attribute.
     * 
     * @return mixed null if there is not match, otherwise string attributes values.
     */
    private function getAttributeWithValue($name, $with_value = null)
    {
        $attribute = array_filter(
            $this->getAttributes(),
            function ($attribute) use ($name, $with_value) {
                return ($name === $attribute->getName()) &&
                    (is_null($with_value) || $attribute->hasValue($with_value));
            }
        );
        return 0 === count($attribute) ? null : str_replace($name . '=', '', (string) end($attribute));
    }
}