Test Failed
Push — master ( 3b96cc...f6b24d )
by Stephen
51s queued 11s
created

S3::download()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 0
loc 18
rs 9.9
c 1
b 0
f 0
1
<?php
2
3
namespace Sfneal\Helpers\Aws\S3\Utils;
4
5
use Closure;
6
use DateTimeInterface;
7
use Illuminate\Contracts\Filesystem\FileNotFoundException;
8
use Illuminate\Contracts\Filesystem\Filesystem;
9
use Illuminate\Filesystem\FilesystemAdapter;
10
use Illuminate\Support\Facades\Response;
11
use Illuminate\Support\Facades\Storage;
12
use Sfneal\Helpers\Aws\S3\Interfaces\S3Filesystem;
13
use Sfneal\Helpers\Aws\S3\StorageS3;
14
15
class S3 implements S3Filesystem
16
{
17
    /**
18
     * @var string
19
     */
20
    private $s3Key;
21
22
    /**
23
     * @var string
24
     */
25
    private $disk;
26
27
    /**
28
     * S3 constructor.
29
     *
30
     * @param string $s3_key
31
     */
32
    public function __construct(string $s3_key)
33
    {
34
        $this->s3Key = $s3_key;
35
        $this->disk = config('filesystem.cloud', 's3');
36
    }
37
38
    /**
39
     * Retrieve a Filesystem instance for the specified disk.
40
     *
41
     * @return Filesystem|FilesystemAdapter
42
     */
43
    private function storageDisk(): FilesystemAdapter
44
    {
45
        return Storage::disk($this->disk);
46
    }
47
48
    /**
49
     * Retrieve the S3 key (useful in conjunctions with `autocompletePath()` method).
50
     *
51
     * @return string
52
     */
53
    public function getKey(): string
54
    {
55
        return $this->s3Key;
56
    }
57
58
    /**
59
     * Set the filesystem disk.
60
     *
61
     * @param string $disk
62
     * @return $this
63
     */
64
    public function setDisk(string $disk): self
65
    {
66
        $this->disk = $disk;
67
68
        return $this;
69
    }
70
71
    /**
72
     * Return either an S3 file url.
73
     *
74
     * @return string
75
     */
76
    public function url(): string
77
    {
78
        return $this->storageDisk()->url($this->s3Key);
79
    }
80
81
    /**
82
     * Return either a temporary S3 file url.
83
     *
84
     * @param DateTimeInterface|null $expiration
85
     * @return string
86
     */
87
    public function urlTemp(DateTimeInterface $expiration = null): string
88
    {
89
        return $this->storageDisk()->temporaryUrl($this->s3Key, $expiration ?? now()->addMinutes(60));
90
    }
91
92
    /**
93
     * Upload a file to an S3 bucket.
94
     *
95
     * @param string $localFilePath
96
     * @param string|null $acl
97
     * @return self
98
     */
99
    public function upload(string $localFilePath, string $acl = null): self
100
    {
101
        return $this->uploadRaw(fopen($localFilePath, 'r+'), $acl);
102
    }
103
104
    /**
105
     * Upload raw file contents to an S3 bucket.
106
     *
107
     * @param $fileContents
108
     * @param string|null $acl
109
     * @return self
110
     */
111
    public function uploadRaw($fileContents, string $acl = null): self
112
    {
113
        $this->storageDisk()->put($this->s3Key, $fileContents, $acl);
114
115
        return $this;
116
    }
117
118
    /**
119
     * Download a file from an S3 bucket.
120
     *
121
     * @param string|null $fileName
122
     * @return \Illuminate\Http\Response
123
     * @throws FileNotFoundException|\League\Flysystem\FileNotFoundException
124
     */
125
    public function download(string $fileName = null): \Illuminate\Http\Response
126
    {
127
        if (is_null($fileName)) {
128
            $fileName = basename($this->s3Key);
129
        }
130
131
        $mime = $this->storageDisk()->getMimetype($this->s3Key);
132
        $size = $this->storageDisk()->getSize($this->s3Key);
133
134
        $response = [
135
            'Content-Type' => $mime,
136
            'Content-Length' => $size,
137
            'Content-Description' => 'File Transfer',
138
            'Content-Disposition' => "attachment; filename={$fileName}",
139
            'Content-Transfer-Encoding' => 'binary',
140
        ];
141
142
        return Response::make($this->storageDisk()->get($this->s3Key), 200, $response);
143
    }
144
145
    /**
146
     * List all of the files in an S3 directory.
147
     *
148
     * @return array
149
     */
150
    public function list(): array
151
    {
152
        $storage = $this->storageDisk();
153
        $client = $storage->getAdapter()->getClient();
154
        $command = $client->getCommand('ListObjects');
155
        $command['Bucket'] = $storage->getAdapter()->getBucket();
156
        $command['Prefix'] = $this->s3Key;
157
        $result = $client->execute($command);
158
159
        $files = [];
160
        if (isset($result['Contents']) && ! empty($result['Contents'])) {
161
            foreach ($result['Contents'] as $content) {
162
                $url = StorageS3::key($content['Key'])->urlTemp();
163
                $parts = explode('/', explode('?', $url, 2)[0]);
164
                $files[] = [
165
                    'name' => end($parts),
166
                    'url' => $url,
167
                    'key' => $content['Key'],
168
                ];
169
            }
170
        }
171
172
        return $files;
173
    }
174
175
    /**
176
     * Autocomplete an S3 path by providing the known start of a path.
177
     *
178
     * - once path autocompletion is resolved the $s3_key property is replaced with the found path
179
     *
180
     * @return $this
181
     */
182
    public function autocompletePath(): self
183
    {
184
        // Extract the known $base of the path & the $wildcard
185
        $directory = dirname($this->s3Key);
186
187
        // Get all of the folders in the base directory
188
        $folders = $this->storageDisk()->directories($directory);
189
190
        // Filter folders to find the wildcard path
191
        $folders = array_filter($folders, function ($value) {
192
            return str_starts_with($value, $this->s3Key);
193
        });
194
195
        // return the resolved path
196
        $this->s3Key = collect($folders)->values()->first();
197
198
        return $this;
199
    }
200
201
    /**
202
     * Retrieve an array of all files in a directory with an optional filtering closure.
203
     *
204
     * @param Closure|null $closure
205
     * @return array
206
     */
207
    public function allFiles(Closure $closure = null): array
208
    {
209
        // Create array of all files
210
        $allFiles = $this->storageDisk()->allFiles($this->s3Key);
211
212
        // Apply filtering closure
213
        if (isset($closure)) {
214
            return array_filter(array_values($allFiles), $closure);
215
        }
216
217
        return $allFiles;
218
    }
219
220
    /**
221
     * Retrieve an array of all directories within another directory with an optional filtering closure.
222
     *
223
     * @param Closure|null $closure
224
     * @return array
225
     */
226
    public function allDirectories(Closure $closure = null): array
227
    {
228
        // Create array of all directories
229
        $allDirectories = $this->storageDisk()->allDirectories($this->s3Key);
230
231
        // Apply filtering closure
232
        if (isset($closure)) {
233
            return array_filter(array_values($allDirectories), $closure);
234
        }
235
236
        return $allDirectories;
237
    }
238
}
239