Test Failed
Push — master ( 3fe401...822a47 )
by Stephen
54s queued 11s
created

S3::exists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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