Passed
Push — main ( f3cfb1...17781b )
by Emil
04:34
created

UploadManager   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 29
dl 0
loc 87
rs 10
c 1
b 1
f 0
ccs 27
cts 27
cp 1
wmc 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A saveUploadedFile() 0 27 5
A deleteUploadedFile() 0 13 2
A __construct() 0 13 3
1
<?php
2
3
namespace App;
4
5
use Symfony\Component\HttpFoundation\File\UploadedFile;
6
7
class UploadManager
8
{
9
    private string $projectDir;
10
    private string $targetDirectory;
11
    private string $targetDirectoryPath;
12
13
    /**
14
     * __construct.
15
     *
16
     * @return void
17
     */
18 7
    public function __construct(string $projectDir, string $targetDirectory = '/uploads')
19
    {
20 7
        $this->projectDir = $projectDir;
21 7
        $this->targetDirectory = ltrim($targetDirectory, '/');
22 7
        $this->targetDirectoryPath = rtrim($this->projectDir.'/public/'.$this->targetDirectory, '/');
23
24
        // Make sure the directory exists
25 7
        if (!is_dir($this->targetDirectoryPath)) {
26 6
            mkdir($this->targetDirectoryPath, 0777, true);
27
        }
28
        // Check write permissions
29 7
        if (!is_writable($this->targetDirectoryPath)) {
30 1
            throw new \RuntimeException($this->targetDirectory.' directory is not writable.');
31
        }
32
    }
33
34
    /**
35
     * saveUploadedFile.
36
     *
37
     * Saves the uploaded file to the /public/uploads folder and returns the path
38
     *
39
     * @param array<string> $fileTypesSupported
40
     *
41
     * @return string|null string containing filePath if successful null if failed
42
     */
43 4
    public function saveUploadedFile(?UploadedFile $file, array $fileTypesSupported): ?string
44
    {
45 4
        $filePath = null;
46
47 4
        if ($file instanceof UploadedFile && $file->isValid()) {
48
            // Check if file is of allowed type
49 3
            $fileType = $file->getMimeType();
50 3
            if (!in_array($fileType, $fileTypesSupported)) {
51 1
                throw new \RuntimeException('Invalid file type. Filetype of '.$fileType.' is not allowed.');
52
            }
53
54
            /** @var string $originalFilename */
55 2
            $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
56 2
            $safeFilename = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
57 2
            $newFilename = $safeFilename.'-'.uniqid().'.'.$file->guessExtension();
58
59
            // Move the file to the directory
60
            try {
61 2
                $file->move($this->targetDirectoryPath, $newFilename);
62
                // Save $newFilename and path to database
63 1
                $filePath = '/'.$this->targetDirectory.'/'.$newFilename;
64 1
            } catch (\Exception $e) {
65 1
                throw new \RuntimeException('Error uploading file: '.$e->getMessage());
66
            }
67
        }
68
69 2
        return $filePath;
70
    }
71
72
    /**
73
     * deleteUploadedFile.
74
     *
75
     * Deletes the file at the given path within the target directory.
76
     *
77
     * @param string $filePath The relative path to the image, e.g., '/uploads/filename.jpg'
78
     *
79
     * @return bool True if deletion was successful, false otherwise
80
     */
81 1
    public function deleteUploadedFile(string $filePath): bool
82
    {
83
        // Full path to the file
84 1
        $fullPath = $this->projectDir.'/public'.$filePath;
85
86
        // Check if file exists
87 1
        if (!file_exists($fullPath)) {
88
            // File does not exist
89 1
            return false;
90
        }
91
92
        // Attempt to delete the file
93 1
        return unlink($fullPath);
94
    }
95
}
96