Passed
Push — master ( 9e4977...ad78b7 )
by Brent
02:46
created

Stitcher   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 14

Importance

Changes 0
Metric Value
dl 0
loc 229
rs 10
c 0
b 0
f 0
wmc 29
lcom 2
cbo 14

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A loadSite() 0 21 4
A loadTemplates() 0 14 3
C stitch() 0 43 8
A parseAdapters() 0 20 4
A parseVariables() 0 13 3
A save() 0 15 4
A getData() 0 9 2
1
<?php
2
3
namespace brendt\stitcher;
4
5
use brendt\stitcher\element\Page;
6
use brendt\stitcher\exception\InvalidSiteException;
7
use brendt\stitcher\exception\TemplateNotFoundException;
8
use brendt\stitcher\factory\AdapterFactory;
9
use brendt\stitcher\factory\ProviderFactory;
10
use brendt\stitcher\factory\TemplateEngineFactory;
11
use Symfony\Component\Filesystem\Filesystem;
12
use Symfony\Component\Finder\Finder;
13
use Symfony\Component\Finder\SplFileInfo;
14
use Symfony\Component\Yaml\Exception\ParseException;
15
use Symfony\Component\Yaml\Yaml;
16
use brendt\stitcher\engine\TemplateEngine;
17
use brendt\stitcher\element\Site;
18
19
class Stitcher {
20
21
    /**
22
     * @var SplFileInfo[]
23
     */
24
    protected $templates;
25
26
    /**
27
     * @var ProviderFactory
28
     */
29
    protected $factory;
30
31
    /**
32
     * @var string
33
     */
34
    private $root;
35
36
    /**
37
     * @var string
38
     */
39
    private $compileDir;
40
41
    /**
42
     * @var string
43
     */
44
    private $publicDir;
45
46
    /**
47
     * @var ProviderFactory
48
     */
49
    private $providerFactory;
50
51
    /**
52
     * @var AdapterFactory
53
     */
54
    private $adapterFactory;
55
56
    /**
57
     * @var TemplateEngine
58
     */
59
    private $templateEngine;
60
61
    /**
62
     * Stitcher constructor.
63
     */
64
    public function __construct() {
65
        $this->root = Config::get('directories.src');
66
        $this->publicDir = Config::get('directories.public');
67
        $this->compileDir = Config::get('directories.cache');
68
69
        $this->providerFactory = Config::getDependency('factory.provider');
70
        $this->adapterFactory = Config::getDependency('factory.adapter');
71
72
        /** @var TemplateEngineFactory $templateEngineFactory */
73
        $templateEngineFactory = Config::getDependency('factory.template.engine');
74
        $this->templateEngine = $templateEngineFactory->getByType(Config::get('engine'));
75
    }
76
77
    /**
78
     * @return Site
79
     * @throws InvalidSiteException
80
     */
81
    public function loadSite() {
82
        $site = new Site();
83
        $finder = new Finder();
84
        $files = $finder->files()->in("{$this->root}/site")->name('*.yml');
85
86
        foreach ($files as $file) {
87
            try {
88
                $fileContents = Yaml::parse($file->getContents());
89
            } catch (ParseException $e) {
90
                throw new InvalidSiteException("{$file->getRelativePathname()}: {$e->getMessage()}");
91
            }
92
93
            foreach ($fileContents as $route => $data) {
0 ignored issues
show
Bug introduced by
The expression $fileContents of type string|array|object<stdClass> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
94
                $page = new Page($route, $data);
95
96
                $site->addPage($page);
97
            }
98
        }
99
100
        return $site;
101
    }
102
103
    /**
104
     * @return SplFileInfo[]
105
     */
106
    public function loadTemplates() {
107
        $finder = new Finder();
108
        $templateExtension = $this->templateEngine->getTemplateExtension();
109
        $templateFolder = Config::get('directories.template') ? Config::get('directories.template') : Config::get('directories.src') . '/template';
110
        $files = $finder->files()->in($templateFolder)->name("*.{$templateExtension}");
111
        $templates = [];
112
113
        foreach ($files as $file) {
114
            $id = str_replace(".{$templateExtension}", '', $file->getRelativePathname());
115
            $templates[$id] = $file;
116
        }
117
118
        return $templates;
119
    }
120
121
    /**
122
     * @param string|array $routes
123
     * @param null         $filterValue
124
     *
125
     * @return array
126
     * @throws TemplateNotFoundException
127
     */
128
    public function stitch($routes = [], $filterValue= null) {
129
        $blanket = [];
130
131
        $site = $this->loadSite();
132
        $templates = $this->loadTemplates();
133
134
        if (is_string($routes)) {
135
            $routes = [$routes];
136
        }
137
138
        foreach ($site as $page) {
139
            $route = $page->getId();
140
141
            $skipRoute = count($routes) && !in_array($route, $routes);
142
            if ($skipRoute) {
143
                continue;
144
            }
145
146
            $templateIsset = isset($templates[$page->getTemplate()]);
147
148
            if (!$templateIsset) {
149
                if (isset($page['template'])) {
150
                    throw new TemplateNotFoundException("Template {$page['template']} not found.");
151
                } else {
152
                    throw new TemplateNotFoundException('No template was set.');
153
                }
154
            }
155
156
            $pages = $this->parseAdapters($page, $filterValue);
157
158
            $pageTemplate = $templates[$page->getTemplate()];
159
            foreach ($pages as $entryPage) {
160
                $entryPage = $this->parseVariables($entryPage);
161
162
                // Render each page
163
                $this->templateEngine->addTemplateVariables($entryPage->getVariables());
164
                $blanket[$entryPage->getId()] = $this->templateEngine->renderTemplate($pageTemplate);
165
                $this->templateEngine->clearTemplateVariables();
166
            }
167
        }
168
169
        return $blanket;
170
    }
171
172
    /**
173
     * @param Page $page
174
     * @param null $entryId
175
     *
176
     * @return Page[]
177
     */
178
    public function parseAdapters(Page $page, $entryId = null) {
179
        $pages = [];
180
181
        // TODO: this will bug with multiple adapters
182
        if (count($page->getAdapters())) {
183
            foreach ($page->getAdapters() as $type => $adapterConfig) {
184
                $adapter = $this->adapterFactory->getByType($type);
185
186
                if ($entryId) {
187
                    $pages = $adapter->transform($page, $entryId);
188
                } else {
189
                    $pages = $adapter->transform($page);
190
                }
191
            }
192
        } else {
193
            $pages = [$page->getId() => $page];
194
        }
195
196
        return $pages;
197
    }
198
199
    /**
200
     * @param Page $page
201
     *
202
     * @return Page
203
     */
204
    public function parseVariables(Page $page) {
205
        foreach ($page->getVariables() as $name => $value) {
206
            if ($page->isParsedField($name)) {
207
                continue;
208
            }
209
210
            $page
211
                ->setVariable($name, $this->getData($value))
212
                ->setParsedField($name);
213
        }
214
215
        return $page;
216
    }
217
218
    /**
219
     * @param array $blanket
220
     */
221
    public function save(array $blanket) {
222
        $fs = new Filesystem();
223
224
        if (!$fs->exists($this->publicDir)) {
225
            $fs->mkdir($this->publicDir);
226
        }
227
228
        foreach ($blanket as $path => $page) {
229
            if ($path === '/') {
230
                $path = 'index';
231
            }
232
233
            $fs->dumpFile($this->publicDir . "/{$path}.html", $page);
234
        }
235
    }
236
237
    private function getData($src) {
238
        $provider = $this->providerFactory->getProvider($src);
239
240
        if (!$provider) {
241
            return $src;
242
        }
243
244
        return $provider->parse($src);
245
    }
246
247
}
248
249
250