Test Failed
Pull Request — master (#21)
by Stephen
03:01
created

S3::upload()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 10
rs 10
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 string
98
     */
99
    public function upload(string $localFilePath, string $acl = null): string
100
    {
101
        if (is_null($acl)) {
102
            $this->storageDisk()->put($this->s3Key, fopen($localFilePath, 'r+'));
103
        } else {
104
            $this->storageDisk()->put($this->s3Key, fopen($localFilePath, 'r+'), $acl);
105
        }
106
107
        // todo: refactor to return 'self'
108
        return $this->url();
109
    }
110
111
    /**
112
     * Upload raw file contents to an S3 bucket.
113
     *
114
     * @param string $fileContents
115
     * @param string|null $acl
116
     * @return string
117
     */
118
    public function upload_raw(string $fileContents, string $acl = null): string
119
    {
120
        if (is_null($acl)) {
121
            $this->storageDisk()->put($this->s3Key, $fileContents);
122
        } else {
123
            $this->storageDisk()->put($this->s3Key, $fileContents, $acl);
124
        }
125
126
        // todo: refactor to return 'self'
127
        return $this->url();
128
    }
129
130
    /**
131
     * Download a file from an S3 bucket.
132
     *
133
     * @param string|null $fileName
134
     * @return \Illuminate\Http\Response
135
     * @throws FileNotFoundException|\League\Flysystem\FileNotFoundException
136
     */
137
    public function download(string $fileName = null): \Illuminate\Http\Response
138
    {
139
        if (is_null($fileName)) {
140
            $fileName = basename($this->s3Key);
141
        }
142
143
        $mime = $this->storageDisk()->getMimetype($this->s3Key);
144
        $size = $this->storageDisk()->getSize($this->s3Key);
145
146
        $response = [
147
            'Content-Type' => $mime,
148
            'Content-Length' => $size,
149
            'Content-Description' => 'File Transfer',
150
            'Content-Disposition' => "attachment; filename={$fileName}",
151
            'Content-Transfer-Encoding' => 'binary',
152
        ];
153
154
        return Response::make($this->storageDisk()->get($this->s3Key), 200, $response);
155
    }
156
157
    /**
158
     * List all of the files in an S3 directory.
159
     *
160
     * @return array
161
     */
162
    public function list(): array
163
    {
164
        $storage = $this->storageDisk();
165
        $client = $storage->getAdapter()->getClient();
166
        $command = $client->getCommand('ListObjects');
167
        $command['Bucket'] = $storage->getAdapter()->getBucket();
168
        $command['Prefix'] = $this->s3Key;
169
        $result = $client->execute($command);
170
171
        $files = [];
172
        if (isset($result['Contents']) && ! empty($result['Contents'])) {
173
            foreach ($result['Contents'] as $content) {
174
                $url = StorageS3::key($content['Key'])->urlTemp();
175
                $parts = explode('/', explode('?', $url, 2)[0]);
176
                $files[] = [
177
                    'name' => end($parts),
178
                    'url' => $url,
179
                    'key' => $content['Key'],
180
                ];
181
            }
182
        }
183
184
        return $files;
185
    }
186
187
    /**
188
     * Autocomplete an S3 path by providing the known start of a path.
189
     *
190
     * - once path autocompletion is resolved the $s3_key property is replaced with the found path
191
     *
192
     * @return $this
193
     */
194
    public function autocompletePath(): self
195
    {
196
        // Extract the known $base of the path & the $wildcard
197
        $directory = dirname($this->s3Key);
198
199
        // Get all of the folders in the base directory
200
        $folders = $this->storageDisk()->directories($directory);
201
202
        // Filter folders to find the wildcard path
203
        $folders = array_filter($folders, function ($value) {
204
            return str_starts_with($value, $this->s3Key);
205
        });
206
207
        // return the resolved path
208
        $this->s3Key = collect($folders)->values()->first();
209
210
        return $this;
211
    }
212
213
    /**
214
     * Retrieve an array of all files in a directory with an optional filtering closure.
215
     *
216
     * @param Closure|null $closure
217
     * @return array
218
     */
219
    public function allFiles(Closure $closure = null): array
220
    {
221
        // Create array of all files
222
        $allFiles = $this->storageDisk()->allFiles($this->s3Key);
223
224
        // Apply filtering closure
225
        if (isset($closure)) {
226
            return array_filter(array_values($allFiles), $closure);
227
        }
228
229
        return $allFiles;
230
    }
231
232
    /**
233
     * Retrieve an array of all directories within another directory with an optional filtering closure.
234
     *
235
     * @param Closure|null $closure
236
     * @return array
237
     */
238
    public function allDirectories(Closure $closure = null): array
239
    {
240
        // Create array of all directories
241
        $allDirectories = $this->storageDisk()->allDirectories($this->s3Key);
242
243
        // Apply filtering closure
244
        if (isset($closure)) {
245
            return array_filter(array_values($allDirectories), $closure);
246
        }
247
248
        return $allDirectories;
249
    }
250
}
251