Completed
Pull Request — master (#58)
by Christophe
09:44 queued 06:23
created

ExtendsAttribute::convertBlockInnerIntoBlock()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 27
ccs 16
cts 16
cp 1
rs 8.5806
cc 4
eloc 13
nc 4
nop 2
crap 4
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
27 9
            $ancestors = $xp->query("ancestor::*[@t:block-inner or @t:block-outer or @t:extends]", $blockNode);
28
29 9
            if ($ancestors->length === 1) {
30 9
                $candidates[] = $blockNode;
31 9
            }
32 9
        }
33
34
        // having block-inner makes no sense when child of an t:extends (t:extend can have only t:block child)
35
        // so lets convert them to t:block nodes
36 9
        $candidates = $this->convertBlockInnerIntoBlock($candidates, $node);
37
38 9
        foreach ($candidates as $candidate) {
39 9
            if ($candidate->parentNode !== $node) {
40 9
                $candidate->parentNode->removeChild($candidate);
41 9
                $node->appendChild($candidate);
42 9
            }
43 9
        }
44 9
        if ($candidates) {
45 9
            foreach (iterator_to_array($node->childNodes) as $k => $item) {
46 9
                if (!in_array($item, $candidates, true)) {
47 9
                    $node->removeChild($item);
48 9
                }
49 9
            }
50 9
        }
51
52 9
        $context->compileChilds($node);
53
54 9
        $set = iterator_to_array($node->childNodes);
55 9
        if (count($set)) {
56 9
            $n = $node->ownerDocument->createTextNode("\n");
57 9
            array_unshift($set, $n);
58 9
        }
59 9
        $ext = $context->createControlNode("extends {$filename}");
60 9
        array_unshift($set, $ext);
61
62 9
        DOMHelper::replaceWithSet($node, $set);
63 9
    }
64
65
    /**
66
     * @param array $candidates
67
     * @param \DOMNode $node
68
     * @return array
69
     */
70 9
    private function convertBlockInnerIntoBlock(array $candidates, \DOMNode $node)
71
    {
72
        /**
73
         * @var $candidate \DOMElement
74
         */
75 9
        foreach ($candidates as $k => $candidate) {
76 9
            if ($candidate->hasAttributeNS(Twital::NS, "block-inner")) {
77
78 3
                $blockName = $candidate->getAttributeNS(Twital::NS, "block-inner");
79
80 3
                $block = $node->ownerDocument->createElementNS(Twital::NS, "block");
81 3
                $block->setAttribute("name", $blockName);
82
83 3
                $candidate->parentNode->insertBefore($block, $candidate);
84
85
                // move all child to the new block node
86 3
                while ($candidate->firstChild) {
87 3
                    $child = $candidate->removeChild($candidate->firstChild);
88 3
                    $block->appendChild($child);
89 3
                }
90 3
                $candidate->parentNode->removeChild($candidate);
91 3
                $candidates[$k] = $block;
92 3
            }
93 9
        }
94
95 9
        return $candidates;
96
    }
97
}
98