StaticAppGenerator::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
nc 2
nop 9
dl 0
loc 29
rs 9.7666
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 PiedWeb\CMSBundle\Extension\StaticGenerator;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use PiedWeb\CMSBundle\Entity\PageInterface as Page;
7
use PiedWeb\CMSBundle\Repository\PageRepository;
8
use PiedWeb\CMSBundle\Service\App;
9
use PiedWeb\CMSBundle\Service\PageCanonicalService as PageCanonical;
10
use PiedWeb\CMSBundle\Utils\GenerateLivePathForTrait;
11
use PiedWeb\CMSBundle\Utils\KernelTrait;
12
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
13
use Symfony\Component\Filesystem\Filesystem;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\RequestStack;
16
use Symfony\Component\HttpKernel\KernelInterface;
17
use Symfony\Component\Routing\RouterInterface;
18
use Symfony\Contracts\Translation\TranslatorInterface;
19
use Twig\Environment as Twig;
20
use WyriHaximus\HtmlCompress\Factory as HtmlCompressor;
21
use WyriHaximus\HtmlCompress\HtmlCompressorInterface;
22
23
/**
24
 * Generate 1 App.
25
 */
26
class StaticAppGenerator
27
{
28
    use GenerateLivePathForTrait;
29
    use KernelTrait;
30
31
    /**
32
     * Contain files relative to SEO wich will be hard copied.
33
     *
34
     * @var array
35
     */
36
    protected $robotsFiles = ['robots.txt'];
37
38
    /**
39
     * @var array
40
     */
41
    protected $dontCopy = ['index.php', '.htaccess'];
42
43
    /**
44
     * @var EntityManagerInterface
45
     */
46
    protected $em;
47
48
    /**
49
     * @var Filesystem
50
     */
51
    protected $filesystem;
52
53
    /**
54
     * @var Twig
55
     */
56
    protected $twig;
57
58
    /**
59
     * @var string
60
     */
61
    protected $webDir;
62
63
    /**
64
     * @var array
65
     */
66
    protected $apps;
67
    protected $app;
68
    protected $staticDomain;
69
    protected $mustGetPagesWithoutHost = true;
70
71
    /** var @string */
72
    protected $staticDir;
73
74
    /**
75
     * @var RequestStack
76
     */
77
    protected $requesStack;
78
79
    /**
80
     * @var \PiedWeb\CMSBundle\Service\PageCanonicalService
81
     */
82
    protected $pageCanonical;
83
84
    /**
85
     * @var TranslatorInterface
86
     */
87
    protected $translator;
88
89
    /**
90
     * @var HtmlCompressorInterface
91
     */
92
    protected $parser;
93
94
    /**
95
     * @var ParameterBagInterface
96
     */
97
    protected $params;
98
99
    /**
100
     * @var RouterInterface
101
     */
102
    protected $router;
103
104
    /**
105
     * Used in .htaccess generation.
106
     *
107
     * @var string
108
     */
109
    protected $redirections = '';
110
111
    public function __construct(
112
        EntityManagerInterface $em,
113
        Twig $twig,
114
        ParameterBagInterface $params,
115
        RequestStack $requesStack,
116
        PageCanonical $pageCanonical,
117
        TranslatorInterface $translator,
118
        RouterInterface $router,
119
        string $webDir,
120
        KernelInterface $kernel
121
    ) {
122
        $this->em = $em;
123
        $this->filesystem = new Filesystem();
124
        $this->twig = $twig;
125
        $this->params = $params;
126
        $this->requesStack = $requesStack;
127
        $this->webDir = $webDir;
128
        $this->pageCanonical = $pageCanonical;
129
        $this->translator = $translator;
130
        $this->router = $router;
131
        $this->apps = $this->params->get('pwc.apps');
132
        $this->parser = HtmlCompressor::construct();
133
134
        if (! method_exists($this->filesystem, 'dumpFile')) {
135
            throw new \RuntimeException('Method dumpFile() is not available. Upgrade your Filesystem.');
136
        }
137
138
        static::loadKernel($kernel);
139
        $this->kernel = $kernel;
140
    }
141
142
    public function generateAll($filter = null)
143
    {
144
        foreach ($this->apps as $app) {
145
            if ($filter && ! \in_array($filter, $app->getHost())) {
146
                continue;
147
            }
148
            $this->generate($app, $this->mustGetPagesWithoutHost);
149
            //$this->generateStaticApp($app);
150
151
            $this->mustGetPagesWithoutHost = false;
152
        }
153
154
        return true;
155
    }
156
157
    public function generateFromHost($host)
158
    {
159
        return $this->generateAll($host);
160
    }
161
162
    /**
163
     * Main Logic is here.
164
     *
165
     * @throws \RuntimeException
166
     * @throws \LogicException
167
     */
168
    public function generate($app, $mustGetPagesWithoutHost = false)
169
    {
170
        $this->app = new App($app['hosts'][0], [$app]);
171
        $this->mustGetPagesWithoutHost = $mustGetPagesWithoutHost;
172
173
        $this->filesystem->remove($this->app->getStaticDir());
174
        $this->generatePages();
175
        $this->generateSitemaps();
176
        $this->generateErrorPages();
177
        $this->copyRobotsFiles();
178
        $this->generateServerManagerFile();
179
        $this->copyAssets();
180
        $this->copyMediaToDownload();
181
    }
182
183
    /**
184
     * Symlink doesn't work on github page, symlink only for apache if conf say OK to symlink.
185
     */
186
    protected function mustSymlink()
187
    {
188
        return $this->app->get('static_generateForApache') ? $this->app->get('static_symlinkMedia') : false;
189
    }
190
191
    /**
192
     * Generate .htaccess for Apache or CNAME for github
193
     * Must be run after generatePages() !!
194
     */
195
    protected function generateServerManagerFile()
196
    {
197
        if ($this->app->get('static_generateForApache')) {
198
            $this->generateHtaccess();
199
        } else { //if ($this->app['static_generateForGithubPages'])) {
200
            $this->generateCname();
201
        }
202
    }
203
204
    /**
205
     * Copy files relative to SEO (robots, sitemaps, etc.).
206
     */
207
    protected function copyRobotsFiles(): void
208
    {
209
        array_map([$this, 'copy'], $this->robotsFiles);
210
    }
211
212
    // todo
213
    // docs
214
    // https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
215
    protected function generateCname()
216
    {
217
        $this->filesystem->dumpFile($this->app->getStaticDir().'/CNAME', $this->app->getMainHost());
218
    }
219
220
    protected function generateHtaccess()
221
    {
222
        $htaccess = $this->twig->render('@PiedWebCMS/static/htaccess.twig', [
223
            'domain' => $this->app->getMainHost(),
224
            'redirections' => $this->redirections,
225
        ]);
226
        $this->filesystem->dumpFile($this->app->getStaticDir().'/.htaccess', $htaccess);
227
    }
228
229
    protected function copy(string $file): void
230
    {
231
        if (file_exists($file)) {
232
            copy(
233
                str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$file),
234
                $this->app->getStaticDir().'/'.$file
235
            );
236
        }
237
    }
238
239
    /**
240
     * Copy (or symlink) for all assets in public
241
     * (and media previously generated by liip in public).
242
     */
243
    protected function copyAssets(): void
244
    {
245
        $symlink = $this->mustSymlink();
246
247
        $dir = dir($this->webDir);
248
        while (false !== $entry = $dir->read()) {
249
            if ('.' == $entry || '..' == $entry) {
250
                continue;
251
            }
252
            if (! \in_array($entry, $this->robotsFiles) && ! \in_array($entry, $this->dontCopy)) {
253
                //$this->symlink(
254
                if (true === $symlink) {
255
                    $this->filesystem->symlink(
256
                        str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$entry),
257
                        $this->app->getStaticDir().'/'.$entry
258
                    );
259
                } else {
260
                    $action = is_file($this->webDir.'/'.$entry) ? 'copy' : 'mirror';
261
                    $this->filesystem->$action($this->webDir.'/'.$entry, $this->app->getStaticDir().'/'.$entry);
262
                }
263
            }
264
        }
265
        $dir->close();
266
    }
267
268
    /**
269
     * Copy or Symlink "not image" media to download folder.
270
     *
271
     * @return void
272
     */
273
    protected function copyMediaToDownload()
274
    {
275
        $symlink = $this->mustSymlink();
276
277
        if (! file_exists($this->app->getStaticDir().'/download')) {
278
            $this->filesystem->mkdir($this->app->getStaticDir().'/download/');
279
            $this->filesystem->mkdir($this->app->getStaticDir().'/download/media');
280
        }
281
282
        $dir = dir($this->webDir.'/../media');
283
        while (false !== $entry = $dir->read()) {
284
            if ('.' == $entry || '..' == $entry) {
285
                continue;
286
            }
287
            // if the file is an image, it's ever exist (maybe it's slow to check every files)
288
            if (! file_exists($this->webDir.'/media/default/'.$entry)) {
289
                if (true === $symlink) {
290
                    $this->filesystem->symlink(
291
                        '../../../media/'.$entry,
292
                        $this->app->getStaticDir().'/download/media/'.$entry
293
                    );
294
                } else {
295
                    $this->filesystem->copy(
296
                        $this->webDir.'/../media/'.$entry,
297
                        $this->app->getStaticDir().'/download/media/'.$entry
298
                    );
299
                }
300
            }
301
        }
302
303
        //$this->filesystem->$action($this->webDir.'/../media', $this->app->getStaticDir().'/download/media');
304
    }
305
306
    protected function generateSitemaps(): void
307
    {
308
        foreach (explode('|', $this->params->get('pwc.locales')) as $locale) {
309
            foreach (['txt', 'xml'] as $format) {
310
                $this->generateSitemap($locale, $format);
311
            }
312
313
            $this->generateFeed($locale);
314
        }
315
    }
316
317
    protected function generateSitemap($locale, $format)
318
    {
319
        $liveUri = $this->generateLivePathFor(
320
            $this->app->getMainHost(),
321
            'piedweb_cms_page_sitemap',
322
            ['locale' => $locale, '_format' => $format]
323
        );
324
        $staticFile = $this->app->getStaticDir().'/sitemap'.$locale.'.'.$format; // todo get it from URI removing host
325
        $this->saveAsStatic($liveUri, $staticFile);
326
327
        if ($this->params->get('locale') == $locale ? '' : '.'.$locale) {
328
            $staticFile = $this->app->getStaticDir().'/sitemap.'.$format;
329
            $this->saveAsStatic($liveUri, $staticFile);
330
        }
331
    }
332
333
    protected function generateFeed($locale)
334
    {
335
        $liveUri = $this->generateLivePathFor(
336
            $this->app->getMainHost(),
337
            'piedweb_cms_page_main_feed',
338
            ['locale' => $locale]
339
        );
340
        $staticFile = $this->app->getStaticDir().'/feed'.$locale.'.xml';
341
        $this->saveAsStatic($liveUri, $staticFile);
342
343
        if ($this->params->get('locale') == $locale ? '' : '.'.$locale) {
344
            $staticFile = $this->app->getStaticDir().'/feed.xml';
345
            $this->saveAsStatic($liveUri, $staticFile);
346
        }
347
    }
348
349
    /**
350
     * The function cache redirection found during generatePages and
351
     * format in self::$redirection the content for the .htaccess.
352
     *
353
     * @return void
354
     */
355
    protected function addRedirection(Page $page)
356
    {
357
        $this->redirections .= 'Redirect ';
358
        $this->redirections .= $page->getRedirectionCode().' ';
359
        $this->redirections .= $this->pageCanonical->generatePathForPage($page->getRealSlug());
360
        $this->redirections .= ' '.$page->getRedirection();
361
        $this->redirections .= PHP_EOL;
362
    }
363
364
    protected function generatePages(): void
365
    {
366
        $qb = $this->getPageRepository()->getQueryToFindPublished('p');
367
        $qb = $this->getPageRepository()->andHost($qb, $this->app->getMainHost(), $this->mustGetPagesWithoutHost);
368
        $pages = $qb->getQuery()->getResult();
369
370
        foreach ($pages as $page) {
371
            $this->generatePage($page);
372
            //if ($page->getRealSlug()) $this->generateFeedFor($page);
373
        }
374
    }
375
376
    protected function generatePage(Page $page)
377
    {
378
        // check if it's a redirection
379
        if (false !== $page->getRedirection()) {
380
            $this->addRedirection($page);
381
382
            return;
383
        }
384
385
        $this->saveAsStatic($this->generateLivePathFor($page), $this->generateFilePath($page));
386
    }
387
388
    protected function saveAsStatic($liveUri, $destination)
389
    {
390
        $request = Request::create($liveUri);
391
392
        $response = static::$appKernel->handle($request);
393
394
        if ($response->isRedirect()) {
395
            // todo
396
            //$this->addRedirection($liveUri, getRedirectUri)
397
            return;
398
        } elseif (200 != $response->getStatusCode()) {
399
            //$this->kernel = static::$appKernel;
400
            if (500 === $response->getStatusCode() && 'dev' == $this->kernel->getEnvironment()) {
401
                exit($this->kernel->handle($request));
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
402
            }
403
404
            return;
405
        }
406
407
        $content = $this->compress($response->getContent());
408
        $this->filesystem->dumpFile($destination, $content);
409
    }
410
411
    protected function compress($html)
412
    {
413
        return $this->parser->compress($html);
414
    }
415
416
    protected function generateFilePath(Page $page)
417
    {
418
        $slug = '' == $page->getRealSlug() ? 'index' : $page->getRealSlug();
419
        $route = $this->pageCanonical->generatePathForPage($slug);
420
421
        return $this->app->getStaticDir().$route.'.html';
422
    }
423
424
    /**
425
     * Generate static file for feed indexing children pages
426
     * (only if children pages exists).
427
     *
428
     * @return void
429
     */
430
    protected function generateFeedFor(Page $page)
431
    {
432
        $liveUri = $this->generateLivePathFor($page, 'piedweb_cms_page_feed');
433
        $staticFile = preg_replace('/.html$/', '.xml', $this->generateFilePath($page));
434
        $this->saveAsStatic($liveUri, $staticFile);
435
    }
436
437
    protected function generateErrorPages(): void
438
    {
439
        $this->generateErrorPage();
440
441
        // todo i18n error in .htaccess
442
        $locales = explode('|', $this->params->get('pwc.locales'));
443
444
        foreach ($locales as $locale) {
445
            $this->filesystem->mkdir($this->app->getStaticDir().'/'.$locale);
446
            $this->generateErrorPage($locale);
447
        }
448
    }
449
450
    protected function generateErrorPage($locale = null, $uri = '404.html')
451
    {
452
        if (null !== $locale) {
453
            $request = new Request();
454
            $request->setLocale($locale);
455
            $this->requesStack->push($request);
456
        }
457
458
        $dump = $this->parser->compress($this->twig->render('@Twig/Exception/error.html.twig'));
459
        $this->filesystem->dumpFile($this->app->getStaticDir().(null !== $locale ? '/'.$locale : '').'/'.$uri, $dump);
460
    }
461
462
    protected function getPageRepository(): PageRepository
463
    {
464
        return $this->em->getRepository($this->params->get('pwc.entity_page'));
465
    }
466
}
467