ExtendsAttribute::visit()   B
last analyzed

Complexity

Conditions 9
Paths 36

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
nc 36
nop 2
dl 0
loc 49
ccs 36
cts 36
cp 1
crap 9
rs 7.5571
c 0
b 0
f 0
1
<?php
2
namespace Goetas\Twital\Attribute;
3
4
use Goetas\Twital\Attribute as AttributeBase;
5
use Goetas\Twital\Compiler;
6
use Goetas\Twital\Helper\DOMHelper;
7
use Goetas\Twital\Twital;
8
9
/**
10
 * @author Asmir Mustafic <[email protected]>
11
 */
12
class ExtendsAttribute implements AttributeBase
13
{
14 9
    public function visit(\DOMAttr $att, Compiler $context)
15
    {
16 9
        $node = $att->ownerElement;
17
18 9
        $filename = '"' . $att->value . '"';
19
20
21 9
        $xp = new \DOMXPath($att->ownerDocument);
22 9
        $xp->registerNamespace("t", Twital::NS);
23
24 9
        $candidates = array();
25 9
        foreach ($xp->query(".//*[@t:block-inner or @t:block-outer]|.//t:*", $node) as $blockNode) {
26 9
            $ancestors = $xp->query("ancestor::*[@t:block-inner or @t:block-outer or @t:extends]", $blockNode);
27
28 9
            if ($ancestors->length === 1) {
29 9
                $candidates[] = $blockNode;
30 9
            }
31 9
        }
32
33
        // having block-inner makes no sense when child of an t:extends (t:extend can have only t:block child)
34
        // so lets convert them to t:block nodes
35 9
        $candidates = $this->convertBlockInnerIntoBlock($candidates, $node);
36
37 9
        foreach ($candidates as $candidate) {
38 9
            if ($candidate->parentNode !== $node) {
39 9
                $candidate->parentNode->removeChild($candidate);
40 9
                $node->appendChild($candidate);
41 9
            }
42 9
        }
43 9
        if ($candidates) {
44 9
            foreach (iterator_to_array($node->childNodes) as $k => $item) {
45 9
                if (!in_array($item, $candidates, true)) {
46 9
                    $node->removeChild($item);
47 9
                }
48 9
            }
49 9
        }
50
51 9
        $context->compileChilds($node);
52
53 9
        $set = iterator_to_array($node->childNodes);
54 9
        if (count($set)) {
55 9
            $n = $node->ownerDocument->createTextNode("\n");
56 9
            array_unshift($set, $n);
57 9
        }
58 9
        $ext = $context->createControlNode("extends {$filename}");
59 9
        array_unshift($set, $ext);
60
61 9
        DOMHelper::replaceWithSet($node, $set);
62 9
    }
63
64
    /**
65
     * @param array $candidates
66
     * @param \DOMNode $node
67
     * @return array
68
     */
69 9
    private function convertBlockInnerIntoBlock(array $candidates, \DOMNode $node)
70
    {
71
        /**
72
         * @var $candidate \DOMElement
73
         */
74 9
        foreach ($candidates as $k => $candidate) {
75 9
            if ($candidate->hasAttributeNS(Twital::NS, "block-inner")) {
76 3
                $blockName = $candidate->getAttributeNS(Twital::NS, "block-inner");
77
78 3
                $block = $node->ownerDocument->createElementNS(Twital::NS, "block");
79 3
                $block->setAttribute("name", $blockName);
80
81 3
                $candidate->parentNode->insertBefore($block, $candidate);
82
83
                // move all child to the new block node
84 3
                while ($candidate->firstChild) {
85 3
                    $child = $candidate->removeChild($candidate->firstChild);
86 3
                    $block->appendChild($child);
87 3
                }
88 3
                $candidate->parentNode->removeChild($candidate);
89 3
                $candidates[$k] = $block;
90 3
            }
91 9
        }
92
93 9
        return $candidates;
94
    }
95
}
96