Test Failed
Pull Request — master (#33)
by Stephen
04:59
created

S3   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Importance

Changes 11
Bugs 0 Features 0
Metric Value
eloc 52
dl 0
loc 234
rs 10
c 11
b 0
f 0
wmc 17

14 Methods

Rating   Name   Duplication   Size   Complexity  
A allFiles() 0 11 2
A url() 0 3 1
A enableStreaming() 0 5 1
A uploadRaw() 0 5 1
A getKey() 0 3 1
A allDirectories() 0 11 2
A disableStreaming() 0 5 1
A urlTemp() 0 5 1
A upload() 0 17 2
A autocompletePath() 0 17 1
A storageDisk() 0 3 1
A __construct() 0 5 1
A download() 0 12 1
A setDisk() 0 5 1
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\Http\File;
11
use Illuminate\Support\Collection;
12
use Illuminate\Support\Facades\Response;
13
use Illuminate\Support\Facades\Storage;
14
use Sfneal\Helpers\Aws\S3\Interfaces\S3Filesystem;
15
16
class S3 implements S3Filesystem
17
{
18
    /**
19
     * @var string AWS S3 file key
20
     */
21
    private $s3Key;
22
23
    /**
24
     * @var string Storage S3 cloud disk name
25
     */
26
    private $disk;
27
28
    /**
29
     * @var bool Enable/disable upload & download streaming
30
     */
31
    private $streaming;
32
33
    /**
34
     * S3 constructor.
35
     *
36
     * @param string $s3Key
37
     */
38
    public function __construct(string $s3Key)
39
    {
40
        $this->s3Key = $s3Key;
41
        $this->disk = config('filesystem.cloud', 's3');
42
        $this->streaming = config('s3-helpers.streaming', true);
43
    }
44
45
    /**
46
     * Retrieve a Filesystem instance for the specified disk.
47
     *
48
     * @return Filesystem|FilesystemAdapter
49
     */
50
    private function storageDisk(): FilesystemAdapter
51
    {
52
        return Storage::disk($this->disk);
53
    }
54
55
    /**
56
     * Retrieve the S3 key (useful in conjunctions with `autocompletePath()` method).
57
     *
58
     * @return string
59
     */
60
    public function getKey(): string
61
    {
62
        return $this->s3Key;
63
    }
64
65
    /**
66
     * Set the filesystem disk.
67
     *
68
     * @param string $disk
69
     * @return $this
70
     */
71
    public function setDisk(string $disk): self
72
    {
73
        $this->disk = $disk;
74
75
        return $this;
76
    }
77
78
    /**
79
     * Enable upload/download streaming regardless of config setting.
80
     *
81
     * @return $this
82
     */
83
    public function enableStreaming(): self
84
    {
85
        $this->streaming = true;
86
87
        return $this;
88
    }
89
90
    /**
91
     * Disable upload/download streaming regardless of config setting.
92
     *
93
     * @return $this
94
     */
95
    public function disableStreaming(): self
96
    {
97
        $this->streaming = false;
98
99
        return $this;
100
    }
101
102
    /**
103
     * Return either an S3 file url.
104
     *
105
     * @return string
106
     */
107
    public function url(): string
108
    {
109
        return $this->storageDisk()->url($this->s3Key);
110
    }
111
112
    /**
113
     * Return either a temporary S3 file url.
114
     *
115
     * @param DateTimeInterface|null $expiration
116
     * @return string
117
     */
118
    public function urlTemp(DateTimeInterface $expiration = null): string
119
    {
120
        return $this->storageDisk()->temporaryUrl(
121
            $this->s3Key,
122
            $expiration ?? config('s3-helpers.expiration')
123
        );
124
    }
125
126
    /**
127
     * Upload a file to S3 using automatic streaming.
128
     *
129
     * @param string $localFilePath
130
     * @param string|null $acl
131
     * @return self
132
     */
133
    public function upload(string $localFilePath, string $acl = null): self
134
    {
135
        // Use streaming for improved performance if enabled
136
        if ($this->streaming) {
137
            $this->storageDisk()->putFileAs(
138
                dirname($this->s3Key),
139
                new File($localFilePath),
140
                basename($this->s3Key),
141
                $acl
142
            );
143
144
            return $this;
145
        }
146
147
        // Use standard file uploading
148
        else {
149
            return $this->uploadRaw(fopen($localFilePath, 'r+'), $acl);
150
        }
151
    }
152
153
    /**
154
     * Upload raw file contents to an S3 bucket.
155
     *
156
     * @param $fileContents
157
     * @param string|null $acl
158
     * @return self
159
     */
160
    public function uploadRaw($fileContents, string $acl = null): self
161
    {
162
        $this->storageDisk()->put($this->s3Key, $fileContents, $acl);
163
164
        return $this;
165
    }
166
167
    /**
168
     * Download a file from an S3 bucket.
169
     *
170
     * @param string|null $fileName
171
     * @return \Illuminate\Http\Response
172
     * @throws FileNotFoundException|\League\Flysystem\FileNotFoundException
173
     */
174
    public function download(string $fileName = null): \Illuminate\Http\Response
175
    {
176
        $fileName = $fileName ?? basename($this->s3Key);
177
        $response = [
178
            'Content-Type' => $this->storageDisk()->getMimetype($this->s3Key),
179
            'Content-Length' => $this->storageDisk()->getSize($this->s3Key),
180
            'Content-Description' => 'File Transfer',
181
            'Content-Disposition' => "attachment; filename={$fileName}",
182
            'Content-Transfer-Encoding' => 'binary',
183
        ];
184
185
        return Response::make($this->storageDisk()->get($this->s3Key), 200, $response);
186
    }
187
188
    /**
189
     * Autocomplete an S3 path by providing the known start of a path.
190
     *
191
     * - once path autocompletion is resolved the $s3_key property is replaced with the found path
192
     *
193
     * @return $this
194
     */
195
    public function autocompletePath(): self
196
    {
197
        // Extract the known $base of the path & the $wildcard
198
        $directory = dirname($this->s3Key);
199
200
        // Get all of the folders in the base directory
201
        $folders = $this->storageDisk()->directories($directory);
202
203
        // Filter folders to find the wildcard path
204
        $folders = array_filter($folders, function ($value) {
205
            return str_starts_with($value, $this->s3Key);
206
        });
207
208
        // return the resolved path
209
        $this->s3Key = collect($folders)->values()->first();
210
211
        return $this;
212
    }
213
214
    /**
215
     * Retrieve an array of all files in a directory with an optional filtering closure.
216
     *
217
     * @param Closure|null $closure
218
     * @return Collection
219
     */
220
    public function allFiles(Closure $closure = null): Collection
221
    {
222
        // Create array of all files
223
        $allFiles = collect($this->storageDisk()->allFiles($this->s3Key));
224
225
        // Apply filtering closure
226
        if (isset($closure)) {
227
            return $allFiles->filter($closure);
228
        }
229
230
        return $allFiles;
231
    }
232
233
    /**
234
     * Retrieve an array of all directories within another directory with an optional filtering closure.
235
     *
236
     * @param Closure|null $closure
237
     * @return Collection
238
     */
239
    public function allDirectories(Closure $closure = null): Collection
240
    {
241
        // Create array of all directories
242
        $allDirectories = collect($this->storageDisk()->allDirectories($this->s3Key));
243
244
        // Apply filtering closure
245
        if (isset($closure)) {
246
            return $allDirectories->filter($closure);
247
        }
248
249
        return $allDirectories;
250
    }
251
}
252