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

Supervisor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Stempler;
10
11
use Spiral\Stempler\Behaviours\BlockBehaviour;
12
use Spiral\Stempler\Behaviours\ExtendsBehaviour;
13
use Spiral\Stempler\Behaviours\IncludeBehaviour;
14
use Spiral\Stempler\Exceptions\LoaderException;
15
use Spiral\Stempler\Exceptions\StemplerException;
16
use Spiral\Stempler\Importers\Stopper;
17
18
/**
19
 * Supervisors used to control node behaviours and syntax.
20
 */
21
class Supervisor implements SupervisorInterface
22
{
23
    /**
24
     * Used to create unique node names when required.
25
     *
26
     * @var int
27
     */
28
    private static $index = 0;
29
30
    /**
31
     * Active set of imports.
32
     *
33
     * @var ImporterInterface[]
34
     */
35
    private $importers = [];
36
37
    /**
38
     * @var SyntaxInterface
39
     */
40
    protected $syntax = null;
41
42
    /**
43
     * @var LoaderInterface
44
     */
45
    protected $loader = null;
46
47
    /**
48
     * @param LoaderInterface $loader
49
     * @param SyntaxInterface $syntax
50
     */
51
    public function __construct(LoaderInterface $loader, SyntaxInterface $syntax)
52
    {
53
        $this->loader = $loader;
54
        $this->syntax = $syntax;
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function syntax()
61
    {
62
        return $this->syntax;
63
    }
64
65
    /**
66
     * Add new elements import locator.
67
     *
68
     * @param ImporterInterface $import
69
     */
70
    public function registerImporter(ImporterInterface $import)
71
    {
72
        array_unshift($this->importers, $import);
73
    }
74
75
    /**
76
     * Active templater imports.
77
     *
78
     * @return ImporterInterface[]
79
     */
80
    public function getImporters()
81
    {
82
        return $this->importers;
83
    }
84
85
    /**
86
     * Remove all element importers.
87
     */
88
    public function flushImporters()
89
    {
90
        $this->importers = [];
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function tokenBehaviour(array $token, array $content, Node $node)
97
    {
98
        switch ($this->syntax->tokenType($token, $name)) {
99
            case SyntaxInterface::TYPE_BLOCK:
100
                //Tag declares block (section)
101
                return new BlockBehaviour($name);
102
103
            case SyntaxInterface::TYPE_EXTENDS:
104
                //Declares parent extending
105
                $extends = new ExtendsBehaviour(
106
                    $this->createNode($this->syntax->resolvePath($token), $token),
107
                    $token
108
                );
109
110
                //We have to combine parent imports with local one (this is why uses has to be defined
111
                //after extends tag!)
1 ignored issue
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
112
                $this->importers = $extends->parentImports();
113
114
                //Sending command to extend parent
115
                return $extends;
116
117
            case SyntaxInterface::TYPE_IMPORTER:
118
                //Implementation specific
119
                $this->registerImporter($this->syntax->createImporter($token, $this));
120
121
                //No need to include import tag into source
122
                return BehaviourInterface::SKIP_TOKEN;
123
        }
124
125
        //We now have to decide if element points to external view (source) to be imported
126
        foreach ($this->importers as $importer) {
127
            if ($importer->importable($name, $token)) {
128
                if ($importer instanceof Stopper) {
129
                    //Native importer tells us to treat this element as simple html
130
                    break;
131
                }
132
133
                //Let's include!
134
                return new IncludeBehaviour(
135
                    $this, $importer->resolvePath($name, $token), $content, $token
136
                );
137
            }
138
        }
139
140
        return BehaviourInterface::SIMPLE_TAG;
141
    }
142
143
    /**
144
     * Create node based on given location with identical supervisor (cloned).
145
     *
146
     * @param string $path
147
     * @param array  $token Context token.
148
     * @return Node
149
     * @throws StemplerException
150
     */
151
    public function createNode($path, array $token = [])
152
    {
153
        //We support dots!
154
        if (!empty($token)) {
155
            $path = str_replace('.', '/', $path);
156
        }
157
158
        try {
159
            $source = $this->loader->getSource($path);
160
        } catch (LoaderException $exception) {
161
            throw new StemplerException($exception->getMessage(), $token, 0, $exception);
162
        }
163
164
        try {
165
            return new Node(clone $this, $this->uniquePlaceholder(), $source);
166
        } catch (StemplerException $exception) {
167
            //Wrapping to clarify location of error
168
            throw $this->clarifyException($path, $exception);
169
        }
170
    }
171
172
    /**
173
     * Get unique placeholder name, unique names are required in some cases to correctly process
174
     * includes and etc.
175
     *
176
     * @return string
177
     */
178
    public function uniquePlaceholder()
179
    {
180
        return md5(self::$index++);
181
    }
182
183
    /**
184
     * Clarify exeption with it's actual location.
185
     *
186
     * @param string            $path
187
     * @param StemplerException $exception
188
     * @return StemplerException
189
     */
190
    protected function clarifyException($path, StemplerException $exception)
191
    {
192
        if (empty($exception->getToken())) {
193
            //Unable to locate
194
            return $exception;
195
        }
196
197
        //We will need only first tag line
198
        $target = explode("\n", $exception->getToken()[HtmlTokenizer::TOKEN_CONTENT])[0];
199
200
        //Let's try to locate place where exception was used
201
        $lines = explode("\n", $this->loader->getSource($path));
202
203
        foreach ($lines as $number => $line) {
204
            if (strpos($line, $target) !== false) {
205
                //We found where token were used (!!)
206
                $exception->setLocation($this->loader->localFilename($path), $number + 1);
207
208
                break;
209
            }
210
        }
211
212
        return $exception;
213
    }
214
}