Test Failed
Push — develop ( 2059dd...ab38af )
by Brent
05:07
created

Stitcher::parseAdapters()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 2
dl 0
loc 20
rs 9.2
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
    /**
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
    /**
237
     * @return Promise
238
     */
239
    public function getPromise() : Promise {
240
        return \Amp\all($this->promises);
0 ignored issues
show
Documentation introduced by
$this->promises is of type array<integer,object<AsyncInterop\Promise>>, but the function expects a array<integer,object<Promise>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
241
    }
242
243
    /**
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