Completed
Push — master ( df0849...3fdaef )
by Freek
07:05
created

MediaStream::getZipStream()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 2
nc 1
nop 0
1
<?php
2
3
namespace Spatie\MediaLibrary;
4
5
use ZipStream\ZipStream;
6
use Illuminate\Support\Collection;
7
use Spatie\MediaLibrary\Models\Media;
8
use Illuminate\Contracts\Support\Responsable;
9
use Symfony\Component\HttpFoundation\StreamedResponse;
10
11
class MediaStream implements Responsable
12
{
13
    /** string */
14
    protected $zipName;
15
16
    /** Illuminate\Support\Collection */
17
    protected $mediaItems;
18
19
    public static function create(string $zipName)
20
    {
21
        return new static($zipName);
22
    }
23
24
    public function __construct(string $zipName)
25
    {
26
        $this->zipName = $zipName;
27
28
        $this->mediaItems = collect();
29
    }
30
31
    public function addMedia(...$mediaItems)
32
    {
33
        collect($mediaItems)
34
            ->flatMap(function ($item) {
35
                if ($item instanceof Media) {
36
                    return [$item];
37
                }
38
39
                if ($item instanceof Collection) {
40
                    return $item->reduce(function (array $carry, Media $media) {
41
                        $carry[] = $media;
42
43
                        return $carry;
44
                    }, []);
45
                }
46
47
                return $item;
48
            })
49
            ->each(function (Media $media) {
50
                $this->mediaItems->push($media);
51
            });
52
53
        return $this;
54
    }
55
56
    public function getMediaItems(): Collection
57
    {
58
        return $this->mediaItems;
59
    }
60
61
    public function toResponse($request)
62
    {
63
        $headers = [
64
            'Content-Disposition' => "attachment; filename=\"{$this->zipName}\"",
65
            'Content-Type' => 'application/octet-stream',
66
        ];
67
68
        return new StreamedResponse(function () {
69
            return $this->getZipStream();
70
        }, 200, $headers);
71
    }
72
73
    public function getZipStream(): ZipStream
74
    {
75
        $zip = new ZipStream($this->zipName);
76
77
        $this->getZipStreamContents()->each(function (array $mediaInZip) use ($zip) {
78
            $stream = $mediaInZip['media']->stream();
79
80
            $zip->addFileFromStream($mediaInZip['fileNameInZip'], $stream);
81
82
            if (is_resource($stream)) {
83
                fclose($stream);
84
            }
85
        });
86
87
        $zip->finish();
88
89
        return $zip;
90
    }
91
92
    protected function getZipStreamContents(): Collection
93
    {
94
        return $this->mediaItems->map(function (Media $media, $mediaItemIndex) {
95
            return [
96
                'fileNameInZip' => $this->getFileNameWithSuffix($this->mediaItems, $mediaItemIndex),
97
                'media' => $media,
98
            ];
99
        });
100
    }
101
102
    protected function getFileNameWithSuffix(Collection $mediaItems, int $currentIndex): string
103
    {
104
        $fileNameCount = 0;
105
106
        $fileName = $mediaItems[$currentIndex]->file_name;
107
108
        foreach ($mediaItems as $index => $media) {
109
            if ($index >= $currentIndex) {
110
                break;
111
            }
112
113
            if ($media->file_name === $fileName) {
114
                $fileNameCount++;
115
            }
116
        }
117
118
        if ($fileNameCount === 0) {
119
            return $fileName;
120
        }
121
122
        $extension = pathinfo($fileName, PATHINFO_EXTENSION);
123
        $fileNameWithoutExtension = pathinfo($fileName, PATHINFO_FILENAME);
124
125
        return "{$fileNameWithoutExtension} ({$fileNameCount}).{$extension}";
126
    }
127
}
128