Passed
Push — master ( b8029f...b45126 )
by 世昌
02:31
created

CompilableTemplate::compiler()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace suda\application\template;
4
5
use Exception;
6
use ReflectionException;
7
use suda\application\Resource;
8
use suda\framework\runnable\Runnable;
9
use suda\framework\filesystem\FileSystem;
10
use suda\application\template\compiler\Compiler;
11
use suda\application\exception\NoTemplateFoundException;
12
13
/**
14
 * 可编译模板
15
 */
16
class CompilableTemplate extends RawTemplate
17
{
18
    /**
19
     * 模板源
20
     *
21
     * @var string
22
     */
23
    protected $source;
24
25
    /**
26
     * 模板配置
27
     *
28
     * @var array
29
     */
30
    protected $config;
31
32
    /**
33
     * 输出目录
34
     *
35
     * @var string
36
     */
37
    protected $output;
38
39
    /**
40
     * 编译器
41
     *
42
     * @var Compiler
43
     */
44
    protected static $compiler;
45
46
    /**
47
     * 检测已经拷贝的目录
48
     *
49
     * @var array
50
     */
51
    protected static $copyedStaticPaths = [];
52
53
    /**
54
     * 静态目录
55
     *
56
     * @var string
57
     */
58
    protected $staticPath;
59
60
    /**
61
     * 模板名
62
     *
63
     * @var string
64
     */
65
    protected $name;
66
67
    /**
68
     * PHP模板
69
     * @var bool
70
     */
71
    protected $raw;
72
73
    /**
74
     * 构建模板
75
     *
76
     * @param string $source
77
     * @param array $config
78
     * @param bool $raw
79
     */
80
    public function __construct(string $source, array $config = [], bool $raw = false)
81
    {
82
        parent::__construct('', []);
83
        $this->source = $source;
84
        $this->name = pathinfo($source, PATHINFO_FILENAME);
85
        $this->config = $config;
86
        $this->raw = $raw;
87
    }
88
89
    /**
90
     * @param string|null $name
91
     * @return string
92
     */
93
    protected function getStaticPath(?string $name = null)
94
    {
95
        $name = is_null($name) ? $this->config['static'] ?? 'static' : $name;
96
        return Resource::getPathByRelativePath($name, dirname($this->getSourcePath()));
97
    }
98
99
    /**
100
     * @param string|null $name
101
     * @return mixed|string
102
     */
103
    protected function getStaticOutputPath(?string $name = null)
104
    {
105
        $public = defined('SUDA_PUBLIC') ? constant('SUDA_PUBLIC') : '.';
106
        $path = $this->config['assets-public'] ?? $public . '/assets/' . $this->getStaticName($name);
107
        FileSystem::make($path);
108
        return $path;
109
    }
110
111
    /**
112
     * 获取编译后的路径
113
     *
114
     * @return string
115
     */
116
    public function getPath()
117
    {
118
        if ($this->isRaw()) {
119
            return $this->source;
120
        }
121
        $output = $this->config['output'] ?? constant('SUDA_DATA') . '/template';
122
        FileSystem::make($output);
123
        return $output . '/' . $this->name . '-' . substr(md5_file($this->getSourcePath()), 10, 8) . '.php';
124
    }
125
126
    /**
127
     * @return bool
128
     */
129
    public function isRaw(): bool
130
    {
131
        return $this->raw;
132
    }
133
134
    /**
135
     * 获取源路径
136
     *
137
     * @return string|null
138
     */
139
    public function getSourcePath(): ?string
140
    {
141
        return $this->source ?? null;
142
    }
143
144
    /**
145
     * 输出
146
     * @ignore-dump
147
     * @return string
148
     * @throws Exception
149
     */
150
    public function getRenderedString()
151
    {
152
        $this->compile();
153
        return parent::getRenderedString();
154
    }
155
156
    /**
157
     * 编译
158
     *
159
     * @return bool
160
     * @throws Exception
161
     */
162
    protected function compile()
163
    {
164
        if ($this->isCompiled() === false && ($sourcePath = $this->getSourcePath()) !== null) {
165
            $destPath = $this->getPath();
166
            $content = FileSystem::get($sourcePath);
167
            if ($content !== null) {
168
                $compiled = $this->compiler()->compileText($content, $this->config);
169
                FileSystem::make(dirname($destPath));
170
                FileSystem::put($destPath, $compiled);
171
            }
172
            return true;
173
        }
174
        return false;
175
    }
176
177
    /**
178
     * 检查是否编译过
179
     * @return bool
180
     */
181
    protected function isCompiled()
182
    {
183
        $sourcePath = $this->getSourcePath();
184
        if ($sourcePath === null) {
185
            throw new NoTemplateFoundException(
186
                'missing source ' . $this->name,
187
                E_USER_ERROR,
188
                $this->name,
189
                NoTemplateFoundException::T_SOURCE
190
            );
191
        }
192
        $source = FileSystem::exist($sourcePath);
193
        $dest = FileSystem::exist($this->getPath());
194
        $isDebug = defined('SUDA_DEBUG') ? constant('SUDA_DEBUG') : false;
195
        $notCompiled = $source === true && $dest === false;
196
        return ($notCompiled || $isDebug) === false;
197
    }
198
199
    /**
200
     * @param string $path
201
     * @throws Exception
202
     */
203
    public function include(string $path)
204
    {
205
        $subfix = $this->config['subfix'] ?? '';
206
        $included = new self(Resource::getPathByRelativePath($path . $subfix, dirname($this->source)), $this->config);
207
        $included->parent = $this;
208
        echo $included->getRenderedString();
209
    }
210
211
    /**
212
     * @param string|null $name
213
     * @return string
214
     */
215
    protected function getStaticPrefix(?string $name = null)
216
    {
217
        $this->prepareStaticSource($name);
218
        if (array_key_exists('assets-prefix', $this->config)) {
219
            $prefix = $this->config['assets-prefix'];
220
        } elseif (defined('SUDA_ASSETS')) {
221
            $prefix = constant('SUDA_ASSETS');
222
        } else {
223
            $prefix = '/assets';
224
        }
225
        return '/' . ltrim($prefix, '/') . '/' . $this->getStaticName($name);
226
    }
227
228
    /**
229
     * @param string|null $name
230
     */
231
    protected function prepareStaticSource(?string $name = null)
232
    {
233
        $isDebug = defined('SUDA_DEBUG') ? constant('SUDA_DEBUG') : false;
234
        $staticPath = $this->getStaticPath($name);
235
        if ($isDebug &&
236
            is_dir($staticPath) &&
237
            !in_array($staticPath, static::$copyedStaticPaths)) {
238
            FileSystem::copyDir($staticPath, $this->getStaticOutputPath($name));
239
            static::$copyedStaticPaths[] = $staticPath;
240
        }
241
    }
242
243
    /**
244
     * @param string|null $name
245
     * @return bool|mixed|string
246
     */
247
    protected function getStaticName(?string $name = null)
248
    {
249
        return $this->config['static-name'] ?? substr(md5($this->getStaticPath($name)), 0, 8);
250
    }
251
252
253
    /**
254
     * @return Compiler
255
     */
256
    protected function compiler()
257
    {
258
        if (static::$compiler === null) {
259
            static::$compiler = $this->createCompiler();
260
        }
261
        return static::$compiler;
262
    }
263
264
    /**
265
     * @return Compiler
266
     */
267
    protected function createCompiler(): Compiler
268
    {
269
        $compiler = new Compiler;
270
        $compiler->init();
271
        return $compiler;
272
    }
273
}
274