ImprovedUploader::getRenamePattern()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace LeKoala\FilePond;
4
5
use ReflectionClass;
6
use InvalidArgumentException;
7
use SilverStripe\Assets\File;
8
use SilverStripe\Assets\Image;
9
use SilverStripe\Control\HTTP;
10
use SilverStripe\Assets\Upload;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\Assets\FileNameFilter;
13
14
/**
15
 * This trait adds convenience methods and extra features to our standard uploader like:
16
 * - More useful default description
17
 * - Rename file with a pattern
18
 * - Default folder
19
 */
20
trait ImprovedUploader
21
{
22
    /**
23
     * @var string
24
     */
25
    protected $renamePattern;
26
27
    /**
28
     * @var boolean
29
     */
30
    protected $showDescriptionSize = true;
31
32
    /**
33
     * Array of accepted file types.
34
     * Can be mime types or wild cards. For instance ['image/*']
35
     * will accept all images. ['image/png', 'image/jpeg']
36
     * will only accepts PNGs and JPEGs.
37
     *
38
     * @return array<string>
39
     */
40
    public function getAcceptedFileTypes()
41
    {
42
        $validator = $this->getValidator();
0 ignored issues
show
Bug introduced by
It seems like getValidator() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
        /** @scrutinizer ignore-call */ 
43
        $validator = $this->getValidator();
Loading history...
43
        $extensions = $validator->getAllowedExtensions();
44
        $mimeTypes = HTTP::config()->uninherited('MimeTypes');
45
46
        $arr = [];
47
        foreach ($extensions as $ext) {
48
            if (isset($mimeTypes[$ext])) {
49
                $arr[] = $mimeTypes[$ext];
50
            }
51
        }
52
        $arr = array_unique($arr);
53
        return $arr;
54
    }
55
56
    /**
57
     * Set default description
58
     *
59
     * @param string $relation Type of relation, eg Image or File
60
     * @param DataObject $record A related record
61
     * @param string $name Relation name, eg "Logo"
62
     * @return string
63
     */
64
    protected function setDefaultDescription($relation, $record = null, $name = null)
65
    {
66
        $desc = '';
67
        if ($this->showDescriptionSize) {
68
            $size = File::format_size($this->getValidator()->getAllowedMaxFileSize());
69
            $desc .= _t('ImprovedUploader.MAXSIZE', 'Max file size: {size}', ['size' => $size]);
70
        }
71
        if ($relation == Image::class) {
72
            // do we have a preferred size set on the record?
73
            if ($record) {
74
                $sizes = $record->config()->image_sizes;
75
                if ($sizes && isset($sizes[$name])) {
76
                    if ($desc) {
77
                        $desc .= '; ';
78
                    }
79
                    // It is an array with two keys
80
                    $size = $sizes[$name][0] . 'x' . $sizes[$name][1];
81
                    if (isset($sizes[$name][2]) && $sizes[$name][2] == 'max') {
82
                        $desc .= _t('ImprovedUploader.MAXRESOLUTION', 'Maximum resolution: {size}px', ['size' => $size]);
83
                    } else {
84
                        $desc .= _t('ImprovedUploader.MINRESOLUTION', 'Minimum resolution: {size}px', ['size' => $size]);
85
                    }
86
                }
87
            }
88
        }
89
90
        // Only show meaningful list of extensions
91
        $extensions = $this->getAllowedExtensions();
0 ignored issues
show
Bug introduced by
It seems like getAllowedExtensions() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

91
        /** @scrutinizer ignore-call */ 
92
        $extensions = $this->getAllowedExtensions();
Loading history...
92
        if (count($extensions) < 7) {
93
            if ($desc) {
94
                $desc .= '; ';
95
            }
96
            $desc .= _t('ImprovedUploader.ALLOWEXTENSION', 'Allowed extensions: {ext}', array('ext' => implode(',', $extensions)));
97
        }
98
99
        $this->description = $desc;
0 ignored issues
show
Bug Best Practice introduced by
The property description does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
100
    }
101
102
    /**
103
     * @return string
104
     */
105
    protected function getDefaultFolderName()
106
    {
107
        // There is no record, use default upload folder
108
        if (!$this->record) {
109
            return Upload::config()->uploads_folder;
110
        }
111
        // The record can determine its own upload folder
112
        if ($this->record->hasMethod('getFolderName')) {
113
            return $this->record->getFolderName();
114
        }
115
        // Have a sane default for others
116
        $class = (new ReflectionClass($this->record))->getShortName();
117
        $name = $this->getSafeName();
118
        return $class . '/' . $name;
119
    }
120
121
    /**
122
     * Apply a pattern set with setRenamePattern
123
     *
124
     * This is more easily applied directly on the temp file array
125
     * where you can change the "name" key
126
     *
127
     * @param string $originalName The name of the file
128
     * @param string $pattern
129
     * @return string The filename
130
     */
131
    protected function changeFilenameWithPattern($originalName, $pattern)
132
    {
133
        // name of file, with extension
134
        $name = pathinfo($originalName, PATHINFO_BASENAME);
135
        // name of file, without extension
136
        $filename = pathinfo($originalName, PATHINFO_FILENAME);
137
        $extension = pathinfo($originalName, PATHINFO_EXTENSION);
138
139
        $field = $this->getSafeName();
140
141
        $map = [
142
            '{name}' => $name,
143
            '{basename}' => $name,
144
            '{filename}' => $filename,
145
            '{extension}' => $extension,
146
            '{timestamp}' => time(),
147
            '{date}' => date('Ymd'),
148
            '{datetime}' => date('Ymd_His'),
149
            '{field}' => $field,
150
        ];
151
        $search = array_keys($map);
152
        $replace = array_values($map);
153
        $replacedName = str_replace($search, $replace, $pattern);
154
155
        // Ensure end result is valid
156
        $filter = new FileNameFilter;
157
        $replacedName = $filter->filter($replacedName);
158
159
        return $replacedName;
160
    }
161
162
    /**
163
     * Get the value of renamePattern
164
     *
165
     * @return string
166
     */
167
    public function getRenamePattern()
168
    {
169
        return $this->renamePattern;
170
    }
171
172
    /**
173
     * Rename pattern can use the following variables:
174
     * - {field}
175
     * - {name}
176
     * - {basename}
177
     * - {extension}
178
     * - {timestamp}
179
     * - {date}
180
     * - {datetime}
181
     *
182
     * A pattern should contain at least {name} or a dot
183
     *
184
     * @param string $renamePattern
185
     * @return $this
186
     */
187
    public function setRenamePattern($renamePattern)
188
    {
189
        // Basic check for extension
190
        if (strpos($renamePattern, '.') === false && strpos($renamePattern, '{name}') === false) {
191
            throw new InvalidArgumentException("Pattern $renamePattern should contain an extension");
192
        }
193
        $this->renamePattern = $renamePattern;
194
        return $this;
195
    }
196
197
    /**
198
     * Get safe name even for multi uploads
199
     *
200
     * @return string
201
     */
202
    public function getSafeName()
203
    {
204
        return str_replace('[]', '', $this->getName());
0 ignored issues
show
Bug introduced by
It seems like getName() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

204
        return str_replace('[]', '', $this->/** @scrutinizer ignore-call */ getName());
Loading history...
205
    }
206
207
    /**
208
     * A simple alias that makes the IDE happy
209
     *
210
     * @param int $ID
211
     * @return File|Image|null
212
     */
213
    protected function getFileByID($ID)
214
    {
215
        return File::get()->byID($ID);
216
    }
217
218
    /**
219
     * Convert an array of file to a single file
220
     *
221
     * This is useful for multi uploads
222
     *
223
     * @param array $tmpFile
224
     * @return array
225
     */
226
    protected function normalizeTempFile($tmpFile)
227
    {
228
        $newTmpFile = [];
229
        foreach ($tmpFile as $k => $v) {
230
            if (is_array($v)) {
231
                $v = $v[0];
232
            }
233
            $newTmpFile[$k] = $v;
234
        }
235
        return $newTmpFile;
236
    }
237
}
238