Test Setup Failed
Push — master ( c70639...caf13f )
by Phan
03:32
created

Download::fromMultipleSongs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
namespace App\Services;
4
5
use App\Models\Album;
6
use App\Models\Artist;
7
use App\Models\Playlist;
8
use App\Models\Song;
9
use App\Models\SongZipArchive;
10
use Exception;
11
use Illuminate\Support\Collection;
12
use Log;
13
14
class Download
15
{
16
    /**
17
     * Generic method to generate a download archive from various source types.
18
     *
19
     * @param Song|Collection<Song>|Album|Artist|Playlist $mixed
0 ignored issues
show
Documentation introduced by
The doc-type Song|Collection<Song>|Album|Artist|Playlist could not be parsed: Expected "|" or "end of type", but got "<" at position 15. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
20
     *
21
     * @throws Exception
22
     *
23
     * @return string Full path to the generated archive
24
     */
25
    public function from($mixed)
26
    {
27
        if ($mixed instanceof Song) {
28
            return $this->fromSong($mixed);
29
        } elseif ($mixed instanceof Collection) {
30
            return $this->fromMultipleSongs($mixed);
31
        } elseif ($mixed instanceof Album) {
32
            return $this->fromAlbum($mixed);
33
        } elseif ($mixed instanceof Artist) {
34
            return $this->fromArtist($mixed);
35
        } elseif ($mixed instanceof Playlist) {
36
            return $this->fromPlaylist($mixed);
37
        } else {
38
            throw new Exception('Unsupport download type.');
39
        }
40
    }
41
42
    /**
43
     * Generate the downloadable path for a song.
44
     *
45
     * @param Song $song
46
     *
47
     * @return string
48
     */
49
    public function fromSong(Song $song)
50
    {
51
        if ($s3Params = $song->s3_params) {
52
            // The song is hosted on Amazon S3.
53
            // We download it back to our local server first.
54
            $localPath = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.basename($s3Params['key']);
55
            $url = $song->getObjectStoragePublicUrl();
56
57
            abort_unless($url, 404);
0 ignored issues
show
Documentation introduced by
$url is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
58
59
            // The following function require allow_url_fopen to be ON.
60
            // We're just assuming that to be the case here.
61
            copy($url, $localPath);
62
        } else {
63
            // The song is hosted locally. Make sure the file exists.
64
            abort_unless(file_exists($song->path), 404);
65
            $localPath = $song->path;
66
        }
67
68
        // The BinaryFileResponse factory only accept ASCII-only file names.
69
        if (ctype_print($localPath)) {
70
            return $localPath;
71
        }
72
73
        // For those with high-byte characters in names, we copy it into a safe name
74
        // as a workaround.
75
        $newPath = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.utf8_decode(basename($song->path));
76
77
        if ($s3Params) {
78
            // If the file is downloaded from S3, we rename it directly.
79
            // This will save us some disk space.
80
            rename($localPath, $newPath);
81
        } else {
82
            // Else we copy it to another file to not mess up the original one.
83
            copy($localPath, $newPath);
84
        }
85
86
        return $newPath;
87
    }
88
89
    /**
90
     * Generate a downloadable path of multiple songs in zip format.
91
     *
92
     * @param Collection $songs
93
     *
94
     * @throws Exception
95
     *
96
     * @return string
97
     */
98
    protected function fromMultipleSongs(Collection $songs)
99
    {
100
        if ($songs->count() === 1) {
101
            return $this->fromSong($songs->first());
102
        }
103
104
        return (new SongZipArchive())
105
            ->addSongs($songs)
106
            ->finish()
107
            ->getPath();
108
    }
109
110
    protected function fromPlaylist(Playlist $playlist)
111
    {
112
        return $this->fromMultipleSongs($playlist->songs);
113
    }
114
115
    protected function fromAlbum(Album $album)
116
    {
117
        return $this->fromMultipleSongs($album->songs);
118
    }
119
120
    protected function fromArtist(Artist $artist)
121
    {
122
        // Don't forget the contributed songs.
123
        $songs = $artist->songs->merge($artist->getContributedSongs());
124
125
        return $this->fromMultipleSongs($songs);
126
    }
127
}
128