Passed
Push — master ( db97d8...ab628c )
by Brent
03:19
created

Stitcher::parseVariables()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Brendt\Stitcher;
4
5
use AsyncInterop\Promise;
6
use Brendt\Stitcher\Exception\TemplateNotFoundException;
7
use Brendt\Stitcher\Site\Site;
8
use Symfony\Component\Config\FileLocator;
9
use Symfony\Component\DependencyInjection\ContainerBuilder;
10
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
11
use Symfony\Component\Filesystem\Filesystem;
12
use Symfony\Component\Finder\Finder;
13
use Symfony\Component\Finder\SplFileInfo;
14
use Symfony\Component\Yaml\Yaml;
15
16
/**
17
 * The Stitcher class is the core compiler of every Stitcher application. This class takes care of all routes, pages,
18
 * templates and data, and "stitches" everything together.
19
 *
20
 * The stitching process is done in several steps, with the final result being a fully rendered website in the
21
 * `directories.public` folder.
22
 */
23
class Stitcher
24
{
25
    /**
26
     * @var ContainerBuilder
27
     */
28
    protected static $container;
29
30
    /**
31
     * @var array
32
     */
33
    protected static $configDefaults = [
34
        'directories.src'    => './src',
35
        'directories.public' => './public',
36
        'directories.cache'  => './.cache',
37
        'meta'               => [],
38
        'minify'             => false,
39
        'engines.template'   => 'smarty',
40
        'engines.image'      => 'gd',
41
        'engines.optimizer'  => true,
42
        'engines.async'      => true,
43
        'caches.image'       => true,
44
        'optimizer.options'  => [],
45
    ];
46
47
    /**
48
     * A collection of promises representing Stitcher's state.
49
     *
50
     * @var Promise[]
51
     */
52
    private $promises = [];
53
54
    /**
55
     * @var string
56
     */
57
    private $srcDir;
58
59
    /**
60
     * @var string
61
     */
62
    private $publicDir;
63
64
    /**
65
     * @var string
66
     */
67
    private $templateDir;
68
69
    /**
70
     * @var SiteParser
71
     */
72
    private $siteParser;
73
74
    /**
75
     * @see \Brendt\Stitcher\Stitcher::create()
76
     *
77
     * @param string $srcDir
78
     * @param string $publicDir
79
     * @param string $templateDir
80
     */
81
    private function __construct(?string $srcDir = './src', ?string $publicDir = './public', ?string $templateDir = './src/template') {
82
        $this->srcDir = $srcDir;
83
        $this->publicDir = $publicDir;
84
        $this->templateDir = $templateDir;
85
    }
86
87
    /**
88
     * Static constructor
89
     *
90
     * @param string $configPath
91
     * @param array  $defaultConfig
92
     *
93
     * @return Stitcher
94
     *
95
     */
96
    public static function create(string $configPath = './config.yml', array $defaultConfig = []) : Stitcher {
97
        self::$container = new ContainerBuilder();
98
99
        $configPathParts = explode('/', $configPath);
100
        $configFileName = array_pop($configPathParts);
101
        $configPath = implode('/', $configPathParts) . '/';
102
        $configFiles = Finder::create()->files()->in($configPath)->name($configFileName)->depth(0);
103
        $srcDir = null;
104
        $publicDir = null;
105
        $templateDir = null;
106
107
        /** @var SplFileInfo $configFile */
108
        foreach ($configFiles as $configFile) {
109
            $fileConfig = Yaml::parse($configFile->getContents());
110
111
            $config = array_merge(
112
                self::$configDefaults,
113
                $fileConfig,
114
                Config::flatten($fileConfig),
115
                $defaultConfig
116
            );
117
118
            $config['directories.template'] = $config['directories.template'] ?? $config['directories.src'];
119
120
            foreach ($config as $key => $value) {
121
                self::$container->setParameter($key, $value);
122
            }
123
124
            $srcDir = $config['directories.src'] ?? $srcDir;
125
            $publicDir = $config['directories.public'] ?? $publicDir;
126
            $templateDir = $config['directories.template'] ?? $templateDir;
127
        }
128
129
        $stitcher = new self($srcDir, $publicDir, $templateDir);
130
        self::$container->set('stitcher', $stitcher);
131
132
        $serviceLoader = new YamlFileLoader(self::$container, new FileLocator(__DIR__));
133
        $serviceLoader->load('services.yml');
134
135
        return $stitcher;
136
    }
137
138
    /**
139
     * @param string $id
140
     *
141
     * @return mixed
142
     */
143
    public static function get(string $id) {
144
        return self::$container->get($id);
145
    }
146
147
    /**
148
     * @param string $key
149
     *
150
     * @return mixed
151
     */
152
    public static function getParameter(string $key) {
153
        return self::$container->getParameter($key);
154
    }
155
156
    /**
157
     * The core stitcher function. This function will compile the configured site and return an array of parsed
158
     * data.
159
     *
160
     * Compiling a site is done in the following steps.
161
     *
162
     *      - Load the site configuration @see \Brendt\Stitcher\Stitcher::loadSite()
163
     *      - Load all available templates @see \Brendt\Stitcher\Stitcher::loadTemplates()
164
     *      - Loop over all pages and transform every page with the configured adapters (in any are set) @see
165
     *      \Brendt\Stitcher\Stitcher::parseAdapters()
166
     *      - Loop over all transformed pages and parse the variables which weren't parsed by the page's adapters. @see
167
     *      \Brendt\Stitcher\Stitcher::parseVariables()
168
     *      - Add all variables to the template engine and render the HTML for each page.
169
     *
170
     * This function takes two optional parameters which are used to render pages on the fly when using the
171
     * developer controller. The first one, `routes` will take a string or array of routes which should be rendered,
172
     * instead of all available routes. The second one, `filterValue` is used to provide a filter when the
173
     * CollectionAdapter is used, and only one entry page should be rendered.
174
     *
175
     * @param string|array $routes
176
     * @param string       $filterValue
177
     *
178
     * @return array
179
     * @throws TemplateNotFoundException
180
     *
181
     * @see \Brendt\Stitcher\Stitcher::save()
182
     * @see \Brendt\Stitcher\Controller\DevController::run()
183
     * @see \Brendt\Stitcher\Adapter\CollectionAdapter::transform()
184
     */
185
    public function stitch($routes = [], string $filterValue = null) : array {
186
        /** @var SiteParser $siteParser */
187
        $siteParser = self::get('parser.site');
188
189
        return $siteParser->parse($routes, $filterValue);
0 ignored issues
show
Bug introduced by
It seems like $routes defined by parameter $routes on line 185 can also be of type string; however, Brendt\Stitcher\SiteParser::parse() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
190
    }
191
192
    /**
193
     * @param array $routes
194
     *
195
     * @return Site
196
     */
197
    public function loadSite(array $routes = []) : Site {
198
        /** @var SiteParser $siteParser */
199
        $siteParser = self::get('parser.site');
200
201
        return $siteParser->loadSite($routes);
202
    }
203
204
    /**
205
     * This function will save a stitched output to HTML files in the `directories.public` directory.
206
     *
207
     * @param array $blanket
208
     *
209
     * @see \Brendt\Stitcher\Stitcher::stitch()
210
     */
211
    public function save(array $blanket) {
212
        $fs = new Filesystem();
213
214
        foreach ($blanket as $path => $page) {
215
            if ($path === '/') {
216
                $path = 'index';
217
            }
218
219
            $fs->dumpFile($this->publicDir . "/{$path}.html", $page);
220
        }
221
    }
222
223
//    /**
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
224
//     * @param Promise|null $promise
225
//     *
226
//     * @return Stitcher
227
//     */
228
//    public function addPromise(?Promise $promise) : Stitcher {
229
//        if ($promise) {
230
//            $this->promises[] = $promise;
231
//        }
232
//
233
//        return $this;
234
//    }
235
236
//    /**
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
237
//     * @return Promise
238
//     */
239
//    public function getPromise() : Promise {
240
//        return \Amp\all($this->promises);
241
//    }
242
243
//    /**
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
244
//     * @param callable $callback
245
//     */
246
//    public function done(callable $callback) {
247
//        $donePromise = $this->getPromise();
248
//
249
//        $donePromise->when($callback);
250
//    }
251
252
}
253
254
255