Passed
Push — master ( 84d9c2...9fa36a )
by Dev
10:32
created

StaticService::copyMediaToDownload()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 14
c 0
b 0
f 0
nc 10
nop 1
dl 0
loc 20
ccs 0
cts 9
cp 0
crap 56
rs 8.8333
1
<?php
2
3
namespace PiedWeb\CMSBundle\Service;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use PiedWeb\CMSBundle\Entity\PageInterface as Page;
7
use PiedWeb\CMSBundle\Service\PageCanonicalService as PageCanonical;
8
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
9
use Symfony\Component\Filesystem\Filesystem;
10
use Symfony\Component\HttpFoundation\Request;
11
use Symfony\Component\HttpFoundation\RequestStack;
12
use Symfony\Contracts\Translation\TranslatorInterface;
13
use Twig\Environment as Twig;
14
use WyriHaximus\HtmlCompress\Factory as HtmlCompressor;
15
16
class StaticService
17
{
18
    /**
19
     * Contain files relative to SEO wich will be hard copied.
20
     *
21
     * @var array
22
     */
23
    protected $robotsFiles = ['robots.txt', 'feed.xml', 'sitemap.xml', 'sitemap.txt'];
24
25
    /**
26
     * @var array
27
     */
28
    protected $dontCopy = ['index.php', '.htaccess'];
29
30
    /**
31
     * @var EntityManagerInterface
32
     */
33
    protected $em;
34
35
    /**
36
     * @var Filesystem
37
     */
38
    protected $filesystem;
39
40
    /**
41
     * @var Twig
42
     */
43
    protected $twig;
44
45
    /**
46
     * @var string
47
     */
48
    protected $webDir;
49
50
    /**
51
     * @var string
52
     */
53
    protected $staticDir;
54
55
    /**
56
     * @var RequestStack
57
     */
58
    protected $requesStack;
59
60
    /**
61
     * @var \PiedWeb\CMSBundle\Service\PageCanonicalService
62
     */
63
    protected $pageCanonical;
64
65
    /**
66
     * @var TranslatorInterface
67
     */
68
    protected $translator;
69
70
    /**
71
     * @var HtmlCompressor
72
     */
73
    protected $parser;
74
75
    /**
76
     * @var ParameterBagInterface
77
     */
78
    protected $params;
79
80
    /**
81
     * Used in .htaccess generation.
82
     *
83
     * @var string
84
     */
85
    protected $redirections = '';
86
87
    public function __construct(
88
        EntityManagerInterface $em,
89
        Twig $twig,
90
        ParameterBagInterface $params,
91
        RequestStack $requesStack,
92
        PageCanonical $pageCanonical,
93
        TranslatorInterface $translator,
94
        string $webDir
95
    ) {
96
        $this->em = $em;
97
        $this->filesystem = new Filesystem();
98
        $this->twig = $twig;
99
        $this->params = $params;
100
        $this->requesStack = $requesStack;
101
        $this->webDir = $webDir;
102
        $this->pageCanonical = $pageCanonical;
103
        $this->translator = $translator;
104
        $this->staticDir = $this->params->get('pwc.static.dir');
105
        $this->parser = HtmlCompressor::construct();
0 ignored issues
show
Documentation Bug introduced by
It seems like WyriHaximus\HtmlCompress\Factory::construct() of type WyriHaximus\HtmlCompress\Parser is incompatible with the declared type WyriHaximus\HtmlCompress\Factory of property $parser.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
106
    }
107
108
    /**
109
     * Main Logic is here.
110
     *
111
     * @throws \RuntimeException
112
     * @throws \LogicException
113
     */
114
    public function dump()
115
    {
116
        if (!method_exists($this->filesystem, 'dumpFile')) {
117
            throw new \RuntimeException('Method dumpFile() is not available. Upgrade your Filesystem.');
118
        }
119
120
        $this->filesystem->remove($this->staticDir);
121
122
        if ($this->params->get('pwc.static.generateForApache')) {
123
            $this->generateHtaccess();
124
            $symlink = $this->params->get('pwc.static.symlinkMedia');
125
        } else { //if ($this->params->has('pwc.static.generateForGithubPages')) {
126
            // symlink doesn't work on github page.
127
            $symlink = false;
128
            $this->generateCname();
129
        }
130
131
        $this->generatePage();
132
        $this->generateErrorPages();
133
        $this->copyRobotsFiles();
134
        $this->copyAssets($symlink);
135
        $this->copyMediaToDownload($symlink);
136
    }
137
138
    /**
139
     * Copy files relative to SEO (robots, sitemaps, etc.).
140
     */
141
    protected function copyRobotsFiles(): void
142
    {
143
        array_map([$this, 'copy'], $this->robotsFiles);
144
    }
145
146
    // todo
147
    // docs
148
    // https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site
149
    protected function generateCname()
150
    {
151
        $this->filesystem->dumpFile($this->staticDir.'/CNAME', $this->params->get('pwc.static.domain'));
152
    }
153
154
    protected function generateHtaccess()
155
    {
156
        if (!$this->params->has('pwc.static.domain')) {
157
            throw new \Exception('Before, you need to configure (in config/packages/piedweb_cms.yaml) static_domain.');
158
        }
159
160
        $htaccess = $this->twig->render('@PiedWebCMS/static/htaccess.twig', [
161
            'domain' => $this->params->get('pwc.static.domain'),
162
            'redirections' => $this->redirections,
163
        ]);
164
        $this->filesystem->dumpFile($this->staticDir.'/.htaccess', $htaccess);
165
    }
166
167
    protected function copy(string $file): void
168
    {
169
        if (file_exists($file)) {
170
            copy(
171
                str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$file),
172
                $this->staticDir.'/'.$file
173
            );
174
        }
175
    }
176
177
    /**
178
     * Copy (or symlink) for all assets in public
179
     * (and media previously generated by liip in public).
180
     */
181
    protected function copyAssets(bool $symlink = true): void
182
    {
183
        $dir = dir($this->webDir);
184
        while (false !== $entry = $dir->read()) {
185
            if ('.' == $entry || '..' == $entry) {
186
                continue;
187
            }
188
            if (!in_array($entry, $this->robotsFiles) && !in_array($entry, $this->dontCopy)) {
189
                //$this->symlink(
190
                if (true === $symlink) {
191
                    $this->filesystem->symlink(
192
                        str_replace($this->params->get('kernel.project_dir').'/', '../', $this->webDir.'/'.$entry),
193
                        $this->staticDir.'/'.$entry
194
                    );
195
                } else {
196
                    $action = is_file($this->webDir.'/'.$entry) ? 'copy' : 'mirror';
197
                    $this->filesystem->$action($this->webDir.'/'.$entry, $this->staticDir.'/'.$entry);
198
                }
199
            }
200
        }
201
        $dir->close();
202
    }
203
204
    /**
205
     * Copy or Symlink "not image" media to download folder.
206
     *
207
     * @return void
208
     */
209
    protected function copyMediaToDownload(bool $symlink = true)
210
    {
211
        if (!file_exists($this->staticDir.'/download')) {
212
            $this->filesystem->mkdir($this->staticDir.'/download/');
213
            $this->filesystem->mkdir($this->staticDir.'/download/media');
214
        }
215
216
        $dir = dir($this->webDir.'/../media');
217
        while (false !== $entry = $dir->read()) {
218
            if ('.' == $entry || '..' == $entry) {
219
                continue;
220
            }
221
            // if the file is an image, it's ever exist (maybe it's slow to check every files)
222
            if (!file_exists($this->webDir.'/media/default/'.$entry)) {
223
                if (true === $symlink) {
224
                    $this->filesystem->symlink('../../../media/'.$entry, $this->staticDir.'/download/media/'.$entry);
225
                } else {
226
                    $this->filesystem->copy(
227
                        $this->webDir.'/../media/'.$entry,
228
                        $this->staticDir.'/download/media/'.$entry
229
                    );
230
                }
231
            }
232
        }
233
234
        //$this->filesystem->$action($this->webDir.'/../media', $this->staticDir.'/download/media');
235
    }
236
237
    protected function generatePage(): void
238
    {
239
        $pages = $this->getPages();
240
241
        foreach ($pages as $page) {
242
            // set current locale to avoid twig error
243
            $request = new Request();
244
            $request->setLocale($page->getLocale());
245
            $this->requesStack->push($request);
246
247
            $page->setTranslatableLocale($page->getLocale());
248
            $this->em->refresh($page);
249
250
            $this->translator->setLocale($page->getLocale());
251
252
            $slug = '' == $page->getRealSlug() ? 'index' : $page->getRealSlug();
253
            $route = $this->pageCanonical->generatePathForPage($slug);
254
            $filepath = $this->staticDir.$route.'.html';
255
256
            // check if it's a redirection
257
            if (false !== $page->getRedirection()) {
258
                $this->redirections .= 'Redirect ';
259
                $this->redirections .= $page->getRedirectionCode().' '.$route.' '.$page->getRedirection();
260
                $this->redirections .= PHP_EOL;
261
                continue;
262
            }
263
264
            $dump = $this->render($page);
265
            $this->filesystem->dumpFile($filepath, $dump);
266
267
            if ($page->getChildrenPages()->count() > 0) {
268
                $dump = $this->renderFeed($page);
269
                $this->filesystem->dumpFile(preg_replace('/.html$/', '.xml', $filepath), $dump);
270
            }
271
        }
272
    }
273
274
    protected function generateErrorPages(): void
275
    {
276
        $this->generateErrorPage();
277
278
        // todo i18n error in .htaccess
279
        $locales = explode('|', $this->params->get('pwc.locales'));
280
281
        foreach ($locales as $locale) {
282
            $this->filesystem->mkdir($this->staticDir.'/'.$locale);
283
            $this->generateErrorPage($locale);
284
        }
285
    }
286
287
    protected function generateErrorPage($locale = null, $uri = '404.html')
288
    {
289
        if (null !== $locale) {
290
            $request = new Request();
291
            $request->setLocale($locale);
292
            $this->requesStack->push($request);
293
        }
294
295
        $dump = $this->parser->compress($this->twig->render('@Twig/Exception/error.html.twig'));
0 ignored issues
show
Bug introduced by
The method compress() does not exist on WyriHaximus\HtmlCompress\Factory. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

295
        /** @scrutinizer ignore-call */ 
296
        $dump = $this->parser->compress($this->twig->render('@Twig/Exception/error.html.twig'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
296
        $this->filesystem->dumpFile($this->staticDir.(null !== $locale ? '/'.$locale : '').'/'.$uri, $dump);
297
    }
298
299
    protected function getPages()
300
    {
301
        $qb = $this->em->getRepository($this->params->get('pwc.entity_page'))->getQueryToFindPublished('p');
0 ignored issues
show
Bug introduced by
The method getQueryToFindPublished() does not exist on Doctrine\Persistence\ObjectRepository. It seems like you code against a sub-type of Doctrine\Persistence\ObjectRepository such as Doctrine\ORM\EntityRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

301
        $qb = $this->em->getRepository($this->params->get('pwc.entity_page'))->/** @scrutinizer ignore-call */ getQueryToFindPublished('p');
Loading history...
302
303
        return $qb->getQuery()->getResult();
304
    }
305
306
    protected function render(Page $page): string
307
    {
308
        $template = $this->params->get('pwc.default_page_template');
309
310
        return $this->parser->compress($this->twig->render($template, ['page' => $page]));
311
    }
312
313
    // todo i18n feed ...
314
    protected function renderFeed(Page $page): string
315
    {
316
        $template = '@PiedWebCMS/page/rss.xml.twig';
317
318
        return $this->parser->compress($this->twig->render($template, ['page' => $page]));
319
    }
320
}
321