MediaRequestHandler::handleMediaRequest()   C
last analyzed

Complexity

Conditions 12
Paths 22

Size

Total Lines 62
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 14.25

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 33
c 1
b 0
f 0
nc 22
nop 1
dl 0
loc 62
ccs 24
cts 32
cp 0.75
crap 14.25
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the Divergence package.
4
 *
5
 * (c) Henry Paradiz <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Divergence\Controllers;
12
13
use Exception;
14
use Divergence\Models\Media\Media;
15
use Divergence\Models\ActiveRecord;
16
use Divergence\Responders\Response;
17
use Divergence\Responders\JsonBuilder;
18
use Divergence\Responders\EmptyBuilder;
19
use Divergence\Responders\EmptyResponse;
20
use Divergence\Responders\MediaBuilder;
21
use Psr\Http\Message\ResponseInterface;
22
use Divergence\Responders\MediaResponse;
23
use GuzzleHttp\Psr7\ServerRequest;
24
use Psr\Http\Message\ServerRequestInterface;
25
26
class MediaRequestHandler extends RecordsRequestHandler
27
{
28
    // RecordRequestHandler configuration
29
    public static $recordClass = Media::class;
30
    public $accountLevelRead = false;
31
    public $accountLevelBrowse = 'User';
32
    public $accountLevelWrite = 'User';
33
    public $accountLevelAPI = false;
34
    public $browseLimit = 100;
35
    public $browseOrder = ['ID' => 'DESC'];
36
37
    // MediaRequestHandler configuration
38
    public $defaultPage = 'browse';
39
    public $defaultThumbnailWidth = 100;
40
    public $defaultThumbnailHeight = 100;
41
    public $uploadFileFieldName = 'mediaFile';
42
    public $responseMode = 'html';
43
44
    public static $inputStream = 'php://input'; // this is a setting so that unit tests can provide a fake stream :)
45
46
    public $searchConditions = [
47
        'Caption' => [
48
            'qualifiers' => ['any','caption']
49
            ,'points' => 2
50
            ,'sql' => 'Caption LIKE "%%%s%%"',
51
        ]
52
        ,'CaptionLike' => [
53
            'qualifiers' => ['caption-like']
54
            ,'points' => 2
55
            ,'sql' => 'Caption LIKE "%s"',
56
        ]
57
        ,'CaptionNot' => [
58
            'qualifiers' => ['caption-not']
59
            ,'points' => 2
60
            ,'sql' => 'Caption NOT LIKE "%%%s%%"',
61
        ]
62
        ,'CaptionNotLike' => [
63
            'qualifiers' => ['caption-not-like']
64
            ,'points' => 2
65
            ,'sql' => 'Caption NOT LIKE "%s"',
66
        ],
67
    ];
68
69
    private ?ServerRequest $request;
70
71 25
    public function handle(ServerRequestInterface $request): ResponseInterface
72
    {
73 25
        $this->request = $request;
74
75
        // handle json response mode
76 25
        if ($this->peekPath() == 'json') {
77 11
            $this->shiftPath();
78 11
            $this->responseBuilder = JsonBuilder::class;
79
        }
80
81
        // handle action
82 25
        switch ($action = $this->shiftPath()) {
83
84 25
            case 'upload':
85 7
                {
86 7
                    return $this->handleUploadRequest();
87 7
                }
88
89 18
            case 'open':
90
                {
91
                    $mediaID = $this->shiftPath();
92
93
                    return $this->handleMediaRequest($mediaID);
94
                }
95
96 18
            case 'download':
97 1
                {
98 1
                    $mediaID = $this->shiftPath();
99 1
                    if ($filename = $this->shiftPath()) {
100 1
                        $filename = urldecode($filename);
101 1
                    }
102 1
                    return $this->handleDownloadRequest($mediaID, $filename);
103 1
                }
104
105 17
            case 'info':
106 1
                {
107 1
                    $mediaID = $this->shiftPath();
108
109 1
                    return $this->handleInfoRequest($mediaID);
110 1
                }
111
112 16
            case 'caption':
113
                {
114
                    $mediaID = $this->shiftPath();
115
116
                    return $this->handleCaptionRequest($mediaID);
117
                }
118
119 16
            case 'delete':
120
                {
121
                    $mediaID = $this->shiftPath();
122
                    return $this->handleDeleteRequest($mediaID);
123
                }
124
125 16
            case 'thumbnail':
126 3
                {
127 3
                    return $this->handleThumbnailRequest();
128 3
                }
129
130
            case false:
131 12
            case '':
132 12
            case 'browse':
133 1
                {
134 1
                    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
135 1
                        return $this->handleUploadRequest();
136 1
                    }
137
138 1
                    return $this->handleBrowseRequest();
139 1
                }
140
141
            default:
142 12
                {
143 12
                    if (ctype_digit($action)) {
144 12
                        return $this->handleMediaRequest($action);
145 12
                    } else {
146 12
                        return parent::handleRecordsRequest($action);
147 12
                    }
148 12
                }
149
        }
150
    }
151
152
153 7
    public function handleUploadRequest($options = []): ResponseInterface
154
    {
155 7
        $this->checkUploadAccess();
156
157 7
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
158
            // init options
159 5
            $options = array_merge([
160 5
                'fieldName' => $this->uploadFileFieldName,
161 5
            ], $options);
162
163
164
            // check upload
165 5
            if (empty($_FILES[$options['fieldName']])) {
166 1
                return $this->throwUploadError('You did not select a file to upload');
167
            }
168
169
            // handle upload errors
170 4
            if ($_FILES[$options['fieldName']]['error'] != UPLOAD_ERR_OK) {
171 4
                switch ($_FILES[$options['fieldName']]['error']) {
172 4
                    case UPLOAD_ERR_NO_FILE:
173 1
                        return $this->throwUploadError('You did not select a file to upload');
174
175 3
                    case UPLOAD_ERR_INI_SIZE:
176 2
                    case UPLOAD_ERR_FORM_SIZE:
177 1
                        return $this->throwUploadError('Your file exceeds the maximum upload size. Please try again with a smaller file.');
178
179 2
                    case UPLOAD_ERR_PARTIAL:
180 1
                        return $this->throwUploadError('Your file was only partially uploaded, please try again.');
181
182
                    default:
183 1
                        return $this->throwUploadError('There was an unknown problem while processing your upload, please try again.');
184
                }
185
            }
186
187
            // init caption
188
            if (!isset($options['Caption'])) {
189
                if (!empty($_REQUEST['Caption'])) {
190
                    $options['Caption'] = $_REQUEST['Caption'];
191
                } else {
192
                    $options['Caption'] = preg_replace('/\.[^.]+$/', '', $_FILES[$options['fieldName']]['name']);
193
                }
194
            }
195
196
            // create media
197
            try {
198
                $Media = Media::createFromUpload($_FILES[$options['fieldName']]['tmp_name'], $options);
199
            } catch (Exception $e) {
200
                return $this->throwUploadError($e->getMessage());
201
            }
202 2
        } elseif ($_SERVER['REQUEST_METHOD'] == 'PUT') {
203 2
            $put = fopen(static::$inputStream, 'r'); // open input stream
204
205 2
            $tmp = tempnam('/tmp', 'dvr');  // use PHP to make a temporary file
206 2
            $fp = fopen($tmp, 'w'); // open write stream to temp file
207
208
            // write
209 2
            while ($data = fread($put, 1024)) {
210 2
                fwrite($fp, $data);
211
            }
212
213
            // close handles
214 2
            fclose($fp);
215 2
            fclose($put);
216
217
            // create media
218
            try {
219 2
                $Media = Media::createFromFile($tmp, $options);
220
            } catch (Exception $e) {
221 2
                return $this->throwUploadError('The file you uploaded is not of a supported media format');
222
            }
223
        } else {
224
            return $this->respond('upload');
225
        }
226
227
        // assign context
228 2
        if (!empty($_REQUEST['ContextClass']) && !empty($_REQUEST['ContextID'])) {
229
            if (!is_subclass_of($_REQUEST['ContextClass'], ActiveRecord::class)
230
                || !in_array($_REQUEST['ContextClass']::getStaticRootClass(), Media::$fields['ContextClass']['values'])
231
                || !is_numeric($_REQUEST['ContextID'])) {
232
                return $this->throwUploadError('Context is invalid');
233
            } elseif (!$Media->Context = $_REQUEST['ContextClass']::getByID($_REQUEST['ContextID'])) {
234
                return $this->throwUploadError('Context class not found');
235
            }
236
237
            $Media->save();
238
        }
239
240 2
        return $this->respond('uploadComplete', [
241 2
            'success' => (bool)$Media
242 2
            ,'data' => $Media,
243 2
        ]);
244
    }
245
246 2
    public function respondRangeNotSatisfiable(string $responseID, int $start, int $end, int $size): Response
247
    {
248 2
        $this->responseBuilder = EmptyBuilder::class;
249
250 2
        return $this->respondEmpty($responseID)
251 2
            ->withStatus(416) // Range Not Satisfiable
252 2
            ->withHeader('Content-Range', "bytes $start-$end/$size");
253
    }
254
255
    /**
256
     * Set caching headers
257
     *
258
     * @param Response $response
259
     * @return Response
260
     */
261 10
    public function setCache(Response $response): Response
262
    {
263 10
        $expires = 60*60*24*365;
264 10
        return $response->withHeader('Cache-Control', "public, max-age= $expires")
265 10
        ->withHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time()+$expires))
266 10
        ->withHeader('Pragma', 'public');
267
    }
268
269 9
    public function respondWithMedia(Media $Media, $variant, $responseID, $responseData = []): ResponseInterface
270
    {
271 9
        if ($this->responseBuilder != MediaBuilder::class) {
272
            throw new Exception('Media responses require MediaBuilder for putting together a response.');
273
        }
274 9
        $className = $this->responseBuilder;
275 9
        $responseBuilder = new $className($responseID, $responseData);
276
277 9
        $responseBuilder->setContentType($Media->MIMEType);
278
279
280 9
        $size = filesize($responseID);
281 9
        $length = $size;
282 9
        $start = 0;
283 9
        $end = $size - 1;
284
285
        // interpret range requests
286 9
        $_server = $this->request->getServerParams();
0 ignored issues
show
Bug introduced by
The method getServerParams() does not exist on null. ( Ignorable by Annotation )

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

286
        /** @scrutinizer ignore-call */ 
287
        $_server = $this->request->getServerParams();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
287 9
        if (!empty($_server['HTTP_RANGE'])) {
288 7
            $chunkStart = $start;
0 ignored issues
show
Unused Code introduced by
The assignment to $chunkStart is dead and can be removed.
Loading history...
289 7
            $chunkEnd = $end;
0 ignored issues
show
Unused Code introduced by
The assignment to $chunkEnd is dead and can be removed.
Loading history...
290
291 7
            list(, $range) = explode('=', $_server['HTTP_RANGE'], 2);
292
293
            // comma indicates multiple ranges which we currently do not support
294 7
            if (strpos($range, ',') !== false) {
295 1
                return $this->respondRangeNotSatisfiable($responseID, $start, $end, $size);
296
            }
297
298 6
            if ($range == '-') { // missing range start and end
299 1
                $range = '0-';
300
            }
301
302 6
            $range = explode('-', $range);
303 6
            $chunkStart = $range[0];
304 6
            $chunkEnd = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
305
306
307 6
            $chunkEnd = ($chunkEnd > $end) ? $end : $chunkEnd;
308
309
            // requested content out of bounds
310 6
            if ($chunkStart > $chunkEnd || $chunkStart > $size - 1 || $chunkEnd >= $size) {
311 1
                return $this->respondRangeNotSatisfiable($responseID, $start, $end, $size);
312
            }
313
314 5
            $start = intval($chunkStart);
315 5
            $end = intval($chunkEnd);
316 5
            $length = $end - $start + 1;
317 5
            $responseBuilder->setRange($start, $end, $length);
318
        }
319
320
321 7
        $response = new MediaResponse($responseBuilder);
322 7
        $response = $this->setCache($response);
323
324
        // tell browser ranges are accepted
325 7
        $response = $response->withHeader('Accept-Ranges', 'bytes')
326 7
        // provide a unique ID for this media
327 7
        ->withHeader('ETag', 'media-'.$Media->ID.'-'.$variant);
328
329
        // if partial content provide proper response header
330 7
        if (isset($chunkStart)) {
331
            // only send 206 if response is less than the whole file
332 5
            if ($end-$start+1<$size) {
333 3
                $response = $response->withStatus(206);
334
            }
335 5
            $response = $response->withHeader('Content-Range', "bytes $start-$end/$size")
336 5
            ->withHeader('Content-Length', $length);
337
        } else {
338
            // range
339 2
            $filesize = filesize($Media->getFilesystemPath($variant));
340 2
            $end = $filesize - 1;
341 2
            $response = $response->withHeader('Content-Range', 'bytes 0-'.$end.'/'.$filesize)
342 2
                ->withHeader('Content-Length', $filesize);
343
        }
344
345 7
        return $response;
346
    }
347
348 3
    public function respondWithThumbnail(Media $Media, $variant, $responseID, $responseData = []): ResponseInterface
349
    {
350 3
        if ($this->responseBuilder != MediaBuilder::class) {
351
            throw new Exception('Media responses require MediaBuilder for putting together a response.');
352
        }
353 3
        $className = $this->responseBuilder;
354 3
        $responseBuilder = new $className($responseID, $responseData);
355
356 3
        $responseBuilder->setContentType($Media->ThumbnailMIMEType);
357
358 3
        $response = new MediaResponse($responseBuilder);
359 3
        $response = $this->setCache($response);
360
361 3
        $response = $response->withHeader('ETag', "media-$Media->ID-$variant")
362 3
            ->withHeader('Content-Length', filesize($responseID));
363
364 3
        return $response;
365
    }
366
367 4
    public function respondEmpty($responseID, $responseData = [])
368
    {
369 4
        if ($this->responseBuilder != EmptyBuilder::class) {
370
            throw new Exception('Media responses require MediaBuilder for putting together a response.');
371
        }
372 4
        $className = $this->responseBuilder;
373 4
        $responseBuilder = new $className($responseID, $responseData);
374 4
        $response = new EmptyResponse($responseBuilder);
375 4
        return $response;
376
    }
377
378
379 12
    public function handleMediaRequest($mediaID): ResponseInterface
380
    {
381 12
        if (empty($mediaID)) {
382
            return $this->throwNotFoundError();
383
        }
384
385
        // get media
386
        try {
387 12
            $Media = Media::getById($mediaID);
388
        } catch (Exception $e) {
389
            return $this->throwUnauthorizedError();
390
        }
391
392 12
        if (!$Media) {
393 1
            return $this->throwNotFoundError();
394
        }
395
396 11
        if (!$this->checkReadAccess($Media)) {
397
            return $this->throwNotFoundError();
398
        }
399
400
401 11
        $_server = $this->request->getServerParams();
402
403 11
        if (isset($_server['HTTP_ACCEPT'])) {
404
            if ($_server['HTTP_ACCEPT'] == 'application/json') {
405
                $this->responseBuilder = JsonBuilder::class;
406
            }
407
        }
408
409 11
        if ($this->responseBuilder == JsonBuilder::class) {
410 1
            return $this->respond('media', [
411 1
                'success' => true
412 1
                ,'data' => $Media,
413 1
            ]);
414
        } else {
415
416
            // determine variant
417 10
            if ($variant = $this->shiftPath()) {
418
                if (!$Media->isVariantAvailable($variant)) {
419
                    return $this->throwNotFoundError();
420
                }
421
            } else {
422 10
                $variant = 'original';
423
            }
424
425
            // initialize response
426 10
            $this->responseBuilder = MediaBuilder::class;
427 10
            set_time_limit(0);
428 10
            $filePath = $Media->getFilesystemPath($variant);
429
430
            // media are immutable for a given URL, so no need to actually check anything if the browser wants to revalidate its cache
431 10
            if (!empty($_server['HTTP_IF_NONE_MATCH']) || !empty($_server['HTTP_IF_MODIFIED_SINCE'])) {
432 2
                $this->responseBuilder = EmptyBuilder::class;
433 2
                $response = $this->respondEmpty($filePath);
434 2
                $response->withDefaults(304);
435
436 2
                return $response;
437
            }
438
439
440 8
            return $this->respondWithMedia($Media, $variant, $filePath);
441
        }
442
    }
443
444 1
    public function handleInfoRequest($mediaID): ResponseInterface
445
    {
446 1
        if (empty($mediaID) || !is_numeric($mediaID)) {
447
            $this->throwNotFoundError();
448
        }
449
450
        // get media
451
        try {
452 1
            $Media = Media::getById($mediaID);
453
        } catch (Exception $e) {
454
            return $this->throwUnauthorizedError();
455
        }
456
457 1
        if (!$Media) {
458
            return $this->throwNotFoundError();
459
        }
460
461 1
        if (!$this->checkReadAccess($Media)) {
462
            return $this->throwUnauthorizedError();
463
        }
464
465 1
        return parent::handleRecordRequest($Media);
466
    }
467
468 1
    public function handleDownloadRequest($media_id, $filename = false): ResponseInterface
469
    {
470 1
        if (empty($media_id) || !is_numeric($media_id)) {
471
            $this->throwNotFoundError();
472
        }
473
474
        // get media
475
        try {
476 1
            $Media = Media::getById($media_id);
477
        } catch (Exception $e) {
478
            return $this->throwUnauthorizedError();
479
        }
480
481
482 1
        if (!$Media) {
483
            return $this->throwNotFoundError();
484
        }
485
486 1
        if (!$this->checkReadAccess($Media)) {
487
            return $this->throwUnauthorizedError();
488
        }
489
490 1
        $filePath = $Media->getFilesystemPath('original');
491
492 1
        $this->responseBuilder = MediaBuilder::class;
493 1
        $response = $this->respondWithMedia($Media, 'original', $filePath);
494
495 1
        $response = $response->withHeader('Content-Disposition', 'attachment; filename="'.($filename ? $filename : $filePath).'"');
496
497 1
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response returns the type Psr\Http\Message\MessageInterface which includes types incompatible with the type-hinted return Psr\Http\Message\ResponseInterface.
Loading history...
498
    }
499
500
    public function handleCaptionRequest($media_id): ResponseInterface
501
    {
502
        // require authentication
503
        $GLOBALS['Session']->requireAccountLevel('Staff');
504
505
        if (empty($media_id) || !is_numeric($media_id)) {
506
            return $this->throwNotFoundError();
507
        }
508
509
        // get media
510
        try {
511
            $Media = Media::getById($media_id);
512
        } catch (Exception $e) {
513
            return $this->throwUnauthorizedError();
514
        }
515
516
517
        if (!$Media) {
518
            $this->throwNotFoundError();
519
        }
520
521
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
522
            $Media->Caption = $_REQUEST['Caption'];
523
            $Media->save();
524
525
            return $this->respond('mediaCaptioned', [
526
                'success' => true
527
                ,'data' => $Media,
528
            ]);
529
        }
530
531
        return $this->respond('mediaCaption', [
532
            'data' => $Media,
533
        ]);
534
    }
535
536
    public function handleDeleteRequest(ActiveRecord $Record): ResponseInterface
537
    {
538
        // require authentication
539
        $GLOBALS['Session']->requireAccountLevel('Staff');
540
541
        if ($mediaID = $this->peekPath()) {
542
            $mediaIDs = [$mediaID];
543
        } elseif (!empty($_REQUEST['mediaID'])) {
544
            $mediaIDs = [$_REQUEST['mediaID']];
545
        } elseif (is_array($_REQUEST['media'])) {
546
            $mediaIDs = $_REQUEST['media'];
547
        }
548
549
        $deleted = [];
550
        foreach ($mediaIDs as $mediaID) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mediaIDs does not seem to be defined for all execution paths leading up to this point.
Loading history...
551
            if (!is_numeric($mediaID)) {
552
                continue;
553
            }
554
555
            // get media
556
            $Media = Media::getByID($mediaID);
557
558
            if (!$Media) {
559
                return $this->throwNotFoundError();
560
            }
561
562
            if ($Media->destroy()) {
563
                $deleted[] = $Media;
564
            }
565
        }
566
567
        return $this->respond('mediaDeleted', [
568
            'success' => true
569
            ,'data' => $deleted,
570
        ]);
571
    }
572
573 3
    public function handleThumbnailRequest(Media $Media = null): ResponseInterface
574
    {
575
        // get media
576 3
        if (!$Media) {
577 3
            if (!$mediaID = $this->shiftPath()) {
578
                return $this->throwNotFoundError();
579 3
            } elseif (!$Media = Media::getByID($mediaID)) {
580
                return $this->throwNotFoundError();
581
            }
582
        }
583
584 3
        $_server = $this->request->getServerParams();
585
586
        // thumbnails are immutable for a given URL, so no need to actually check anything if the browser wants to revalidate its cache
587 3
        if (!empty($_server['HTTP_IF_NONE_MATCH']) || !empty($_server['HTTP_IF_MODIFIED_SINCE'])) {
588
            $this->responseBuilder = EmptyBuilder::class;
589
            $response = $this->respondEmpty($Media->ID);
590
            $response->withDefaults(304);
591
592
            return $response;
593
        }
594
595
        // get format
596 3
        if (preg_match('/^(\d+)x(\d+)(x([0-9A-F]{6})?)?$/i', $this->peekPath(), $matches)) {
0 ignored issues
show
Bug introduced by
It seems like $this->peekPath() can also be of type false; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

596
        if (preg_match('/^(\d+)x(\d+)(x([0-9A-F]{6})?)?$/i', /** @scrutinizer ignore-type */ $this->peekPath(), $matches)) {
Loading history...
597 2
            $this->shiftPath();
598 2
            $maxWidth = $matches[1];
599 2
            $maxHeight = $matches[2];
600 2
            $fillColor = !empty($matches[4]) ? $matches[4] : false;
601
        } else {
602 1
            $maxWidth = $this->defaultThumbnailWidth;
603 1
            $maxHeight = $this->defaultThumbnailHeight;
604 1
            $fillColor = false;
605
        }
606
607 3
        if ($this->peekPath() == 'cropped') {
608
            $this->shiftPath();
609
            $cropped = true;
610
        } else {
611 3
            $cropped = false;
612
        }
613
614
        // get thumbnail media
615
        try {
616 3
            $thumbPath = $Media->getThumbnail($maxWidth, $maxHeight, $fillColor, $cropped);
617
618 3
            $this->responseBuilder = MediaBuilder::class;
619 3
            $response = $this->respondWithThumbnail($Media, "$maxWidth-$maxHeight-$fillColor-$cropped", $thumbPath);
620 3
            return $response;
621
        } catch (Exception $e) {
622
            return $this->throwNotFoundError();
623
        }
624
    }
625
626
627 1
    public function handleBrowseRequest($options = [], $conditions = [], $responseID = null, $responseData = []): ResponseInterface
628
    {
629
        // apply tag filter
630 1
        if (!empty($_REQUEST['tag'])) {
631
            // get tag
632
            if (!$Tag = Tag::getByHandle($_REQUEST['tag'])) {
0 ignored issues
show
Bug introduced by
The type Divergence\Controllers\Tag was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
633
                return $this->throwNotFoundError();
634
            }
635
636
            $conditions[] = 'ID IN (SELECT ContextID FROM tag_items WHERE TagID = '.$Tag->ID.' AND ContextClass = "Product")';
637
        }
638
639
640
        // apply context filter
641 1
        if (!empty($_REQUEST['ContextClass'])) {
642
            $conditions['ContextClass'] = $_REQUEST['ContextClass'];
643
        }
644
645 1
        if (!empty($_REQUEST['ContextID']) && is_numeric($_REQUEST['ContextID'])) {
646
            $conditions['ContextID'] = $_REQUEST['ContextID'];
647
        }
648
649 1
        return parent::handleBrowseRequest($options, $conditions, $responseID, $responseData);
650
    }
651
652
653
654
    public function handleMediaDeleteRequest(): ResponseInterface
655
    {
656
        // sanity check
657
        if (empty($_REQUEST['media']) || !is_array($_REQUEST['media'])) {
658
            return $this->throwNotFoundError();
659
        }
660
661
        // retrieve photos
662
        $media_array = [];
663
        foreach ($_REQUEST['media'] as $media_id) {
664
            if (!is_numeric($media_id)) {
665
                return $this->throwNotFoundError();
666
            }
667
668
            if ($Media = Media::getById($media_id)) {
669
                $media_array[$Media->ID] = $Media;
670
671
                if (!$this->checkWriteAccess($Media)) {
672
                    return $this->throwUnauthorizedError();
673
                }
674
            }
675
        }
676
677
        // delete
678
        $deleted = [];
679
        foreach ($media_array as $media_id => $Media) {
680
            if ($Media->delete()) {
681
                $deleted[] = $media_id;
682
            }
683
        }
684
685
        return $this->respond('mediaDeleted', [
686
            'success' => true
687
            ,'deleted' => $deleted,
688
        ]);
689
    }
690
691 7
    public function checkUploadAccess()
692
    {
693 7
        return true;
694
    }
695
696 5
    public function throwUploadError($error): ResponseInterface
697
    {
698 5
        return $this->respond('error', [
699 5
            'success' => false,
700 5
            'failed' => [
701 5
                'errors'	=>	$error,
702 5
            ],
703 5
        ]);
704
    }
705
}
706