Passed
Push — master ( 4017d9...9757db )
by Dev
10:15
created

StaticAppGenerator::__construct()   A

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\AppConfigHelper as 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
155
    public function generateFromHost($host)
156
    {
157
        return $this->generateAll($host);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->generateAll($host) targeting PiedWeb\CMSBundle\Extens...enerator::generateAll() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
158
    }
159
160
    /**
161
     * Main Logic is here.
162
     *
163
     * @throws \RuntimeException
164
     * @throws \LogicException
165
     */
166
    public function generate($app, $mustGetPagesWithoutHost = false)
167
    {
168
        $this->app = new App($app['hosts'][0], [$app]);
169
        $this->mustGetPagesWithoutHost = $mustGetPagesWithoutHost;
170
171
        $this->filesystem->remove($this->app->getStaticDir());
172
        $this->generatePages();
173
        $this->generateSitemaps();
174
        $this->generateErrorPages();
175
        $this->copyRobotsFiles();
176
        $this->generateServerManagerFile();
177
        $this->copyAssets();
178
        $this->copyMediaToDownload();
179
    }
180
181
    /**
182
     * Symlink doesn't work on github page, symlink only for apache if conf say OK to symlink.
183
     */
184
    protected function mustSymlink()
185
    {
186
        return $this->app->get('static_generateForApache') ? $this->app->get('static_symlinkMedia') : false;
187
    }
188
189
    /**
190
     * Generate .htaccess for Apache or CNAME for github
191
     * Must be run after generatePages() !!
192
     */
193
    protected function generateServerManagerFile()
194
    {
195
        if ($this->app->get('static_generateForApache')) {
196
            $this->generateHtaccess();
197
        } else { //if ($this->app['static_generateForGithubPages'])) {
198
            $this->generateCname();
199
        }
200
    }
201
202
    /**
203
     * Copy files relative to SEO (robots, sitemaps, etc.).
204
     */
205
    protected function copyRobotsFiles(): void
206
    {
207
        array_map([$this, 'copy'], $this->robotsFiles);
208
    }
209
210
    // todo
211
    // docs
212
    // https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
213
    protected function generateCname()
214
    {
215
        $this->filesystem->dumpFile($this->app->getStaticDir().'/CNAME', $this->app->getMainHost());
216
    }
217
218
    protected function generateHtaccess()
219
    {
220
        $htaccess = $this->twig->render('@PiedWebCMS/static/htaccess.twig', [
221
            'domain' => $this->app->getMainHost(),
222
            'redirections' => $this->redirections,
223
        ]);
224
        $this->filesystem->dumpFile($this->app->getStaticDir().'/.htaccess', $htaccess);
225
    }
226
227
    protected function copy(string $file): void
228
    {
229
        if (file_exists($file)) {
230
            copy(
231
                str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$file),
232
                $this->app->getStaticDir().'/'.$file
233
            );
234
        }
235
    }
236
237
    /**
238
     * Copy (or symlink) for all assets in public
239
     * (and media previously generated by liip in public).
240
     */
241
    protected function copyAssets(): void
242
    {
243
        $symlink = $this->mustSymlink();
244
245
        $dir = dir($this->webDir);
246
        while (false !== $entry = $dir->read()) {
247
            if ('.' == $entry || '..' == $entry) {
248
                continue;
249
            }
250
            if (!\in_array($entry, $this->robotsFiles) && !\in_array($entry, $this->dontCopy)) {
251
                //$this->symlink(
252
                if (true === $symlink) {
253
                    $this->filesystem->symlink(
254
                        str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$entry),
255
                        $this->app->getStaticDir().'/'.$entry
256
                    );
257
                } else {
258
                    $action = is_file($this->webDir.'/'.$entry) ? 'copy' : 'mirror';
259
                    $this->filesystem->$action($this->webDir.'/'.$entry, $this->app->getStaticDir().'/'.$entry);
260
                }
261
            }
262
        }
263
        $dir->close();
264
    }
265
266
    /**
267
     * Copy or Symlink "not image" media to download folder.
268
     *
269
     * @return void
270
     */
271
    protected function copyMediaToDownload()
272
    {
273
        $symlink = $this->mustSymlink();
274
275
        if (!file_exists($this->app->getStaticDir().'/download')) {
276
            $this->filesystem->mkdir($this->app->getStaticDir().'/download/');
277
            $this->filesystem->mkdir($this->app->getStaticDir().'/download/media');
278
        }
279
280
        $dir = dir($this->webDir.'/../media');
281
        while (false !== $entry = $dir->read()) {
282
            if ('.' == $entry || '..' == $entry) {
283
                continue;
284
            }
285
            // if the file is an image, it's ever exist (maybe it's slow to check every files)
286
            if (!file_exists($this->webDir.'/media/default/'.$entry)) {
287
                if (true === $symlink) {
288
                    $this->filesystem->symlink(
289
                        '../../../media/'.$entry,
290
                        $this->app->getStaticDir().'/download/media/'.$entry
291
                    );
292
                } else {
293
                    $this->filesystem->copy(
294
                        $this->webDir.'/../media/'.$entry,
295
                        $this->app->getStaticDir().'/download/media/'.$entry
296
                    );
297
                }
298
            }
299
        }
300
301
        //$this->filesystem->$action($this->webDir.'/../media', $this->app->getStaticDir().'/download/media');
302
    }
303
304
    protected function generateSitemaps(): void
305
    {
306
        foreach (explode('|', $this->params->get('pwc.locales')) as $locale) {
307
            foreach (['txt', 'xml'] as $format) {
308
                $this->generateSitemap($locale, $format);
309
            }
310
311
            $this->generateFeed($locale);
312
        }
313
    }
314
315
    protected function generateSitemap($locale, $format)
316
    {
317
        $liveUri = $this->generateLivePathFor(
318
            $this->app->getMainHost(),
319
            'piedweb_cms_page_sitemap',
320
            ['locale' => $locale, '_format' => $format]
321
        );
322
        $staticFile = $this->app->getStaticDir().'/sitemap'.$locale.'.'.$format; // todo get it from URI removing host
323
        $this->saveAsStatic($liveUri, $staticFile);
324
325
        if ($this->params->get('locale') == $locale ? '' : '.'.$locale) {
326
            $staticFile = $this->app->getStaticDir().'/sitemap.'.$format;
327
            $this->saveAsStatic($liveUri, $staticFile);
328
        }
329
    }
330
331
    protected function generateFeed($locale)
332
    {
333
        $liveUri = $this->generateLivePathFor(
334
            $this->app->getMainHost(),
335
            'piedweb_cms_page_main_feed',
336
            ['locale' => $locale]
337
        );
338
        $staticFile = $this->app->getStaticDir().'/feed'.$locale.'.xml';
339
        $this->saveAsStatic($liveUri, $staticFile);
340
341
        if ($this->params->get('locale') == $locale ? '' : '.'.$locale) {
342
            $staticFile = $this->app->getStaticDir().'/feed.xml';
343
            $this->saveAsStatic($liveUri, $staticFile);
344
        }
345
    }
346
347
    /**
348
     * The function cache redirection found during generatePages and
349
     * format in self::$redirection the content for the .htaccess.
350
     *
351
     * @return void
352
     */
353
    protected function addRedirection(Page $page)
354
    {
355
        $this->redirections .= 'Redirect ';
356
        $this->redirections .= $page->getRedirectionCode().' ';
357
        $this->redirections .= $this->pageCanonical->generatePathForPage($page->getRealSlug());
358
        $this->redirections .= ' '.$page->getRedirection();
359
        $this->redirections .= PHP_EOL;
360
    }
361
362
    protected function generatePages(): void
363
    {
364
        $qb = $this->getPageRepository()->getQueryToFindPublished('p');
365
        $qb = $this->getPageRepository()->andHost($qb, $this->app->getMainHost(), $this->mustGetPagesWithoutHost);
366
        $pages = $qb->getQuery()->getResult();
367
368
        foreach ($pages as $page) {
369
            $this->generatePage($page);
370
            //if ($page->getRealSlug()) $this->generateFeedFor($page);
371
        }
372
    }
373
374
    protected function generatePage(Page $page)
375
    {
376
        // check if it's a redirection
377
        if (false !== $page->getRedirection()) {
378
            $this->addRedirection($page);
379
380
            return;
381
        }
382
383
        $this->saveAsStatic($this->generateLivePathFor($page), $this->generateFilePath($page));
384
    }
385
386
    protected function saveAsStatic($liveUri, $destination)
387
    {
388
        $request = Request::create($liveUri);
389
390
        $response = static::$appKernel->handle($request);
391
392
        if ($response->isRedirect()) {
393
            // todo
394
            //$this->addRedirection($liveUri, getRedirectUri)
395
            return;
396
        } elseif (200 != $response->getStatusCode()) {
397
            //$this->kernel = static::$appKernel;
398
            if (500 === $response->getStatusCode() && 'dev' == $this->kernel->getEnvironment()) {
399
                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...
400
            }
401
402
            return;
403
        }
404
405
        $content = $this->compress($response->getContent());
406
        $this->filesystem->dumpFile($destination, $content);
407
    }
408
409
    protected function compress($html)
410
    {
411
        return $this->parser->compress($html);
412
    }
413
414
    protected function generateFilePath(Page $page)
415
    {
416
        $slug = '' == $page->getRealSlug() ? 'index' : $page->getRealSlug();
417
        $route = $this->pageCanonical->generatePathForPage($slug);
418
419
        return $this->app->getStaticDir().$route.'.html';
420
    }
421
422
    /**
423
     * Generate static file for feed indexing children pages
424
     * (only if children pages exists).
425
     *
426
     * @return void
427
     */
428
    protected function generateFeedFor(Page $page)
429
    {
430
        $liveUri = $this->generateLivePathFor($page, 'piedweb_cms_page_feed');
431
        $staticFile = preg_replace('/.html$/', '.xml', $this->generateFilePath($page));
432
        $this->saveAsStatic($liveUri, $staticFile);
433
    }
434
435
    protected function generateErrorPages(): void
436
    {
437
        $this->generateErrorPage();
438
439
        // todo i18n error in .htaccess
440
        $locales = explode('|', $this->params->get('pwc.locales'));
441
442
        foreach ($locales as $locale) {
443
            $this->filesystem->mkdir($this->app->getStaticDir().'/'.$locale);
444
            $this->generateErrorPage($locale);
445
        }
446
    }
447
448
    protected function generateErrorPage($locale = null, $uri = '404.html')
449
    {
450
        if (null !== $locale) {
451
            $request = new Request();
452
            $request->setLocale($locale);
453
            $this->requesStack->push($request);
454
        }
455
456
        $dump = $this->parser->compress($this->twig->render('@Twig/Exception/error.html.twig'));
457
        $this->filesystem->dumpFile($this->app->getStaticDir().(null !== $locale ? '/'.$locale : '').'/'.$uri, $dump);
458
    }
459
460
    protected function getPageRepository(): PageRepository
461
    {
462
        return $this->em->getRepository($this->params->get('pwc.entity_page'));
463
    }
464
}
465