Passed
Push — master ( 0154b6...cfd13a )
by Dorian
01:18
created

Downloader   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
dl 0
loc 138
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B shouldDownload() 0 27 5
A __construct() 0 9 2
B synchronizeContents() 0 30 6
A shouldCleanFilesystem() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace App\Domain;
4
5
use App\Filesystem\FilesystemCleaner;
6
use App\UI\Skippable;
7
use App\UI\UserInterface;
8
use Symfony\Component\Filesystem\Filesystem;
9
use Symfony\Component\Yaml\Yaml;
10
11
abstract class Downloader
12
{
13
    use Skippable;
14
15
    /** @var \App\UI\UserInterface */
16
    protected $ui;
17
18
    /** @var array */
19
    protected $config;
20
21
    /**
22
     * @return string
23
     */
24
    abstract protected function getConfigFilePath(): string;
25
26
    /**
27
     * @return Downloads
28
     */
29
    abstract protected function createDownloadsCollection(): Downloads;
30
31
    /**
32
     * @param \App\Domain\Downloads $downloads
33
     *
34
     * @return \App\Domain\Downloads
35
     */
36
    abstract protected function filterAlreadyDownloaded(Downloads $downloads): Downloads;
37
38
    /**
39
     * @param \App\Domain\Content $content
40
     *
41
     * @return \App\Domain\Downloads
42
     */
43
    abstract protected function extractDownloads(Content $content): Downloads;
44
45
    /**
46
     * @param \App\Domain\Downloads $downloads
47
     * @param \App\Domain\Path $downloadPath
48
     *
49
     * @throws \RuntimeException
50
     */
51
    abstract protected function download(Downloads $downloads, Path $downloadPath): void;
52
53
    /**
54
     * {@inheritdoc}
55
     * @param array $config
56
     *
57
     * @throws \Symfony\Component\Yaml\Exception\ParseException
58
     */
59
    public function __construct(UserInterface $ui, array $config = [])
60
    {
61
        $this->ui = $ui;
62
63
        if (!empty($configFilePath = $this->getConfigFilePath())) {
64
            $config += (array) Yaml::parseFile($configFilePath);
65
        }
66
67
        $this->config = $config;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     * @throws \RuntimeException
73
     * @throws \Symfony\Component\Filesystem\Exception\IOException
74
     */
75
    public function synchronizeContents(Contents $contents, PathPart $rootPathPart): void
76
    {
77
        if ($contents->isEmpty()) {
78
            return;
79
        }
80
81
        $downloaderPathPart = new PathPart($this->config['path_part'] ?? []);
82
        $downloadPath = new Path([$rootPathPart, $downloaderPathPart]);
83
84
        // Try to create the downloads directory... 'cause if it fails, nothing will work.
85
        (new Filesystem())->mkdir((string) $downloadPath);
86
87
        if ($this->shouldCleanFilesystem()) {
88
            (new FilesystemCleaner($this->ui))($downloadPath);
89
        }
90
91
        // Add the downloader path part and get a collection of downloads
92
        $downloads = $this->createDownloadsCollection();
93
        foreach ($contents as $content) {
94
            $content->getPath()->add($downloaderPathPart);
95
96
            foreach ($this->extractDownloads($content) as $download) {
97
                $downloads->add($download);
98
            }
99
        }
100
101
        $downloads = $this->filterAlreadyDownloaded($downloads);
102
103
        if ($this->shouldDownload($downloads, $downloadPath)) {
104
            $this->download($downloads, $downloadPath);
105
        }
106
    }
107
108
    /**
109
     * @return bool
110
     */
111
    protected function shouldCleanFilesystem(): bool
112
    {
113
        return $this->config['clean_filesystem'] ?? true;
114
    }
115
116
    /**
117
     * @param \App\Domain\Downloads $downloads
118
     * @param \App\Domain\Path $downloadPath
119
     *
120
     * @return bool
121
     */
122
    private function shouldDownload(Downloads $downloads, Path $downloadPath): bool
123
    {
124
        $this->ui->writeln(sprintf('Downloading files with <info>%s</info>... '.PHP_EOL, static::class));
125
126
        if ($downloads->isEmpty()) {
127
            $this->ui->writeln($this->ui->indent().'<comment>Nothing to download.</comment>'.PHP_EOL);
128
129
            return false;
130
        }
131
132
        $this->ui->writeln(
133
            sprintf(
134
                '%sThe script is about to download <question> %s </question> files into <info>%s</info>. '.PHP_EOL,
135
                $this->ui->indent(),
136
                $downloads->count(),
137
                (string) $downloadPath
138
            )
139
        );
140
141
        $this->ui->write($this->ui->indent());
142
        if ($this->skip($this->ui) || !$this->ui->confirm()) {
143
            $this->ui->writeln(($this->ui->isDryRun() ? '' : PHP_EOL).'<info>Done.</info>'.PHP_EOL);
144
145
            return false;
146
        }
147
148
        return true;
149
    }
150
}
151