Passed
Push — master ( 451245...2b5fd7 )
by Brent
03:56
created

SiteParser::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 24
nc 1
nop 10
dl 0
loc 27
rs 8.8571
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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