generateZipContentFileNameFromPath()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.5

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 15
ccs 5
cts 10
cp 0.5
rs 9.9332
cc 2
nc 2
nop 1
crap 2.5
1
<?php
2
3
namespace App\Models;
4
5
use App\Facades\Download;
6
use Exception;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\Log;
9
use RuntimeException;
10
use ZipArchive;
11
12
class SongZipArchive
13
{
14
    /**
15
     * @var ZipArchive
16
     */
17
    private $archive;
18
19
    /**
20
     * Path to the zip archive.
21
     *
22
     * @var string
23
     */
24
    private $path;
25
26
    /**
27
     * Names of the files in the archive
28
     * Format: [file-name.mp3' => currentFileIndex].
29
     *
30
     * @var array
31
     */
32
    private $fileNames = [];
33
34 2
    public function __construct(string $path = '')
35
    {
36 2
        $this->path = $path ?: self::generateRandomArchivePath();
37
38 2
        $this->archive = new ZipArchive();
39
40 2
        if ($this->archive->open($this->path, ZipArchive::CREATE) !== true) {
41
            throw new RuntimeException('Cannot create zip file.');
42
        }
43 2
    }
44
45
    /**
46
     * Add multiple songs into the archive.
47
     */
48 1
    public function addSongs(Collection $songs): self
49
    {
50 1
        $songs->each([$this, 'addSong']);
51
52 1
        return $this;
53
    }
54
55
    /**
56
     * Add a single song into the archive.
57
     */
58 2
    public function addSong(Song $song): self
59
    {
60
        try {
61 2
            $path = Download::fromSong($song);
62 2
            $this->archive->addFile($path, $this->generateZipContentFileNameFromPath($path));
63
        } catch (Exception $e) {
64
            Log::error($e);
65
        }
66
67 2
        return $this;
68
    }
69
70
    /**
71
     * Finish (close) the archive.
72
     */
73
    public function finish(): self
74
    {
75
        $this->archive->close();
76
77
        return $this;
78
    }
79
80
    public function getPath(): string
81
    {
82
        return $this->path;
83
    }
84
85
    /**
86
     * We add all files into the zip archive as a flat structure.
87
     * As a result, there can be duplicate file names.
88
     * This method makes sure each file name is unique in the zip archive.
89
     */
90 2
    private function generateZipContentFileNameFromPath(string $path): string
91
    {
92 2
        $name = basename($path);
93
94 2
        if (array_key_exists($name, $this->fileNames)) {
95
            $this->fileNames[$name]++;
96
            $parts = explode('.', $name);
97
            $ext = $parts[count($parts) - 1];
98
            $parts[count($parts) - 1] = $this->fileNames[$name].".$ext";
99
            $name = implode('.', $parts);
100
        } else {
101 2
            $this->fileNames[$name] = 1;
102
        }
103
104 2
        return $name;
105
    }
106
107 2
    private static function generateRandomArchivePath(): string
108
    {
109
        // We use system's temp dir instead of storage_path() here, so that the generated files
110
        // can be cleaned up automatically after server reboot.
111 2
        return sprintf('%s%skoel-download-%s.zip', sys_get_temp_dir(), DIRECTORY_SEPARATOR, uniqid());
112
    }
113
114 2
    public function getArchive(): ZipArchive
115
    {
116 2
        return $this->archive;
117
    }
118
}
119