Passed
Push — develop ( 7fa55c...bce364 )
by Brent
02:48
created

SiteParser   B

Complexity

Total Complexity 27

Size/Duplication

Total Lines 319
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
dl 0
loc 319
rs 7.8571
c 0
b 0
f 0
wmc 27
lcom 1
cbo 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 25 1
B loadSite() 0 24 6
A loadTemplates() 0 14 2
B parse() 0 25 5
A parsePage() 0 18 2
A parseAdapters() 0 19 4
A parseVariables() 0 13 3
A setFilter() 0 5 1
A getData() 0 9 2
A createMeta() 0 5 1
1
<?php
2
3
namespace Brendt\Stitcher;
4
5
use Brendt\Html\Meta\Meta;
6
use Brendt\Stitcher\Exception\TemplateNotFoundException;
7
use Brendt\Stitcher\Factory\AdapterFactory;
8
use Brendt\Stitcher\Factory\HeaderCompilerFactory;
9
use Brendt\Stitcher\Factory\ParserFactory;
10
use Brendt\Stitcher\Factory\TemplateEngineFactory;
11
use Brendt\Stitcher\Site\Http\HeaderCompiler;
12
use Brendt\Stitcher\Site\Meta\MetaCompiler;
13
use Brendt\Stitcher\Site\Page;
14
use Brendt\Stitcher\Site\Site;
15
use Brendt\Stitcher\Template\TemplateEngine;
16
use Brendt\Stitcher\Template\TemplatePlugin;
17
use Symfony\Component\Finder\Finder;
18
use Symfony\Component\Finder\SplFileInfo;
19
use Symfony\Component\Yaml\Yaml;
20
21
class SiteParser
22
{
23
    /**
24
     * @var string
25
     */
26
    private $filter;
27
28
    /**
29
     * @var string
30
     */
31
    private $srcDir;
32
33
    /**
34
     * @var string
35
     */
36
    private $templateDir;
37
38
    /**
39
     * @var ParserFactory
40
     */
41
    private $parserFactory;
42
43
    /**
44
     * @var TemplateEngineFactory
45
     */
46
    private $templateEngineFactory;
47
48
    /**
49
     * @var AdapterFactory
50
     */
51
    private $adapterFactory;
52
53
    /**
54
     * @var HeaderCompilerFactory
55
     */
56
    private $headerCompilerFactory;
57
58
    /**
59
     * @var array
60
     */
61
    private $metaConfig;
62
63
    /**
64
     * @var TemplatePlugin
65
     */
66
    private $templatePlugin;
67
68
    /**
69
     * @var HeaderCompiler|null
70
     */
71
    private $headerCompiler;
72
73
    /**
74
     * @var TemplateEngine
75
     */
76
    private $templateEngine;
77
78
    /**
79
     * @var SplFileInfo[]
80
     */
81
    private $templates;
82
83
    /**
84
     * @var MetaCompiler
85
     */
86
    private $metaCompiler;
87
88
    /**
89
     * SiteParser constructor.
90
     *
91
     * @param string                $srcDir
92
     * @param string                $templateDir
93
     * @param TemplatePlugin        $templatePlugin
94
     * @param ParserFactory         $parserFactory
95
     * @param TemplateEngineFactory $templateEngineFactory
96
     * @param AdapterFactory        $adapterFactory
97
     * @param HeaderCompilerFactory $headerCompilerFactory
98
     * @param MetaCompiler          $metaCompiler
99
     * @param array                 $metaConfig
100
     */
101
    public function __construct(
102
        string $srcDir,
103
        string $templateDir,
104
        TemplatePlugin $templatePlugin,
105
        ParserFactory $parserFactory,
106
        TemplateEngineFactory $templateEngineFactory,
107
        AdapterFactory $adapterFactory,
108
        HeaderCompilerFactory $headerCompilerFactory,
109
        MetaCompiler $metaCompiler,
110
        array $metaConfig = []
111
    ) {
112
        $this->srcDir = $srcDir;
113
        $this->templateDir = $templateDir;
114
        $this->templatePlugin = $templatePlugin;
115
        $this->parserFactory = $parserFactory;
116
        $this->templateEngineFactory = $templateEngineFactory;
117
        $this->adapterFactory = $adapterFactory;
118
        $this->headerCompilerFactory = $headerCompilerFactory;
119
        $this->metaCompiler = $metaCompiler;
120
        $this->metaConfig = $metaConfig;
121
122
        $this->headerCompiler = $this->headerCompilerFactory->getHeaderCompilerByEnvironment();
123
        $this->templateEngine = $this->templateEngineFactory->getDefault();
124
        $this->templates = $this->loadTemplates();
125
    }
126
127
    /**
128
     * Load a site from YAML configuration files in the `directories.src`/site directory.
129
     * All YAML files are loaded and parsed into Page objects and added to a Site collection.
130
     *
131
     * @param array $routes
132
     *
133
     * @return Site
134
     * @throws InvalidSiteException
135
     * @see \Brendt\Stitcher\Site\Page
136
     * @see \Brendt\Stitcher\Site\Site
137
     */
138
    public function loadSite(array $routes = []) : Site {
139
        /** @var SplFileInfo[] $files */
140
        $files = Finder::create()->files()->in("{$this->srcDir}/site")->name('*.yml');
141
        $site = new Site();
142
143
        foreach ($files as $file) {
144
            try {
145
                $fileContents = (array) Yaml::parse($file->getContents());
146
            } catch (ParseException $e) {
0 ignored issues
show
Bug introduced by
The class Brendt\Stitcher\ParseException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
147
                throw new InvalidSiteException("{$file->getRelativePathname()}: {$e->getMessage()}");
148
            }
149
150
            foreach ($fileContents as $route => $data) {
151
                if (count($routes) && !in_array($route, $routes)) {
152
                    continue;
153
                }
154
155
                $page = new Page($route, $data, $this->createMeta());
156
                $site->addPage($page);
157
            }
158
        }
159
160
        return $site;
161
    }
162
163
    /**
164
     * Load all templates from either the `directories.template` directory. Depending on the configured template
165
     * engine, set with `engines.template`; .html or .tpl files will be loaded.
166
     *
167
     * @return SplFileInfo[]
168
     */
169
    public function loadTemplates() {
170
        $templateExtension = $this->templateEngine->getTemplateExtension();
171
172
        /** @var SplFileInfo[] $files */
173
        $files = Finder::create()->files()->in($this->templateDir)->name("*.{$templateExtension}");
174
        $templates = [];
175
176
        foreach ($files as $file) {
177
            $id = str_replace(".{$templateExtension}", '', $file->getRelativePathname());
178
            $templates[$id] = $file;
179
        }
180
        
181
        return $templates;
182
    }
183
184
    /**
185
     * Parse a path into usable data.
186
     *
187
     * @param array  $routes
188
     * @param string $filterValue
189
     *
190
     * @return array|mixed
191
     * @throws TemplateNotFoundException
192
     */
193
    public function parse($routes = [], string $filterValue = null) : array {
194
        $blanket = [];
195
196
        $site = $this->loadSite((array) $routes);
197
198
        foreach ($site as $page) {
199
            $templateIsset = isset($this->templates[$page->getTemplatePath()]);
200
201
            if (!$templateIsset) {
202
                if ($template = $page->getTemplatePath()) {
203
                    throw new TemplateNotFoundException("Template {$template} not found.");
204
                } else {
205
                    throw new TemplateNotFoundException('No template was set.');
206
                }
207
            }
208
209
            $pages = $this->parseAdapters($page, $filterValue);
210
211
            foreach ($pages as $entryPage) {
212
                $blanket[$entryPage->getId()] = $this->parsePage($entryPage);
213
            }
214
        }
215
216
        return $blanket;
217
    }
218
219
    /**
220
     * @param Page $page
221
     *
222
     * @return string
223
     */
224
    public function parsePage(Page $page) : string {
225
        $entryPage = $this->parseVariables($page);
226
        $this->metaCompiler->compilePage($page);
227
228
        $this->templatePlugin->setPage($entryPage);
229
        $this->templateEngine->addTemplateVariables($entryPage->getVariables());
230
231
        $pageTemplate = $this->templates[$page->getTemplatePath()];
232
        $result = $this->templateEngine->renderTemplate($pageTemplate);
233
        
234
        if ($this->headerCompiler) {
235
            $this->headerCompiler->compilePage($page);
236
        }
237
238
        $this->templateEngine->clearTemplateVariables();
239
240
        return $result;
241
    }
242
243
    /**
244
     * This function takes a page and optional entry id. The page's adapters will be loaded and looped.
245
     * An adapter will transform a page's original configuration and variables to one or more pages.
246
     * An entry id can be provided as a filter. This filter can be used in an adapter to skip rendering unnecessary
247
     * pages. The filter parameter is used to render pages on the fly when using the developer controller.
248
     *
249
     * @param Page   $page
250
     * @param string $entryId
251
     *
252
     * @return Page[]
253
     *
254
     * @see  \Brendt\Stitcher\Adapter\Adapter::transform()
255
     * @see  \Brendt\Stitcher\Controller\DevController::run()
256
     */
257
    public function parseAdapters(Page $page, $entryId = null) {
258
        if (!$page->getAdapters()) {
259
            return [$page->getId() => $page];
260
        }
261
262
        $pages = [$page];
263
264
        foreach ($page->getAdapters() as $type => $adapterConfig) {
265
            $adapter = $this->adapterFactory->getByType($type);
266
267
            if ($entryId !== null) {
268
                $pages = $adapter->transform($pages, $entryId);
269
            } else {
270
                $pages = $adapter->transform($pages);
271
            }
272
        }
273
274
        return $pages;
275
    }
276
277
    /**
278
     * This function takes a Page object and parse its variables using a Parser. It will only parse variables which
279
     * weren't parsed already by an adapter.
280
     *
281
     * @param Page $page
282
     *
283
     * @return Page
284
     *
285
     * @see \Brendt\Stitcher\Factory\ParserFactory
286
     * @see \Brendt\Stitcher\Parser\Parser
287
     * @see \Brendt\Stitcher\Site\Page::isParsedVariable()
288
     */
289
    public function parseVariables(Page $page) {
290
        foreach ($page->getVariables() as $name => $value) {
291
            if ($page->isParsedVariable($name)) {
292
                continue;
293
            }
294
295
            $page
296
                ->setVariableValue($name, $this->getData($value))
297
                ->setVariableIsParsed($name);
298
        }
299
300
        return $page;
301
    }
302
303
    /**
304
     * @param string $filter
305
     *
306
     * @return SiteParser
307
     */
308
    public function setFilter(string $filter) : SiteParser {
309
        $this->filter = $filter;
310
311
        return $this;
312
    }
313
314
    /**
315
     * This function will get the parser based on the value. This value is parsed by the parser, or returned if no
316
     * suitable parser was found.
317
     *
318
     * @param $value
319
     *
320
     * @return mixed
321
     *
322
     * @see \Brendt\Stitcher\Factory\ParserFactory
323
     */
324
    private function getData($value) {
325
        $parser = $this->parserFactory->getByFileName($value);
326
327
        if (!$parser) {
328
            return $value;
329
        }
330
331
        return $parser->parse($value);
332
    }
333
334
    private function createMeta() : Meta {
335
        $meta = new Meta();
336
337
        return $meta;
338
    }
339
}
340