Passed
Push — develop ( 45cc91...7eab64 )
by Brent
02:47
created

SiteParser::parsePage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
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\Page;
13
use Brendt\Stitcher\Site\Site;
14
use Brendt\Stitcher\Template\TemplateEngine;
15
use Brendt\Stitcher\Template\TemplatePlugin;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Finder\SplFileInfo;
18
use Symfony\Component\Yaml\Yaml;
19
20
class SiteParser
21
{
22
    /**
23
     * @var string
24
     */
25
    private $filter;
26
27
    /**
28
     * @var string
29
     */
30
    private $srcDir;
31
32
    /**
33
     * @var string
34
     */
35
    private $templateDir;
36
37
    /**
38
     * @var ParserFactory
39
     */
40
    private $parserFactory;
41
42
    /**
43
     * @var TemplateEngineFactory
44
     */
45
    private $templateEngineFactory;
46
47
    /**
48
     * @var AdapterFactory
49
     */
50
    private $adapterFactory;
51
52
    /**
53
     * @var HeaderCompilerFactory
54
     */
55
    private $headerCompilerFactory;
56
57
    /**
58
     * @var array
59
     */
60
    private $metaConfig;
61
62
    /**
63
     * @var TemplatePlugin
64
     */
65
    private $templatePlugin;
66
67
    /**
68
     * @var HeaderCompiler|null
69
     */
70
    private $headerCompiler;
71
72
    /**
73
     * @var TemplateEngine
74
     */
75
    private $templateEngine;
76
77
    /**
78
     * @var SplFileInfo[]
79
     */
80
    private $templates;
81
82
    /**
83
     * SiteParser constructor.
84
     *
85
     * @param string                $srcDir
86
     * @param string                $templateDir
87
     * @param TemplatePlugin        $templatePlugin
88
     * @param ParserFactory         $parserFactory
89
     * @param TemplateEngineFactory $templateEngineFactory
90
     * @param AdapterFactory        $adapterFactory
91
     * @param HeaderCompilerFactory $headerCompilerFactory
92
     * @param array                 $metaConfig
93
     */
94
    public function __construct(
95
        string $srcDir,
96
        string $templateDir,
97
        TemplatePlugin $templatePlugin,
98
        ParserFactory $parserFactory,
99
        TemplateEngineFactory $templateEngineFactory,
100
        AdapterFactory $adapterFactory,
101
        HeaderCompilerFactory $headerCompilerFactory,
102
        array $metaConfig = []
103
    ) {
104
        $this->srcDir = $srcDir;
105
        $this->templateDir = $templateDir;
106
        $this->templatePlugin = $templatePlugin;
107
        $this->parserFactory = $parserFactory;
108
        $this->templateEngineFactory = $templateEngineFactory;
109
        $this->adapterFactory = $adapterFactory;
110
        $this->headerCompilerFactory = $headerCompilerFactory;
111
        $this->metaConfig = $metaConfig;
112
113
        $this->headerCompiler = $this->headerCompilerFactory->getHeaderCompilerByEnvironment();
114
        $this->templateEngine = $this->templateEngineFactory->getDefault();
115
        $this->templates = $this->loadTemplates();
116
    }
117
118
    /**
119
     * Load a site from YAML configuration files in the `directories.src`/site directory.
120
     * All YAML files are loaded and parsed into Page objects and added to a Site collection.
121
     *
122
     * @param array $routes
123
     *
124
     * @return Site
125
     * @throws InvalidSiteException
126
     * @see \Brendt\Stitcher\Site\Page
127
     * @see \Brendt\Stitcher\Site\Site
128
     */
129
    public function loadSite(array $routes = []) : Site {
130
        /** @var SplFileInfo[] $files */
131
        $files = Finder::create()->files()->in("{$this->srcDir}/site")->name('*.yml');
132
        $site = new Site();
133
134
        foreach ($files as $file) {
135
            try {
136
                $fileContents = (array) Yaml::parse($file->getContents());
137
            } 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...
138
                throw new InvalidSiteException("{$file->getRelativePathname()}: {$e->getMessage()}");
139
            }
140
141
            foreach ($fileContents as $route => $data) {
142
                if (count($routes) && !in_array($route, $routes)) {
143
                    continue;
144
                }
145
146
                $page = new Page($route, $data, $this->createMeta());
147
                $site->addPage($page);
148
            }
149
        }
150
151
        return $site;
152
    }
153
154
    /**
155
     * Load all templates from either the `directories.template` directory. Depending on the configured template
156
     * engine, set with `engines.template`; .html or .tpl files will be loaded.
157
     *
158
     * @return SplFileInfo[]
159
     */
160
    public function loadTemplates() {
161
        $templateExtension = $this->templateEngine->getTemplateExtension();
162
163
        /** @var SplFileInfo[] $files */
164
        $files = Finder::create()->files()->in($this->templateDir)->name("*.{$templateExtension}");
165
        $templates = [];
166
167
        foreach ($files as $file) {
168
            $id = str_replace(".{$templateExtension}", '', $file->getRelativePathname());
169
            $templates[$id] = $file;
170
        }
171
        
172
        return $templates;
173
    }
174
175
    /**
176
     * Parse a path into usable data.
177
     *
178
     * @param array  $routes
179
     * @param string $filterValue
180
     *
181
     * @return array|mixed
182
     * @throws TemplateNotFoundException
183
     */
184
    public function parse($routes = [], string $filterValue = null) : array {
185
        $blanket = [];
186
187
        $site = $this->loadSite((array) $routes);
188
189
        foreach ($site as $page) {
190
            $templateIsset = isset($this->templates[$page->getTemplatePath()]);
191
192
            if (!$templateIsset) {
193
                if ($template = $page->getTemplatePath()) {
194
                    throw new TemplateNotFoundException("Template {$template} not found.");
195
                } else {
196
                    throw new TemplateNotFoundException('No template was set.');
197
                }
198
            }
199
200
            $pages = $this->parseAdapters($page, $filterValue);
201
202
            foreach ($pages as $entryPage) {
203
                $blanket[$entryPage->getId()] = $this->parsePage($entryPage);
204
            }
205
        }
206
207
        return $blanket;
208
    }
209
210
    /**
211
     * @param Page $page
212
     *
213
     * @return string
214
     */
215
    public function parsePage(Page $page) : string {
216
        $entryPage = $this->parseVariables($page);
217
        $entryPage->parseMeta($entryPage->getVariables());
218
219
        if ($this->headerCompiler) {
220
            $this->headerCompiler->compilePage($page);
221
        }
222
223
        $this->templatePlugin->setPage($entryPage);
224
        $this->templateEngine->addTemplateVariables($entryPage->getVariables());
225
226
        $pageTemplate = $this->templates[$page->getTemplatePath()];
227
        $result = $this->templateEngine->renderTemplate($pageTemplate);
228
229
        $this->templateEngine->clearTemplateVariables();
230
231
        return $result;
232
    }
233
234
    /**
235
     * This function takes a page and optional entry id. The page's adapters will be loaded and looped.
236
     * An adapter will transform a page's original configuration and variables to one or more pages.
237
     * An entry id can be provided as a filter. This filter can be used in an adapter to skip rendering unnecessary
238
     * pages. The filter parameter is used to render pages on the fly when using the developer controller.
239
     *
240
     * @param Page   $page
241
     * @param string $entryId
242
     *
243
     * @return Page[]
244
     *
245
     * @see  \Brendt\Stitcher\Adapter\Adapter::transform()
246
     * @see  \Brendt\Stitcher\Controller\DevController::run()
247
     */
248
    public function parseAdapters(Page $page, $entryId = null) {
249
        if (!$page->getAdapters()) {
250
            return [$page->getId() => $page];
251
        }
252
253
        $pages = [$page];
254
255
        foreach ($page->getAdapters() as $type => $adapterConfig) {
256
            $adapter = $this->adapterFactory->getByType($type);
257
258
            if ($entryId !== null) {
259
                $pages = $adapter->transform($pages, $entryId);
260
            } else {
261
                $pages = $adapter->transform($pages);
262
            }
263
        }
264
265
        return $pages;
266
    }
267
268
    /**
269
     * This function takes a Page object and parse its variables using a Parser. It will only parse variables which
270
     * weren't parsed already by an adapter.
271
     *
272
     * @param Page $page
273
     *
274
     * @return Page
275
     *
276
     * @see \Brendt\Stitcher\Factory\ParserFactory
277
     * @see \Brendt\Stitcher\Parser\Parser
278
     * @see \Brendt\Stitcher\Site\Page::isParsedVariable()
279
     */
280
    public function parseVariables(Page $page) {
281
        foreach ($page->getVariables() as $name => $value) {
282
            if ($page->isParsedVariable($name)) {
283
                continue;
284
            }
285
286
            $page
287
                ->setVariableValue($name, $this->getData($value))
288
                ->setVariableIsParsed($name);
289
        }
290
291
        return $page;
292
    }
293
294
    /**
295
     * @param string $filter
296
     *
297
     * @return SiteParser
298
     */
299
    public function setFilter(string $filter) : SiteParser {
300
        $this->filter = $filter;
301
302
        return $this;
303
    }
304
305
    /**
306
     * This function will get the parser based on the value. This value is parsed by the parser, or returned if no
307
     * suitable parser was found.
308
     *
309
     * @param $value
310
     *
311
     * @return mixed
312
     *
313
     * @see \Brendt\Stitcher\Factory\ParserFactory
314
     */
315
    private function getData($value) {
316
        $parser = $this->parserFactory->getByFileName($value);
317
318
        if (!$parser) {
319
            return $value;
320
        }
321
322
        return $parser->parse($value);
323
    }
324
325
    private function createMeta() : Meta {
326
        $meta = new Meta();
327
328
        return $meta;
329
    }
330
}
331