Completed
Push — master ( 522461...c89cc2 )
by Fabien
02:24
created

ConfigurationWarning::getQueryBuilder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
namespace Fab\Media\View\Warning;
3
4
/*
5
 * This file is part of the Fab/Media project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10
11
use Fab\Media\Module\MediaModule;
12
use TYPO3\CMS\Core\Database\ConnectionPool;
13
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
use Fab\Vidi\Tca\Tca;
16
use Fab\Vidi\View\AbstractComponentView;
17
18
/**
19
 * View which renders a button for uploading assets.
20
 */
21
class ConfigurationWarning extends AbstractComponentView
22
{
23
24
    /**
25
     * @var array
26
     */
27
    protected $notAllowedMountPoints = [];
28
29
    /**
30
     * Renders a button for uploading assets.
31
     *
32
     * @return string
33
     */
34
    public function render()
35
    {
36
37
        $result = '';
38
39
        // Check whether storage is configured or not.
40
        if ($this->checkStorageNotConfigured()) {
41
            $this->configureStorage();
42
            $result .= $this->formatMessageForStorageConfigured();
43
        }
44
45
        // Check whether storage is online or not.
46
        if ($this->checkStorageOffline()) {
47
            $result .= $this->formatMessageForStorageOffline();
48
        }
49
50
        // Check all mount points of the storage are available
51
        if (!$this->checkMountPoints()) {
52
            $result .= $this->formatMessageForMountPoints();
53
        }
54
55
        // Check all mount points of the storage are available
56
        if (!$this->hasBeenWarmedUp() && !$this->checkColumnNumberOfReferences()) {
57
            if ($this->canBeInitializedSilently() < 2000) {
58
                $numberOfFiles = $this->getCacheService()->warmUp();
59
                $result .= $this->formatMessageForSilentlyUpdatedColumnNumberOfReferences($numberOfFiles);
60
                touch($this->getWarmUpSemaphoreFile());
61
            } else {
62
                $result .= $this->formatMessageForUpdateRequiredColumnNumberOfReferences();
63
            }
64
        }
65
66
        return $result;
67
    }
68
69
    /**
70
     * @return \Fab\Media\Cache\CacheService|object
71
     */
72
    protected function getCacheService()
73
    {
74
        return GeneralUtility::makeInstance(\Fab\Media\Cache\CacheService::class);
75
    }
76
77
    /**
78
     * @return boolean
79
     */
80
    protected function configureStorage()
81
    {
82
        $tableName = 'sys_file_storage';
83
        $fields = array(
84
            'maximum_dimension_original_image',
85
            'extension_allowed_file_type_1',
86
            'extension_allowed_file_type_2',
87
            'extension_allowed_file_type_3',
88
            'extension_allowed_file_type_4',
89
            'extension_allowed_file_type_5',
90
        );
91
92
        $values = [];
93
        foreach ($fields as $field) {
94
            $values[$field] = Tca::table($tableName)->field($field)->getDefaultValue();
95
        }
96
97
        $storage = $this->getMediaModule()->getCurrentStorage();
98
        $this->getDatabaseConnection()->exec_UPDATEquery($tableName, 'uid = ' . $storage->getUid(), $values);
99
    }
100
101
    /**
102
     * @return bool
103
     */
104
    protected function hasBeenWarmedUp()
105
    {
106
        return is_file(($this->getWarmUpSemaphoreFile()));
107
    }
108
109
    /**
110
     * @return string
111
     */
112
    protected function getWarmUpSemaphoreFile()
113
    {
114
        return PATH_site . 'typo3temp/.media_cache_warmed_up';
115
    }
116
117
    /**
118
     * Check whether the storage is correctly configured.
119
     *
120
     * @return boolean
121
     */
122
    protected function checkStorageNotConfigured()
123
    {
124
        $currentStorage = $this->getMediaModule()->getCurrentStorage();
125
        $storageRecord = $currentStorage->getStorageRecord();
126
127
        // Take the storage fields and check whether some data was initialized.
128
        $fields = array(
129
            'extension_allowed_file_type_1',
130
            'extension_allowed_file_type_2',
131
            'extension_allowed_file_type_3',
132
            'extension_allowed_file_type_4',
133
            'extension_allowed_file_type_5',
134
        );
135
136
        $result = true;
137
        foreach ($fields as $fieldName) {
138
            // true means the storage has data and thus was configured / saved once.
139
            if (!empty($storageRecord[$fieldName])) {
140
                $result = false;
141
                break;
142
            }
143
        }
144
        return $result;
145
    }
146
147
    /**
148
     * Format a message whenever the storage is offline.
149
     *
150
     * @return string
151
     */
152
    protected function formatMessageForStorageConfigured()
153
    {
154
        $storage = $this->getMediaModule()->getCurrentStorage();
155
156
        $result = <<< EOF
157
			<div class="alert alert-info">
158
				<div class="alert-title">
159
						Storage has been configured.
160
				</div>
161
				<div class="alert-message">
162
					The storage "{$storage->getName()}" was not configured for Media. Some default values have automatically been added.
163
					To see those values, open the storage record "{$storage->getName()}" ({$storage->getUid()})
164
					and check under tab "Upload Settings" or "Default mount points".
165
				</div>
166
			</div>
167
EOF;
168
169
        return $result;
170
    }
171
172
    /**
173
     * Check whether the storage is online or not.
174
     *
175
     * @return boolean
176
     */
177
    protected function checkStorageOffline()
178
    {
179
        return !$this->getMediaModule()->getCurrentStorage()->isOnline();
180
    }
181
182
    /**
183
     * Format a message whenever the storage is offline.
184
     *
185
     * @return string
186
     */
187
    protected function formatMessageForStorageOffline()
188
    {
189
        $storage = $this->getMediaModule()->getCurrentStorage();
190
191
        $result = <<< EOF
192
			<div class="alert alert-warning">
193
					<div class="alert-title">
194
						Storage is currently offline
195
				</div>
196
					<div class="alert-message">
197
						The storage "{$storage->getName()}" looks currently to be off-line. Contact an administrator if you think this is an error.
198
					</div>
199
				</div>
200
			</div>
201
EOF;
202
203
        return $result;
204
    }
205
206
    /**
207
     * Check whether mount points privilege are ok.
208
     *
209
     * @return boolean
210
     */
211
    protected function checkMountPoints()
212
    {
213
        if (!$this->getBackendUser()->isAdmin()) {
214
215
            $fileMounts = $this->getBackendUser()->getFileMountRecords();
216
217
            $fileMountIdentifiers = [];
218
            foreach ($fileMounts as $fileMount) {
219
                $fileMountIdentifiers[] = $fileMount['uid'];
220
            }
221
222
            $storage = $this->getMediaModule()->getCurrentStorage();
223
            $storageRecord = $storage->getStorageRecord();
224
            $fieldNames = array(
225
                'mount_point_file_type_1',
226
                'mount_point_file_type_2',
227
                'mount_point_file_type_3',
228
                'mount_point_file_type_4',
229
                'mount_point_file_type_5',
230
            );
231
            foreach ($fieldNames as $fileName) {
232
                $fileMountIdentifier = (int)$storageRecord[$fileName];
233
                if ($fileMountIdentifier > 0 && !in_array($fileMountIdentifier, $fileMountIdentifiers)) {
234
                    $this->notAllowedMountPoints[] = $this->fetchMountPoint($fileMountIdentifier);
235
                } else {
236
                    # $fileMountIdentifier
237
                    $folder = $storage->getRootLevelFolder();
0 ignored issues
show
Unused Code introduced by
$folder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
238
                }
239
            }
240
        }
241
        return empty($this->notAllowedMountPoints);
242
    }
243
244
    /**
245
     * Return a mount point according to an file mount identifier.
246
     *
247
     * @param string $identifier
248
     * @return array
249
     */
250
    protected function fetchMountPoint($identifier)
251
    {
252
        /** @var QueryBuilder $queryBuilder */
253
        $queryBuilder = $this->getQueryBuilder('sys_filemounts');
254
        return $queryBuilder
255
            ->select('*')
256
            ->from('sys_filemounts')
257
            ->where('uid = ' . $identifier)
258
            ->execute()
259
            ->fetch();
260
    }
261
262
    /**
263
     * Format a message whenever mount points privilege are not OK.
264
     *
265
     * @return string
266
     */
267
    protected function formatMessageForMountPoints()
268
    {
269
270
        $storage = $this->getMediaModule()->getCurrentStorage();
271
        $backendUser = $this->getBackendUser();
272
273
        foreach ($this->notAllowedMountPoints as $notAllowedMountPoints) {
274
            $list = sprintf('<li>"%s" with path %s</li>',
275
                $notAllowedMountPoints['title'],
276
                $notAllowedMountPoints['path']
277
            );
278
279
        }
280
281
        $result = <<< EOF
282
			<div class="alert alert-warning">
283
					<div class="alert-title">
284
						File mount are wrongly configured for user "{$backendUser->user['username']}".
285
				</div>
286
					<div class="alert-message">
287
						User "{$backendUser->user['username']}" has no access to the following mount point configured in storage "{$storage->getName()}":
288
						<ul>
289
						{$list}
0 ignored issues
show
Bug introduced by
The variable $list does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
290
						</ul>
291
					</div>
292
				</div>
293
			</div>
294
EOF;
295
296
        return $result;
297
    }
298
299
    /**
300
     * @return boolean
301
     */
302
    protected function canBeInitializedSilently()
303
    {
304
        /** @var QueryBuilder $queryBuilder */
305
        $queryBuilder = $this->getQueryBuilder('sys_file');
306
        $count = $queryBuilder
307
            ->count('*')
308
            ->from('sys_file')
309
            ->execute()
310
            ->fetchColumn(0);
311
        return (int)$count;
312
313
    }
314
315
    /**
316
     * Check whether the column "total_of_references" has been already processed once.
317
     *
318
     * @return boolean
319
     */
320
    protected function checkColumnNumberOfReferences()
321
    {
322
        /** @var QueryBuilder $queryBuilder */
323
        $queryBuilder = $this->getQueryBuilder('sys_file');
324
        $file = $queryBuilder
325
            ->select('*')
326
            ->from('sys_file')
327
            ->where('number_of_references > 0')
328
            ->execute()
329
            ->fetch();
330
331
        return !empty($file);
332
    }
333
334
    /**
335
     * Format a message if columns "total_of_references" looks wrong.
336
     *
337
     * @param int $numberOfFile
338
     * @return string
339
     */
340
    protected function formatMessageForSilentlyUpdatedColumnNumberOfReferences($numberOfFile)
341
    {
342
343
        $result = <<< EOF
344
			<div class="alert alert-success">
345
				<div class="alert-title">
346
						Initialized column "number_of_references" for ${numberOfFile} files
347
				</div>
348
				<div class="alert-message">
349
					The column "sys_file.number_of_references" is used as a caching column for storing the total number of usage of a file.
350
					It is required when searching files by "usage" in the visual search bar. For example searching for files with 0 usage,
351
					corresponds to file that are not used on the Frontend,
352
					The column can be initialized manually  <strong>by opening the tool "Cache warm up" in in the upper right button of this module</strong>
353
					or by a scheduler task.
354
					The number of usage is then updated by a Hook each time a record is edited which contains file references coming from "sys_file_reference" or from "sys_refindex" if soft
355
					reference.
356
				</div>
357
			</div>
358
EOF;
359
360
        return $result;
361
    }
362
363
364
    /**
365
     * Format a message if columns "total_of_references" looks wrong.
366
     *
367
     * @return string
368
     */
369
    protected function formatMessageForUpdateRequiredColumnNumberOfReferences()
370
    {
371
372
        $result = <<< EOF
373
			<div class="alert alert-warning">
374
				<div class="alert-title">
375
						Column "number_of_references" requires to be initialized.
376
				</div>
377
				<div class="alert-message">
378
				    This action can not be done automatically as there are more than 2000 files. <br/>
379
380
					The column "number_of_references" in "sys_file" is used as a caching column for storing the total number of usage of a file.
381
					It is required when searching files by "usage" in the visual search bar. For example searching for files with 0 usage,
382
					corresponds to file that are not used on the Frontend,
383
					The column can be initialized <strong>by opening the tool "Cache warm up" in in the upper right button of this module</strong>
384
					or by a scheduler task.
385
					The number of usage is then updated by a Hook each time a record is edited which contains file references coming from "sys_file_reference" or from "sys_refindex" if soft
386
					reference.
387
				</div>
388
			</div>
389
EOF;
390
391
        return $result;
392
    }
393
394
    /**
395
     * Returns an instance of the current Backend User.
396
     *
397
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
398
     */
399
    protected function getBackendUser()
400
    {
401
        return $GLOBALS['BE_USER'];
402
    }
403
404
    /**
405
     * @param string $tableName
406
     * @return object|QueryBuilder
407
     */
408
    protected function getQueryBuilder($tableName): QueryBuilder
409
    {
410
        /** @var ConnectionPool $connectionPool */
411
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
412
        return $connectionPool->getQueryBuilderForTable($tableName);
413
    }
414
415
    /**
416
     * @return MediaModule|object
417
     */
418
    protected function getMediaModule()
419
    {
420
        return GeneralUtility::makeInstance(\Fab\Media\Module\MediaModule::class);
421
    }
422
423
}
424