ModelTrait::getS3Component()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace diecoding\aws\s3\traits;
4
5
use Yii;
6
use yii\web\UploadedFile;
7
8
/**
9
 * Trait ModelTrait for Model
10
 * 
11
 * @package diecoding\aws\s3\traits
12
 * 
13
 * @link      https://sugengsulistiyawan.my.id/
14
 * @author    Sugeng Sulistiyawan <[email protected]>
15
 * @copyright Copyright (c) 2023
16
 */
17
trait ModelTrait
18
{
19
    /**
20
     * @return \diecoding\aws\s3\Service|mixed
21
     */
22
    public function getS3Component()
23
    {
24
        return Yii::$app->get('s3');
25
    }
26
27
    /**
28
     * List the paths on S3 to each model file attribute.
29
     * It must be a Key-Value array, where Key is the attribute name and Value is the base path for the file in S3.
30
     * Override this method for saving each attribute in its own "folder".
31
     * 
32
     * @return array Key-Value of attributes and its paths.
33
     */
34
    public function attributePaths()
35
    {
36
        return [];
37
    }
38
39
    /**
40
     * Save UploadedFile toS3.
41
     * ! Important: This function uploads this model filename to keep consistency of the model.
42
     * 
43
     * @param UploadedFile $file Uploaded file to save
44
     * @param string $attribute Attribute name where the uploaded filename name will be saved
45
     * @param string $fileName Name which file will be saved. If empty will use the name from $file
46
     * @param bool $autoExtension `true` to automatically append or replace the extension to the file name. Default is `true`
47
     * 
48
     * @return string|false Uploaded full path of filename on success or `false` in failure.
49
     */
50
    public function saveUploadedFile(UploadedFile $file, $attribute, $fileName = '', $autoExtension = true)
51
    {
52
        if ($this->hasError) {
53
            return false;
54
        }
55
56
        if (empty($fileName)) {
57
            $fileName = $file->name;
58
        }
59
        if ($autoExtension) {
60
            $_file = (string) pathinfo($fileName, PATHINFO_FILENAME);
61
            $fileName = $_file . '.' . $file->extension;
62
        }
63
        $filePath = $this->getAttributePath($attribute) . '/' . $fileName;
64
65
        /** @var \Aws\ResultInterface $result */
66
        $result = $this->getS3Component()
67
            ->commands()
68
            ->upload(
69
                $filePath,
70
                $file->tempName
71
            )
72
            ->withContentType($file->type)
73
            ->execute();
74
75
        // Validate successful upload to S3
76
        if ($this->isSuccessResponseStatus($result)) {
77
            $this->{$attribute} = $fileName;
78
79
            return $fileName;
80
        }
81
82
        return false;
83
    }
84
85
    /**
86
     * Delete model file attribute from S3.
87
     * 
88
     * @param string $attribute Attribute name which holds the filename
89
     * 
90
     * @return bool `true` on success or if file doesn't exist.
91
     */
92
    public function removeFile($attribute)
93
    {
94
        if (empty($this->{$attribute})) {
95
            // No file to remove
96
            return true;
97
        }
98
99
        $filePath = $this->getAttributePath($attribute) . '/' . $this->{$attribute};
100
        $result = $this->getS3Component()
101
            ->commands()
102
            ->delete($filePath)
103
            ->execute();
104
105
        // Validate successful removal from S3
106
        if ($this->isSuccessResponseStatus($result)) {
107
            $this->{$attribute} = null;
108
109
            return true;
110
        }
111
112
        return false;
113
    }
114
115
    /**
116
     * Retrieves the URL for a given model file attribute.
117
     * 
118
     * @param string $attribute Attribute name which holds the filename
119
     * 
120
     * @return string URL to access file
121
     */
122
    public function getFileUrl($attribute)
123
    {
124
        if (empty($this->{$attribute})) {
125
            return '';
126
        }
127
128
        return $this->getS3Component()->getUrl($this->getAttributePath($attribute) . '/' . $this->{$attribute});
129
    }
130
131
    /**
132
     * Retrieves the presigned URL for a given model file attribute.
133
     * 
134
     * @param string $attribute Attribute name which holds the filename
135
     * 
136
     * @return string Presigned URL to access file
137
     */
138
    public function getFilePresignedUrl($attribute)
139
    {
140
        if (empty($this->{$attribute})) {
141
            return '';
142
        }
143
144
        return $this->getS3Component()->getPresignedUrl(
145
            $this->getAttributePath($attribute) . '/' . $this->{$attribute},
146
            $this->getPresignedUrlDuration($attribute)
147
        );
148
    }
149
150
    /**
151
     * Retrieves the URL signature expiration.
152
     * 
153
     * @param string $attribute Attribute name which holds the duration
154
     * 
155
     * @return mixed URL expiration
156
     */
157
    public function getPresignedUrlDuration($attribute)
158
    {
159
        if (empty($this->{$attribute})) {
160
            return 0;
161
        }
162
163
        return '+5 minutes';
164
    }
165
166
    /**
167
     * Retrieves the base path on S3 for a given attribute.
168
     * @see attributePaths()
169
     * 
170
     * @param string $attribute Attribute to get its path
171
     * 
172
     * @return string The path where all file of that attribute should be stored. Returns empty string if the attribute isn't in the list.
173
     */
174
    public function getAttributePath($attribute)
175
    {
176
        $paths = $this->attributePaths();
177
        if (array_key_exists($attribute, $paths)) {
178
            return $paths[$attribute];
179
        }
180
181
        return '';
182
    }
183
184
    /**
185
     * Check for valid status code from the S3 response.
186
     * Success responses will be considered status codes is 2**.
187
     * Override function for custom validations.
188
     * 
189
     * @param \Aws\ResultInterface $response S3 response containing the status code
190
     * 
191
     * @return bool whether this response is successful.
192
     */
193
    public function isSuccessResponseStatus($response)
194
    {
195
        return !empty($response->get('@metadata')['statusCode']) &&
196
            $response->get('@metadata')['statusCode'] >= 200 &&
197
            $response->get('@metadata')['statusCode'] < 300;
198
    }
199
}
200