Completed
Push — feature/6.x ( db50a0...aa9894 )
by Schlaefer
03:28
created

UploadsTable::moveUpload()   B

Complexity

Conditions 7
Paths 44

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 7
eloc 24
c 1
b 0
f 1
nc 44
nop 1
dl 0
loc 37
rs 8.6026

1 Method

Rating   Name   Duplication   Size   Complexity  
A UploadsTable::getUploadStorage() 0 9 2
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * Saito - The Threaded Web Forum
6
 *
7
 * @copyright Copyright (c) the Saito Project Developers
8
 * @link https://github.com/Schlaefer/Saito
9
 * @license http://opensource.org/licenses/MIT
10
 */
11
12
namespace ImageUploader\Model\Table;
13
14
use App\Lib\Model\Table\AppTable;
15
use Cake\Core\Configure;
16
use Cake\Event\Event;
17
use Cake\I18n\Number;
18
use Cake\ORM\RulesChecker;
19
use Cake\Validation\Validation;
20
use Cake\Validation\Validator;
21
use ImageUploader\Lib\UploadStorage;
22
use ImageUploader\Model\Entity\Upload;
23
24
/**
25
 * Uploads
26
 *
27
 * Indeces:
28
 * - user_id, title - Combined used for uniqueness test. User_id for user's
29
 *   upload overview page.
30
 */
31
class UploadsTable extends AppTable
32
{
33
    /**
34
     * Max filename length.
35
     *
36
     * Constrained to 191 due to InnoDB index max-length on MySQL 5.6.
37
     */
38
    public const FILENAME_MAXLENGTH = 191;
39
40
    /**
41
     * Handles persistent storage
42
     * @var \ImageUploader\Lib\UploadStorage
43
     */
44
    private UploadStorage $uploadStorage;
45
46
    /**
47
     * {@inheritDoc}
48
     */
49
    public function initialize(array $config): void
50
    {
51
        $this->addBehavior('Timestamp');
52
        $this->setEntityClass(Upload::class);
53
54
        $this->belongsTo('Users', ['foreignKey' => 'user_id']);
55
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60
    public function validationDefault(Validator $validator): Validator
61
    {
62
        $validator
63
            ->add('id', 'valid', ['rule' => 'numeric'])
64
            ->allowEmptyString('id', 'create')
65
            ->notBlank('name')
66
            ->notBlank('size')
67
            ->notBlank('type')
68
            ->notBlank('user_id')
69
            ->requirePresence(['name', 'size', 'type', 'user_id'], 'create');
70
71
        $validator->add(
72
            'tmp_name',
73
            [
74
                'file' => [
75
                    'rule' => [$this, 'validateFile'],
76
                ],
77
            ]
78
        );
79
80
        $validator->add(
81
            'title',
82
            [
83
                'maxLength' => [
84
                    'rule' => ['maxLength', self::FILENAME_MAXLENGTH],
85
                    'message' => __('vld.uploads.title.maxlength', self::FILENAME_MAXLENGTH),
86
                ],
87
            ]
88
        );
89
90
        return $validator;
91
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96
    public function buildRules(RulesChecker $rules): RulesChecker
97
    {
98
        /** @var \ImageUploader\Lib\UploaderConfig $UploaderConfig */
99
        $UploaderConfig = Configure::read('Saito.Settings.uploader');
100
        $nMax = $UploaderConfig->getMaxNumberOfUploadsPerUser();
101
        $rules->add(
102
            function (Upload $entity, array $options) use ($nMax) {
103
                $count = $this->findByUserId($entity->get('user_id'))->count();
104
105
                return $count < $nMax;
106
            },
107
            'maxAllowedUploadsPerUser',
108
            [
109
                'errorField' => 'user_id',
110
                'message' => __d('image_uploader', 'validation.error.maxNumberOfItems', $nMax),
111
            ]
112
        );
113
114
        // check that user exists
115
        $rules->add($rules->existsIn('user_id', 'Users'));
116
117
        // check that same user can't have two items with the same name
118
        $rules->add(
119
            $rules->isUnique(
120
                // Don't use a identifier like "name" which changes (jpg->png).
121
                ['title', 'user_id'],
122
                __d('image_uploader', 'validation.error.fileExists')
123
            )
124
        );
125
126
        return $rules;
127
    }
128
129
    /**
130
     * {@inheritDoc}
131
     */
132
    public function beforeSave(Event $event, Upload $entity, \ArrayObject $options)
133
    {
134
        if ($entity->isDirty('name') || $entity->isDirty('tmp_name')) {
135
            try {
136
                $this->getUploadStorage()->upload($entity);
137
            } catch (\Throwable $e) {
138
                return false;
139
            }
140
        }
141
142
        return true;
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     */
148
    public function beforeDelete(Event $event, Upload $entity, \ArrayObject $options)
149
    {
150
        try {
151
            $this->getUploadStorage()->delete($entity);
152
        } catch (\Throwable $e) {
153
            return false;
154
        }
155
156
        return true;
157
    }
158
159
    /**
160
     * Validate file by size
161
     *
162
     * @param mixed $check value
163
     * @param array $context context
164
     * @return string|bool
165
     */
166
    public function validateFile($check, array $context)
167
    {
168
        /** @var \ImageUploader\Lib\UploaderConfig $UploaderConfig */
169
        $UploaderConfig = Configure::read('Saito.Settings.uploader');
170
171
        $type = $context['data']['type'];
172
173
        /// Check file type
174
        if (!$UploaderConfig->hasType($type)) {
175
            return __d('image_uploader', 'validation.error.mimeType', $type);
176
        }
177
178
        /// Check file size
179
        $size = $UploaderConfig->getSize($type);
180
        if (!Validation::fileSize($check, '<', $size)) {
181
            return __d(
182
                'image_uploader',
183
                'validation.error.fileSize',
184
                Number::toReadableSize($size)
185
            );
186
        }
187
188
        return true;
189
    }
190
191
    /**
192
     * Getter for UploadHandler
193
     * @return \ImageUploader\Lib\UploadStorage UploadHandler
194
     */
195
    protected function getUploadStorage(): UploadStorage
196
    {
197
        if (empty($this->uploadStorage)) {
198
            /** @var \ImageUploader\Lib\UploaderConfig $UploaderConfig */
199
            $UploaderConfig = Configure::read('Saito.Settings.uploader');
200
            $this->uploadStorage = new UploadStorage($UploaderConfig->getStorageFilesystem());
201
        }
202
203
        return $this->uploadStorage;
204
    }
205
}
206