Passed
Push — develop ( 3e8c8e...6a4b14 )
by Brent
02:58
created

SiteParser::loadSite()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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