DerDu/MOC-Framework-Mark-V

View on GitHub
Component/Document/Vendor/UniversalXml/Source/Parser.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
namespace MOC\V\Component\Document\Vendor\UniversalXml\Source;

/**
 * Class Parser
 *
 * @package MOC\V\Component\Document\Vendor\UniversalXml\Source
 */
class Parser extends Mask
{

    /** @var array $Stack */
    private $Stack = array();
    /** @var null|Node $Result */
    private $Result = null;

    /**
     * @param Tokenizer $Tokenizer
     */
    function __construct(Tokenizer $Tokenizer)
    {

        /** @var Token $Token */
        foreach ((array)$Tokenizer->getResult() as $Token) {
            // Convert Token to Node
            $Node = new Node($Token);
            // Handle Token by Type
            if ($Token->isOpenTag()) {
                $this->processOpen($Node);
            } elseif ($Token->isCloseTag()) {
                // Get Parent (OpenTag)
                /** @var Node $Parent */
                $Parent = array_pop($this->Stack);
                // Handle Close by Type
                switch ($Parent->getType()) {
                    case $Parent::TYPE_CONTENT : {
                        $this->processCloseContent($Parent, $Tokenizer, $Token);
                        break;
                    }
                    case $Parent::TYPE_STRUCTURE : {
                        $this->processCloseStructure($Parent);
                        break;
                    }
                    case $Parent::TYPE_CDATA : {
                        $this->processCloseCDATA($Parent);
                        break;
                    }
                }
            } elseif ($Token->isShortTag()) {
                $this->processShort($Node);
            } elseif ($Token->isCDATATag()) {
                $this->processCDATA($Node);
            } elseif ($Token->isCommentTag()) {
                $this->processComment($Node);
            }
        }
        // Set parsed Stack as Result
        $this->Result = array_pop($this->Stack);
    }

    /**
     * @param Node $Node
     */
    private function processOpen(Node $Node)
    {

        // Set Parent Type to Structure
        if (!empty( $this->Stack )) {
            $Parent = array_pop($this->Stack);
            $Parent->setType($Parent::TYPE_STRUCTURE);
            array_push($this->Stack, $Parent);
        }
        // Add Node to Stack
        array_push($this->Stack, $Node);
    }

    /**
     * @param Node      $Parent
     * @param Tokenizer $Tokenizer
     * @param Token     $Token
     */
    private function processCloseContent(Node $Parent, Tokenizer $Tokenizer, Token $Token)
    {

        // Get Content
        $LengthName = strlen($Parent->getName()) + 1;
        $LengthAttribute = strlen($Parent->getAttributeString()) + 1;
        $LengthAttribute = ( $LengthAttribute == 1 ? 0 : $LengthAttribute );
        $Parent->setContent(
            substr(
                $Tokenizer->getContent(),

                $Parent->getPosition()
                + $LengthName
                + $LengthAttribute,

                ( $Token->getPosition() - $Parent->getPosition() )
                - ( $LengthName + 1 )
                - ( $LengthAttribute )
            )
        );
        // Do Parent Close
        $Ancestor = array_pop($this->Stack);
        $Ancestor->addChild($Parent);
        array_push($this->Stack, $Ancestor);
    }

    /**
     * @param Node $Parent
     */
    private function processCloseStructure(Node $Parent)
    {

        // Set Ancestor <-> Parent Relation
        /** @var Node $Ancestor */
        $Ancestor = array_pop($this->Stack);
        if (is_object($Ancestor)) {
            // Do Parent Close
            $Ancestor->addChild($Parent);
            array_push($this->Stack, $Ancestor);
        } else {
            // No Ancestor -> Parent = Root
            array_push($this->Stack, $Parent);
        }
    }

    /**
     * @param Node $Parent
     */
    private function processCloseCDATA(Node $Parent)
    {

        // Set Ancestor <-> Parent Relation
        /** @var Node $Ancestor */
        $Ancestor = array_pop($this->Stack);
        // Do Parent Close
        $Ancestor->addChild($Parent);
        array_push($this->Stack, $Ancestor);
    }

    /**
     * @param Node $Node
     */
    private function processShort(Node $Node)
    {

        // Set Ancestor <-> Node Relation
        /** @var Node $Parent */
        $Ancestor = array_pop($this->Stack);
        $Ancestor->setType($Ancestor::TYPE_STRUCTURE);
        // Do Node Close
        $Ancestor->addChild($Node);
        array_push($this->Stack, $Ancestor);
    }

    /**
     * @param Node $Node
     */
    private function processCDATA(Node $Node)
    {

        // Set Parent Type/Content
        /** @var Node $Parent */
        $Parent = array_pop($this->Stack);
        $Parent->setType($Parent::TYPE_CDATA);
        $Parent->setContent($Node->getName());
        $this->decodePayload($Parent, self::PATTERN_CDATA);
        // Do Node Close
        array_push($this->Stack, $Parent);
    }

    /**
     * @param Node $Node
     */
    private function processComment(Node $Node)
    {

        // Set Parent Type/Content
        /** @var Node $Parent */
        $Parent = array_pop($this->Stack);
        $Node->setType($Node::TYPE_COMMENT);
        $Node->setContent($Node->getName());
        $Node->setName('__COMMENT__');
        $this->decodePayload($Node, self::PATTERN_COMMENT);
        // Do Node Close
        $Parent->addChild($Node);
        array_push($this->Stack, $Parent);
    }

    /**
     * @return Node|null
     */
    public function getResult()
    {

        return $this->Result;
    }
}