chippyash/Builder-Pattern

View on GitHub
src/Chippyash/BuilderPattern/Renderer/XmlRenderer.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php
/*
 * Builder Pattern Library
 *
 * @author Ashley Kitson <akitson@zf4.biz>
 * @copyright Ashley Kitson, UK, 2014
 * @licence GPL V3 or later : http://www.gnu.org/licenses/gpl.html
 * @link http://en.wikipedia.org/wiki/Builder_pattern
 */
namespace Chippyash\BuilderPattern\Renderer;

use Chippyash\BuilderPattern\RendererInterface;
use \Chippyash\BuilderPattern\BuilderInterface;

/**
 * Passes back the built data object converted to XML
 */
class XmlRenderer implements RendererInterface
{
    /**
     * Render the built data
     * 
     * @param BuilderInterface $builder
     * @return array
     */
    public function render(BuilderInterface $builder)
    {
        return $this->arrayToDom($builder->getResult())->saveXML();
    }
    
    /**
     * Convert an associative array into a DOMDocument
     * NB - works only for simple item data types
     * A root node of <root> will be set if do not specify an alternative
     *
     * @todo Extend to cater for complex item data types (objects etc)
     * @param array $arr Array to convert
     * @param string $root Root name for DOM
     * @see DOMUtil::domNodeToArray
     *
     * @return \DOMDocument
     */
    protected function arrayToDom(array $arr, $root = 'root')
    {
        $dom = new \DOMDocument();
        $rootEle = $dom->createElement($root);
        $this->arrayToDomNode($dom, $rootEle, $arr);
        $dom->appendChild($rootEle);

        return $dom;
    }

    /**
     * Recursive iteration through array to be converted to DOM
     *
     * @param \DOMDocument $dom
     * @param \DOMElement $node
     * @param array $arr
     */
    protected function arrayToDomNode(\DOMDocument $dom, \DOMElement $node, array $arr)
    {
        foreach ($arr as $key => $item) {
            $ref = null;
            if (is_numeric($key) || empty($key)) {
                if (is_numeric($key)) {
                    $ref = $key;
                }
                $key = 'item';
            }
            if (is_array($item)) {
                $newNode = $dom->createElement($key);
                if (!is_null($ref)) {
                    $attr = $dom->createAttribute('ref');
                    $attr->value = $ref;
                    $newNode->appendChild($attr);
                }
                $this->arrayToDomNode($dom, $newNode, $item);
                $node->appendChild($newNode);
            } elseif (is_object($item)) {
                $this->encodeObject($key, $item, $dom, $node);
            } else {
                $node->appendChild($dom->createElement($key, $item));
            }
        }
    }
    
    protected function encodeObject($key, $value, \DOMDocument $dom, \DOMElement $node) 
    {
        if (method_exists($value, '__toString')) {
            $node->appendChild($dom->createElement($key, (string) $value));
        } elseif (method_exists($value, 'toString')) {
            $node->appendChild($dom->createElement($key, $value->toString()));
        } elseif ($value instanceof \Serializable) {
            $node->appendChild($dom->createElement($key, serialize($value)));
        } else {
            if ($value instanceof IteratorAggregate) {
                $props = $value->getIterator();
                $propCollection = [];
                foreach ($props as $key => $value) {
                    $propCollection[$key] = $value;
                }
            } elseif ($value instanceof Iterator) {
                $props = $value;
                $propCollection = [];
                foreach ($props as $key => $value) {
                    $propCollection[$key] = $value;
                }
            } else {
                $propCollection = get_object_vars($value);
            }
            $newNode = $dom->createElement($key);
            foreach ($propCollection as $k => $v) {
                $newNode->appendChild($dom->createElement($k, $v));
            }
            $node->appendChild($newNode);
        }
    }
}