Passed
Push — develop ( 05f1f1...f46e70 )
by Brent
02:35
created

TemplatePlugin::file()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 5
nop 2
dl 0
loc 26
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
namespace Brendt\Stitcher\Template;
4
5
use Brendt\Html\Meta\Meta;
6
use Brendt\Image\ResponsiveFactory;
7
use Brendt\Stitcher\Factory\ParserFactory;
8
use Brendt\Stitcher\Site\Http\Header;
9
use Brendt\Stitcher\Site\Page;
10
use CSSmin;
11
use JSMin;
12
use Symfony\Component\Filesystem\Filesystem;
13
use Symfony\Component\Finder\Finder;
14
use Symfony\Component\Finder\SplFileInfo;
15
16
/**
17
 * This class provides functionality which can be used by template plugins/functions.
18
 */
19
class TemplatePlugin
20
{
21
22
    /**
23
     * @var string
24
     */
25
    private $publicDir;
26
27
    /**
28
     * @var string
29
     */
30
    private $srcDir;
31
32
    /**
33
     * @var ParserFactory
34
     */
35
    private $parserFactory;
36
37
    /**
38
     * @var ResponsiveFactory
39
     */
40
    private $responsiveFactory;
41
42
    /**
43
     * @var CSSmin
44
     */
45
    private $cssMinifier;
46
47
    /**
48
     * @var bool
49
     */
50
    private $minify;
51
52
    /**
53
     * @var Page
54
     */
55
    private $page;
56
57
    public function __construct(
58
        ParserFactory $parserFactory,
59
        ResponsiveFactory $responsiveFactory,
60
        CSSmin $cssMinifier,
61
        string $publicDir,
62
        string $srcDir,
63
        bool $minify
64
    ) {
65
        $this->parserFactory = $parserFactory;
66
        $this->responsiveFactory = $responsiveFactory;
67
        $this->cssMinifier = $cssMinifier;
68
        $this->publicDir = $publicDir;
69
        $this->srcDir = $srcDir;
70
        $this->minify = $minify;
71
    }
72
73
    /**
74
     * @param Page $page
75
     *
76
     * @return TemplatePlugin
77
     */
78
    public function setPage(Page $page) : TemplatePlugin {
79
        $this->page = $page;
80
81
        return $this;
82
    }
83
84
    /**
85
     * This function will read meta configuration from `meta` and output the corresponding meta tags.
86
     *
87
     * @param array $extra
88
     *
89
     * @return string
90
     */
91
    public function meta(array $extra = []) : string {
92
        $meta = $this->page ? $this->page->meta : new Meta();
93
94
        foreach ($extra as $name => $content) {
95
            $meta->name($name, $content);
96
        }
97
98
        return $meta->render();
99
    }
100
101
    /**
102
     * This function will take a source path and an optional inline parameter.
103
     * The CSS file will be copied from the source path to the public directory.
104
     * If the `minify` option is set to true in config.yml, the output will be minified.
105
     *
106
     * If the inline parameter is set, the output won't be copied to a public file,
107
     * but instead be outputted to an HTML string which can be included in a template.
108
     *
109
     * Files with the .scss and .sass extensions will be compiled to normal CSS files.
110
     *
111
     * @param string $src
112
     * @param bool   $inline Inline this resource
113
     * @param bool   $push   Use HTTP/2 server push to send this resource.
114
     *
115
     * @return string
116
     */
117
    public function css(string $src, bool $inline = false, bool $push = false) : string {
118
        $parser = $this->parserFactory->getByFileName($src);
119
        $data = $parser->parse($src);
120
121
        if ($this->minify) {
122
            $data = $this->cssMinifier->run($data);
123
        }
124
125
        if ($inline) {
126
            return "<style>{$data}</style>";
127
        }
128
        $srcParsed = preg_replace('/\.scss|\.sass/', '.css', $src);
129
        $fs = new Filesystem();
130
        $dst = "{$this->publicDir}/$srcParsed";
131
132
        if ($push) {
133
            $this->page->addHeader(Header::link("\"</{$srcParsed}>; rel=preload; as=style\""));
134
        }
135
136
        if ($fs->exists($dst)) {
137
            $fs->remove($dst);
138
        }
139
140
        $fs->dumpFile($dst, $data);
141
142
        return "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$srcParsed}\">";
143
    }
144
145
    /**
146
     * This function will take a source path and an optional inline parameter.
147
     * The JS file will be copied from the source path to the public directory.
148
     * If the `minify` option is set to true in config.yml, the output will be minified.
149
     *
150
     * If the inline parameter is set, the output won't be copied to a public file,
151
     * but instead be outputted to an HTML string which can be included in a template.
152
     *
153
     * @param string $src
154
     * @param bool   $inline Inline this resource
155
     * @param bool   $async
156
     * @param bool   $push   Use HTTP/2 server push to send this resource.
157
     *
158
     * @return string
159
     */
160
    public function js(string $src, bool $inline = false, bool $async = false, bool $push = false) : string {
161
        $parser = $this->parserFactory->getByFileName($src);
162
        $data = $parser->parse($src);
163
164
        if ($this->minify) {
165
            $data = JSMin::minify($data);
166
        }
167
168
        if ($inline) {
169
            return "<script>{$data}</script>";
170
        }
171
172
        $fs = new Filesystem();
173
        $dst = "{$this->publicDir}/$src";
174
175
        if ($push) {
176
            $this->page->addHeader(Header::link("\"</{$src}>; rel=preload; as=script\""));
177
        }
178
179
        if ($fs->exists($dst)) {
180
            $fs->remove($dst);
181
        }
182
183
        $fs->dumpFile($dst, $data);
184
        $result = "<script src=\"{$src}\"";
185
186
        if ($async) {
187
            $result .= ' async';
188
        }
189
190
        $result .= "></script>";
191
192
        return $result;
193
    }
194
195
    /**
196
     * Create a responsive image using brendt\responsive-images.
197
     *
198
     * @param      $src
199
     * @param bool $push Use HTTP/2 server push to send this resource.
200
     *
201
     * @return array
202
     *
203
     * @see \Brendt\Image\ResponsiveFactory
204
     */
205
    public function image(string $src, bool $push = false) : array {
206
        $image = $this->responsiveFactory->create($src);
207
208
        if (!$image) {
209
            return ['src' => null, 'srcset' => null, 'sizes' => null];
210
        }
211
212
        if ($push) {
213
            $this->page->addHeader(Header::link("\"</{$image->src()}>; rel=preload; as=image\""));
214
        }
215
216
        return [
217
            'src'    => $image->src(),
218
            'srcset' => $image->srcset(),
219
            'sizes'  => $image->sizes(),
220
        ];
221
    }
222
223
    /**
224
     * Create a public file from the src directory and return its path.
225
     *
226
     * @param string $src
227
     * @param bool   $push Use HTTP/2 server push to send this resource.
228
     *
229
     * @return null|string
230
     */
231
    public function file($src, bool $push = false) : ?string {
232
        $src = trim($src, '/');
233
        $files = Finder::create()->in($this->srcDir)->path($src)->getIterator();
234
        $files->rewind();
235
        /** @var SplFileInfo $file */
236
        $file = $files->current();
237
238
        if (!$file) {
239
            return null;
240
        }
241
242
        $fs = new Filesystem();
243
        $dst = "{$this->publicDir}/{$src}";
244
245
        if ($push) {
246
            $this->page->addHeader(Header::link("\"</{$src}>; rel=preload; as=document\""));
247
        }
248
249
        if ($fs->exists($dst)) {
250
            $fs->remove($dst);
251
        }
252
253
        $fs->dumpFile($dst, $file->getContents());
254
255
        return "/{$src}";
256
    }
257
258
}
259