Completed
Push — master ( 3b9aa0...812432 )
by Anton
03:38
created

IncludeBlock   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 131
rs 10
c 0
b 0
f 0
wmc 8
lcom 1
cbo 4

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
B createNode() 0 42 4
A contextNode() 0 9 2
A createPlaceholder() 0 7 1
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Stempler\Behaviours;
10
11
use Spiral\Stempler\BehaviourInterface;
12
use Spiral\Stempler\HtmlTokenizer;
13
use Spiral\Stempler\Node;
14
use Spiral\Stempler\Supervisor;
15
16
/**
17
 * Replaces specified block (including tag) with external node, automatically uses inner tag
18
 * content as "context" block and all other tag attributes as additional node child.
19
 */
20
class IncludeBlock implements BehaviourInterface
21
{
22
    /**
23
     * Name of block used to represent import context.
24
     */
25
    const CONTEXT_BLOCK = 'context';
26
27
    /**
28
     * Path to be included (see Supervisor createNode).
29
     *
30
     * @var string
31
     */
32
    protected $path = '';
33
34
    /**
35
     * Import context includes everything between opening and closing tag.
36
     *
37
     * @var array
38
     */
39
    protected $context = [];
40
41
    /**
42
     * Context token.
43
     *
44
     * @var array
45
     */
46
    protected $token = [];
47
48
    /**
49
     * @var Supervisor
50
     */
51
    protected $supervisor = null;
52
53
    /**
54
     * @param Supervisor $supervisor
55
     * @param string     $path
56
     * @param array      $context
57
     * @param array      $token
58
     */
59
    public function __construct(
60
        Supervisor $supervisor,
61
        string $path,
62
        array $context,
63
        array $token = []
64
    ) {
65
        $this->supervisor = $supervisor;
66
        $this->path = $path;
67
68
        $this->context = $context;
69
        $this->token = $token;
70
    }
71
72
    /**
73
     * Create node to be injected into template at place of tag caused import.
74
     *
75
     * @return Node
76
     */
77
    public function createNode(): Node
78
    {
79
        //Content of node to be imported
80
        $node = $this->supervisor->createNode($this->path, $this->token);
81
82
        //Let's register user defined blocks (context and attributes) as placeholders
83
        $node->mountBlock(
84
            self::CONTEXT_BLOCK,
85
            [],
86
            [$this->createPlaceholder(self::CONTEXT_BLOCK, $contextID)],
87
            true
88
        );
89
90
        foreach ($this->token[HtmlTokenizer::TOKEN_ATTRIBUTES] as $attribute => $value) {
91
            //Attributes counted as blocks to replace elements in included node
92
            $node->mountBlock($attribute, [], [$value], true);
93
        }
94
95
        //We now have to compile node content to pass it's body to parent node
96
        $content = $node->compile($dynamic);
97
98
        //Outer blocks (usually user attributes) can be exported to template using non default
99
        //rendering technique, for example every "extra" attribute can be passed to specific
100
        //template location. Stempler to decide.
101
        foreach ($this->supervisor->getSyntax()->blockExporters() as $exporter) {
102
            $content = $exporter->mountBlocks($content, $dynamic);
1 ignored issue
show
Bug introduced by
It seems like $dynamic can also be of type null; however, Spiral\Stempler\ExporterInterface::mountBlocks() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
103
        }
104
105
        //Let's parse complied content without any imports (to prevent collision)
106
        $supervisor = clone $this->supervisor;
107
        $supervisor->flushImporters();
108
109
        //Outer content must be protected using unique names
110
        $rebuilt = new Node($supervisor, $supervisor->uniquePlaceholder(), $content);
111
112
        if (!empty($contextBlock = $rebuilt->findNode($contextID))) {
113
            //Now we can mount our content block
114
            $contextBlock->mountNode($this->contextNode());
115
        }
116
117
        return $rebuilt;
118
    }
119
120
    /**
121
     * Pack node context (everything between open and close tag).
122
     *
123
     * @return Node
124
     */
125
    protected function contextNode(): Node
126
    {
127
        $context = '';
128
        foreach ($this->context as $token) {
129
            $context .= $token[HtmlTokenizer::TOKEN_CONTENT];
130
        }
131
132
        return new Node($this->supervisor, $this->supervisor->uniquePlaceholder(), $context);
133
    }
134
135
    /**
136
     * Create placeholder block (to be injected with inner blocks defined in context).
137
     *
138
     * @param string      $name
139
     * @param string|null $blockID
140
     *
141
     * @return string
142
     */
143
    protected function createPlaceholder(string $name, string &$blockID = null): string
144
    {
145
        $blockID = $name . '-' . $this->supervisor->uniquePlaceholder();
146
147
        //Short block declaration syntax
148
        return '${' . $blockID . '}';
149
    }
150
}