Passed
Push — master ( d48c3e...c4ec56 )
by Vermeulen
40s
created

FileManager::createSymLink()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 45
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 26
nc 10
nop 3
dl 0
loc 45
ccs 25
cts 25
cp 1
crap 6
rs 8.8817
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace bultonFr\Utils\Files;
6
7
use Exception;
8
9
/**
10
 * Some methods to manage files and folders
11
 *
12
 * @author bulton-fr <[email protected]>
13
 */
14
class FileManager
15
{
16
    /**
17
     * Exception code when the constructor's first parameter is not null and
18
     * is not an instance of \Psr\Log\LoggerInterface
19
     */
20
    const EXCEP_NOT_LOGGER_INTERFACE = 202001;
21
22
    /**
23
     * Exception code when a file already exist
24
     *
25
     * @const EXCEP_FILE_EXIST
26
     */
27
    const EXCEP_FILE_EXIST = 202002;
28
29
    /**
30
     * Exception code when a file not exist
31
     *
32
     * @const EXCEP_FILE_NOT_EXIST
33
     */
34
    const EXCEP_FILE_NOT_EXIST = 202003;
35
36
    /**
37
     * Exception code when the symlink target not exist
38
     *
39
     * @const EXCEP_LINK_TARGET_NOT_FOUND
40
     */
41
    const EXCEP_LINK_TARGET_NOT_FOUND = 202004;
42
43
    /**
44
     * Exception code if the creating of the symlink failed
45
     *
46
     * @const EXCEP_LINK_CREATION_FAILED
47
     */
48
    const EXCEP_LINK_CREATION_FAILED = 202005;
49
50
    /**
51
     * Exception code when the deleting of the symlink failed
52
     *
53
     * @const EXCEP_LINK_REMOVE_FAILED
54
     */
55
    const EXCEP_LINK_REMOVE_FAILED = 202006;
56
57
    /**
58
     * Exception code when a directory already exist
59
     *
60
     * @const EXCEP_DIRECTORY_EXIST
61
     */
62
    const EXCEP_DIRECTORY_EXIST = 202007;
63
64
    /**
65
     * Exception code when the directory creation failed
66
     *
67
     * @const EXCEP_DIRECTORY_CREATION_FAILED
68
     */
69
    const EXCEP_DIRECTORY_CREATION_FAILED = 202008;
70
71
    /**
72
     * Exception code when the file to copy not exist
73
     *
74
     * @const EXCEP_COPY_SOURCE_NOT_FOUND
75
     */
76
    const EXCEP_COPY_SOURCE_NOT_FOUND = 202009;
77
78
    /**
79
     * Exception code when a copy failed
80
     *
81
     * @const EXCEP_COPY_FAILED
82
     */
83
    const EXCEP_COPY_FAILED = 202010;
84
85
    /**
86
     * Exception code when a directory deletion failed
87
     *
88
     * @const EXCEP_DIRECTORY_REMOVE_FAIL
89
     */
90
    const EXCEP_DIRECTORY_REMOVE_FAIL = 202011;
91
92
    /**
93
     * The Logger instance where all debug message will be sent
94
     *
95
     * @var \Psr\Log\LoggerInterface|null
96
     */
97
    protected $logger;
98
99
    /**
100
     * The Logger level to use to send messages
101
     *
102
     * @var string
103
     */
104
    protected $loggerMsgType = '';
105
106
    /**
107
     * Constructor
108
     *
109
     * @param \Psr\Log\LoggerInterface|null $logger The Logger instance
110
     * where all debug message will be sent
111
     * @param string $loggerMsgType (default 'debug') The Logger level to use
112
     * to send messages
113
     */
114
    public function __construct($logger = null, string $loggerMsgType = 'debug')
115
    {
116 1
        if ($logger !== null && $logger instanceof \Psr\Log\LoggerInterface === false) {
117 1
            throw new Exception(
118 1
                'The constructor first parameter must be an instance of \Psr\Log\LoggerInterface.',
119 1
                static::EXCEP_NOT_LOGGER_INTERFACE
120
            );
121
        }
122
123 1
        $this->logger        = $logger;
124 1
        $this->loggerMsgType = $loggerMsgType;
125 1
    }
126
127
    /**
128
     * Get the value of logger
129
     *
130
     * @return \Psr\Log\LoggerInterface|null
131
     */
132
    public function getLogger()
133
    {
134 1
        return $this->logger;
135
    }
136
137
    /**
138
     * Get the value of loggerMsgType
139
     *
140
     * @return string
141
     */
142
    public function getLoggerMsgType(): string
143
    {
144 1
        return $this->loggerMsgType;
145
    }
146
147
    /**
148
     * Send a message to logger
149
     *
150
     * @param array ...$args Arguments passed to Logger function
151
     * @return void
152
     */
153
    protected function sendMsgInLogger(...$args)
154
    {
155 1
        if ($this->logger === null) {
156 1
            return;
157
        }
158
159 1
        $msgType = $this->loggerMsgType;
160 1
        $this->logger->{$msgType}(...$args);
161 1
    }
162
    
163
    /**
164
     * Create a symlink
165
     *
166
     * @param string $linkTarget The symlink target path
167
     * @param string $linkFile The symlink file path
168
     * @param bool $tryRelative (default true) If system try to resolv paths
169
     *  to use a relative path for target.
170
     *
171
     * @return void
172
     */
173
    public function createSymLink(
174
        string $linkTarget,
175
        string $linkFile,
176
        bool $tryRelative = true
177
    ) {
178 1
        $this->sendMsgInLogger(
179 1
            'FileManager - Create symlink',
180
            [
181 1
                'linkTarget' => $linkTarget,
182 1
                'linkFile'   => $linkFile
183
            ]
184
        );
185
        
186 1
        if (file_exists($linkFile)) {
187 1
            throw new Exception(
188 1
                'link file '.$linkFile.' already exist.',
189 1
                static::EXCEP_FILE_EXIST
190
            );
191
        }
192
        
193 1
        if (file_exists($linkTarget) === false) {
194 1
            throw new Exception(
195 1
                'link target '.$linkTarget.' not found.',
196 1
                static::EXCEP_LINK_TARGET_NOT_FOUND
197
            );
198
        }
199
200 1
        $usedTarget = $linkTarget;
201 1
        if ($tryRelative === true) {
202
            try {
203 1
                $usedTarget = Paths::absoluteToRelative($linkTarget, $linkFile);
204 1
                $this->sendMsgInLogger(
205 1
                    'FileManager - Create symlink - Use relative path',
206 1
                    ['target' => $usedTarget]
207
                );
208 1
            } catch (Exception $e) {
209 1
                $usedTarget = $linkTarget;
210
            }
211
        }
212
        
213 1
        $status = symlink($usedTarget, $linkFile);
214 1
        if ($status === false) {
215 1
            throw new Exception(
216 1
                'link create failed for '.$linkFile.' -> '.$usedTarget,
217 1
                static::EXCEP_LINK_CREATION_FAILED
218
            );
219
        }
220 1
    }
221
    
222
    /**
223
     * Remove a symlink
224
     *
225
     * @param string $linkFile The symlink file path
226
     *
227
     * @return void
228
     */
229
    public function removeSymLink(string $linkFile)
230
    {
231 1
        $this->sendMsgInLogger(
232 1
            'FileManager - Remove symlink',
233 1
            ['linkFile' => $linkFile]
234
        );
235
        
236 1
        if (file_exists($linkFile) === false) {
237 1
            throw new Exception(
238 1
                'link file '.$linkFile.' not found.',
239 1
                static::EXCEP_FILE_NOT_EXIST
240
            );
241
        }
242
        
243 1
        $status = unlink($linkFile);
244 1
        if ($status === false) {
245 1
            throw new Exception(
246 1
                'link remove failed for '.$linkFile,
247 1
                static::EXCEP_LINK_REMOVE_FAILED
248
            );
249
        }
250 1
    }
251
    
252
    /**
253
     * Create a new directory
254
     *
255
     * @param string $dirPath The directory path
256
     *
257
     * @return void
258
     */
259
    public function createDirectory(string $dirPath)
260
    {
261 1
        $this->sendMsgInLogger(
262 1
            'FileManager - Create directory',
263 1
            ['path' => $dirPath]
264
        );
265
        
266 1
        if (file_exists($dirPath) === true) {
267 1
            throw new Exception(
268 1
                'Directory '.$dirPath.' already exist.',
269 1
                static::EXCEP_DIRECTORY_EXIST
270
            );
271
        }
272
        
273 1
        $status = mkdir($dirPath, 0755);
274 1
        if ($status === false) {
275 1
            throw new Exception(
276 1
                'Directory '.$dirPath.' creation failed.',
277 1
                static::EXCEP_DIRECTORY_CREATION_FAILED
278
            );
279
        }
280 1
    }
281
    
282
    /**
283
     * Copy a file
284
     *
285
     * @param string $source The source file path
286
     * @param string $target The destination file path
287
     *
288
     * @return void
289
     */
290
    public function copyFile(string $source, string $target)
291
    {
292 1
        $this->sendMsgInLogger(
293 1
            'FileManager - Copy file',
294
            [
295 1
                'source' => $source,
296 1
                'target' => $target
297
            ]
298
        );
299
        
300 1
        if (file_exists($target)) {
301 1
            throw new Exception(
302 1
                'target file '.$target.' already exist.',
303 1
                static::EXCEP_FILE_EXIST
304
            );
305
        }
306
        
307 1
        if (file_exists($source) === false) {
308 1
            throw new Exception(
309 1
                'copy source '.$source.' not found.',
310 1
                static::EXCEP_COPY_SOURCE_NOT_FOUND
311
            );
312
        }
313
        
314 1
        $status = copy($source, $target);
315 1
        if ($status === false) {
316 1
            throw new Exception(
317 1
                'copy failed for '.$source.' -> '.$target,
318 1
                static::EXCEP_COPY_FAILED
319
            );
320
        }
321 1
    }
322
    
323
    /**
324
     * Remove folders recursively
325
     *
326
     * @see http://php.net/manual/fr/function.rmdir.php#110489
327
     *
328
     * @param string $dirPath Path to directory to remove
329
     *
330
     * @return boolean
331
     */
332
    public function removeRecursiveDirectory(string $dirPath)
333
    {
334 1
        $this->sendMsgInLogger(
335 1
            'FileManager - Remove files and directories',
336 1
            ['path' => $dirPath]
337
        );
338
        
339 1
        $itemList = array_diff(scandir($dirPath), ['.', '..']);
0 ignored issues
show
Bug introduced by
It seems like scandir($dirPath) can also be of type false; however, parameter $array1 of array_diff() does only seem to accept array, 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

339
        $itemList = array_diff(/** @scrutinizer ignore-type */ scandir($dirPath), ['.', '..']);
Loading history...
340
        
341 1
        foreach ($itemList as $itemName) {
342 1
            $itemPath = $dirPath.'/'.$itemName;
343
            
344 1
            if (is_dir($itemPath)) {
345 1
                $this->removeRecursiveDirectory($itemPath);
346
            } else {
347 1
                unlink($itemPath);
348
            }
349
        }
350
        
351 1
        $rmDirStatus = rmdir($dirPath);
352 1
        if ($rmDirStatus === false) {
353 1
            throw new Exception(
354 1
                'Directory deletion has failed for '.$dirPath,
355 1
                static::EXCEP_DIRECTORY_REMOVE_FAIL
356
            );
357
        }
358 1
    }
359
}
360