Completed
Branch dbal-improvement (06db1a)
by Anton
03:59
created

IncludeBehaviour::contextNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6667
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Stempler\Behaviours;
9
10
use Spiral\Stempler\BehaviourInterface;
11
use Spiral\Stempler\HtmlTokenizer;
12
use Spiral\Stempler\Node;
13
use Spiral\Stempler\Supervisor;
14
15
/**
16
 * Replaces specified block (including tag) with external node, automatically uses inner tag
17
 * content as "context" block and all other tag attributes as additional node child.
18
 */
19
class IncludeBehaviour implements BehaviourInterface
20
{
21
    /**
22
     * Name of block used to represent import context.
23
     */
24
    const CONTEXT_BLOCK = 'context';
25
26
    /**
27
     * Path to be included (see Supervisor createNode).
28
     *
29
     * @var string
30
     */
31
    protected $path = '';
32
33
    /**
34
     * Import context includes everything between opening and closing tag.
35
     *
36
     * @var array
37
     */
38
    protected $context = [];
39
40
    /**
41
     * Context token.
42
     *
43
     * @var array
44
     */
45
    protected $token = [];
46
47
    /**
48
     * @var Supervisor
49
     */
50
    protected $supervisor = null;
51
52
    /**
53
     * @param Supervisor $supervisor
54
     * @param string     $path
55
     * @param array      $context
56
     * @param array      $token
57
     */
58
    public function __construct(Supervisor $supervisor, $path, array $context, array $token = [])
59
    {
60
        $this->supervisor = $supervisor;
61
        $this->path = $path;
62
63
        $this->context = $context;
64
        $this->token = $token;
65
    }
66
67
    /**
68
     * Create node to be injected into template at place of tag caused import.
69
     *
70
     * @return Node
71
     */
72
    public function createNode()
73
    {
74
        //Content of node to be imported
75
        $node = $this->supervisor->createNode($this->path, $this->token);
76
77
        //Let's register user defined blocks (context and attributes) as placeholders
78
        $node->mountBlock(
79
            self::CONTEXT_BLOCK,
80
            [],
81
            [$this->createPlaceholder(self::CONTEXT_BLOCK, $contextID)],
82
            true
83
        );
84
85
        foreach ($this->token[HtmlTokenizer::TOKEN_ATTRIBUTES] as $attribute => $value) {
86
            //Attributes counted as blocks to replace elements in included node
87
            $node->mountBlock($attribute, [], [$value], true);
88
        }
89
90
        //We now have to compile node content to pass it's body to parent node
91
        $content = $node->compile($dynamic);
92
93
        //Outer blocks (usually user attributes) can be exported to template using non default
94
        //rendering technique, for example every "extra" attribute can be passed to specific
95
        //template location. Stempler to decide.
96
        foreach ($this->supervisor->syntax()->blockExporters() as $exporter) {
97
            $content = $exporter->mountBlocks($content, $dynamic);
98
        }
99
100
        //Let's parse complied content without any imports (to prevent collision)
101
        $supervisor = clone $this->supervisor;
102
        $supervisor->flushImporters();
103
104
        //Outer content must be protected using unique names
105
        $rebuilt = new Node($supervisor, $supervisor->uniquePlaceholder(), $content);
106
107
        if (!empty($contextBlock = $rebuilt->findNode($contextID))) {
108
            //Now we can mount our content block
109
            $contextBlock->mountNode($this->contextNode());
110
        }
111
112
        return $rebuilt;
113
    }
114
115
    /**
116
     * Pack node context (everything between open and close tag).
117
     *
118
     * @return Node
119
     */
120
    protected function contextNode()
121
    {
122
        $context = '';
123
        foreach ($this->context as $token) {
124
            $context .= $token[HtmlTokenizer::TOKEN_CONTENT];
125
        }
126
127
        return new Node($this->supervisor, $this->supervisor->uniquePlaceholder(), $context);
128
    }
129
130
    /**
131
     * Create placeholder block (to be injected with inner blocks defined in context).
132
     *
133
     * @param string $name
134
     * @param string $blockID
135
     * @return string
136
     */
137
    protected function createPlaceholder($name, &$blockID)
138
    {
139
        $blockID = $name . '-' . $this->supervisor->uniquePlaceholder();
140
141
        //Short block declaration syntax
142
        return '${' . $blockID . '}';
143
    }
144
}