Completed
Push — master ( 3af88c...d76c98 )
by Mewes
05:10
created

SyntaxCheckNodeVisitor::doEnterNode()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 21
rs 7.1428
cc 8
eloc 10
nc 5
nop 2
1
<?php
2
3
namespace MewesK\TwigExcelBundle\Twig\NodeVisitor;
4
5
use MewesK\TwigExcelBundle\Twig\Node\XlsNode;
6
use Twig_BaseNodeVisitor;
7
use Twig_Environment;
8
use Twig_Error_Syntax;
9
use Twig_Node;
10
use Twig_Node_Block;
11
use Twig_Node_Macro;
12
13
/**
14
 * Class SyntaxCheckNodeVisitor
15
 *
16
 * @package MewesK\TwigExcelBundle\Twig\NodeVisitor
17
 */
18
class SyntaxCheckNodeVisitor extends Twig_BaseNodeVisitor
19
{
20
    /**
21
     * @var array
22
     */
23
    protected $path = [];
24
25
    /**
26
     * {@inheritdoc}
27
     *
28
     * @throws Twig_Error_Syntax
29
     */
30
    protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
31
    {
32
        if (($node instanceof Twig_Node_Block || $node instanceof Twig_Node_Macro) && !$node->hasAttribute('twigExcelBundle') && $this->checkContainsXlsNode($node)) {
33
            if ($node instanceof Twig_Node_Block) {
34
                throw new Twig_Error_Syntax('Block tags do not work together with Twig tags provided by TwigExcelBundle. Please use \'xlsblock\' instead.');
35
            }
36
            elseif ($node instanceof Twig_Node_Macro) {
37
                throw new Twig_Error_Syntax('Macro tags do not work together with Twig tags provided by TwigExcelBundle. Please use \'xlsmacro\' instead.');
38
            }
39
        }
40
        elseif ($node instanceof XlsNode) {
41
            /**
42
             * @var XlsNode $node
43
             */
44
            $this->checkAllowedParents($node, $node->getAllowedParents());
45
        }
46
47
        $this->path[] = get_class($node);
48
49
        return $node;
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
56
    {
57
        array_pop($this->path);
58
59
        return $node;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function getPriority()
66
    {
67
        return 0;
68
    }
69
70
    //
71
    // Helper
72
    //
73
74
    /**
75
     * @param Twig_Node $node
76
     * @param array $allowedParents
77
     *
78
     * @throws Twig_Error_Syntax
79
     */
80
    protected function checkAllowedParents(Twig_Node $node, array $allowedParents)
81
    {
82
        $parentName = null;
83
84
        foreach (array_reverse($this->path) as $className) {
85
            if (strpos($className, 'MewesK\TwigExcelBundle\Twig\Node\Xls') === 0) {
86
                $parentName = $className;
87
                break;
88
            }
89
        }
90
91
        if ($parentName === null) {
92
            return;
93
        }
94
95
        foreach ($allowedParents as $className) {
96
            if ($className === $parentName) {
97
                return;
98
            }
99
        }
100
101
        // reset path since throwing an error prevents doLeaveNode to be called
102
        $this->path = [];
103
        throw new Twig_Error_Syntax(sprintf('Node "%s" is not allowed inside of Node "%s".', get_class($node), $parentName));
104
    }
105
106
    /**
107
     * @param Twig_Node $node
108
     * @return bool
109
     */
110
    private function checkContainsXlsNode(Twig_Node $node)
111
    {
112
        foreach ($node->getIterator() as $key => $subNode) {
113
            if ($node instanceof XlsNode) {
114
                return true;
115
            } elseif ($subNode instanceof Twig_Node && $subNode->count() > 0) {
116
                if ($this->checkContainsXlsNode($subNode)) {
117
                    return true;
118
                }
119
            }
120
        }
121
        return false;
122
    }
123
}
124