Test Failed
Push — master ( ca159c...8f4401 )
by Sebastian
03:00
created

AbstractPathInfo::isFolder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * File containing the class {@see \AppUtils\FileHelper\AbstractPathInfo}.
4
 *
5
 * @package Application Utils
6
 * @subpackage FileHelper
7
 * @see \AppUtils\FileHelper\AbstractPathInfo
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils\FileHelper;
13
14
use AppUtils\FileHelper;
15
use AppUtils\FileHelper_Exception;
16
use AppUtils\Interface_Stringable;
17
use AppUtils\Interfaces\RenderableInterface;
18
use DateTime;
19
use DirectoryIterator;
20
use SplFileInfo;
21
22
/**
23
 * Abstract implementation of the path info interface.
24
 *
25
 * @package Application Utils
26
 * @subpackage FileHelper
27
 * @author Sebastian Mordziol <[email protected]>
28
 */
29
abstract class AbstractPathInfo implements PathInfoInterface, Interface_Stringable
30
{
31
    protected string $path;
32
33
    /**
34
     * @var array<string,mixed>
35
     */
36
    private array $runtimeProperties = array();
37
38
    public function __construct(string $path)
39
    {
40
        $this->path = FileHelper::normalizePath($path);
41
    }
42
43
    /**
44
     * @return string
45
     */
46
    public function getPath() : string
47
    {
48
        return $this->path;
49
    }
50
51
    /**
52
     * Gets the file name without path, e.g. "filename.txt",
53
     * or the folder name if it's a folder.
54
     *
55
     * @return string
56
     */
57
    public function getName() : string
58
    {
59
        return basename($this->path);
60
    }
61
62
    public function isFolder() : bool
63
    {
64
        return FolderInfo::is_dir($this->path);
65
    }
66
67
    public function isFile() : bool
68
    {
69
        return FileInfo::is_file($this->path);
70
    }
71
72
    public function exists() : bool
73
    {
74
        return file_exists($this->path);
75
    }
76
77
    public function isWritable() : bool
78
    {
79
        return is_writable($this->path);
80
    }
81
82
    public function isReadable() : bool
83
    {
84
        return is_readable($this->path);
85
    }
86
87
    /**
88
     * @return string
89
     *
90
     * @throws FileHelper_Exception
91
     * @see FileHelper::ERROR_REAL_PATH_NOT_FOUND
92
     */
93
    public function getRealPath() : string
94
    {
95
        $this->requireExists();
96
97
        $path = realpath($this->path);
98
99
        if($path !== false)
100
        {
101
            return FileHelper::normalizePath($path);
102
        }
103
104
        throw new FileHelper_Exception(
105
            sprintf('Real path for [%s] not found.', $this->getName()),
106
            sprintf('Tried accessing real path for [%s].', $this->getPath()),
107
            FileHelper::ERROR_REAL_PATH_NOT_FOUND
108
        );
109
    }
110
111
    /**
112
     * @param bool $condition
113
     * @param string $conditionLabel
114
     * @param int|null $errorCode
115
     * @return $this
116
     * @throws FileHelper_Exception
117
     */
118
    private function requireTrue(bool $condition, string $conditionLabel, ?int $errorCode=null) : self
119
    {
120
        if($condition === true)
121
        {
122
            return $this;
123
        }
124
125
        if($errorCode === null)
126
        {
127
            $errorCode = FileHelper::ERROR_FILE_DOES_NOT_EXIST;
128
        }
129
130
        throw new FileHelper_Exception(
131
            sprintf('Path [%s] %s.', $this->getName(), $conditionLabel),
132
            sprintf('Tried accessing the path [%s].', $this->getPath()),
133
            $errorCode
134
        );
135
    }
136
137
    /**
138
     * @param int|null $errorCode
139
     * @return $this
140
     * @throws FileHelper_Exception
141
     */
142
    public function requireExists(?int $errorCode=null) : self
143
    {
144
        return $this->requireTrue(
145
            !empty($this->path) && realpath($this->path) !== false,
146
            'does not exist',
147
            FileHelper::ERROR_FILE_DOES_NOT_EXIST
148
        );
149
    }
150
151
    /**
152
     * @param int|NULL $errorCode
153
     * @return $this
154
     * @throws FileHelper_Exception
155
     */
156
    public function requireReadable(?int $errorCode=null) : self
157
    {
158
        $this->requireExists($errorCode);
159
160
        return $this->requireTrue(
161
            $this->isReadable(),
162
            'is not readable',
163
            FileHelper::ERROR_FILE_NOT_READABLE
164
        );
165
    }
166
167
    /**
168
     * @param int|null $errorCode
169
     * @return $this
170
     * @throws FileHelper_Exception
171
     */
172
    public function requireWritable(?int $errorCode=null) : self
173
    {
174
        return $this->requireTrue(
175
            $this->isWritable(),
176
            'is not writable',
177
            FileHelper::ERROR_PATH_NOT_WRITABLE
178
        );
179
    }
180
181
    /**
182
     * @return FileInfo
183
     *
184
     * @throws FileHelper_Exception
185
     * @see FileHelper::ERROR_PATH_IS_NOT_A_FILE
186
     */
187
    public function requireIsFile() : FileInfo
188
    {
189
        if($this instanceof FileInfo)
190
        {
191
            return $this;
192
        }
193
194
        throw new FileHelper_Exception(
195
            'Target path is not a file',
196
            sprintf(
197
                'Path: [%s].',
198
                $this->path
199
            ),
200
            FileHelper::ERROR_PATH_IS_NOT_A_FILE
201
        );
202
    }
203
204
    /**
205
     * @return FolderInfo
206
     *
207
     * @throws FileHelper_Exception
208
     * @see FileHelper::ERROR_PATH_IS_NOT_A_FOLDER
209
     */
210
    public function requireIsFolder() : FolderInfo
211
    {
212
        if($this instanceof FolderInfo)
213
        {
214
            return $this;
215
        }
216
217
        throw new FileHelper_Exception(
218
            'Target path is not a folder',
219
            sprintf(
220
                'Path: [%s].',
221
                $this->path
222
            ),
223
            FileHelper::ERROR_PATH_IS_NOT_A_FOLDER
224
        );
225
    }
226
227
    /**
228
     * @param string|PathInfoInterface|SplFileInfo $path
229
     * @return string
230
     */
231
    public static function type2string($path) : string
232
    {
233
        if($path instanceof PathInfoInterface)
234
        {
235
            return $path->getPath();
236
        }
237
238
        if($path instanceof SplFileInfo)
239
        {
240
            return $path->getPathname();
241
        }
242
243
        return $path;
244
    }
245
246
    /**
247
     * Resolves the type of the target path: file or folder.
248
     *
249
     * NOTE: Requires the file or folder to exist in the
250
     * file system, and will throw an exception otherwise.
251
     *
252
     * @param string|PathInfoInterface|SplFileInfo $path
253
     * @return PathInfoInterface
254
     *
255
     * @throws FileHelper_Exception
256
     * @see FileHelper::ERROR_PATH_INVALID
257
     */
258
    public static function resolveType($path) : PathInfoInterface
259
    {
260
        if($path instanceof PathInfoInterface)
261
        {
262
            return $path;
263
        }
264
265
        $path = self::type2string($path);
266
267
        if(FolderInfo::is_dir($path))
268
        {
269
            return FolderInfo::factory($path);
270
        }
271
272
        if(FileInfo::is_file($path))
273
        {
274
            return FileInfo::factory($path);
275
        }
276
277
        throw new FileHelper_Exception(
278
            'Invalid file or folder path.',
279
            sprintf(
280
                'Target path: [%s].',
281
                $path
282
            ),
283
            FileHelper::ERROR_PATH_INVALID
284
        );
285
    }
286
287
    /**
288
     * Stores an arbitrary value in this object, which can
289
     * be retrieved again with {@see AbstractPathInfo::getRuntimeProperty()}.
290
     *
291
     * These properties have no functionality beyond offering
292
     * a way to store custom data.
293
     *
294
     * @param string $name
295
     * @param mixed $value
296
     * @return $this
297
     */
298
    public function setRuntimeProperty(string $name, $value) : self
299
    {
300
        $this->runtimeProperties[$name] = $value;
301
        return $this;
302
    }
303
304
    /**
305
     * Retrieves a previously set property, if any.
306
     *
307
     * @param string $name
308
     * @return mixed|null The stored value, or null if it does not exist (or has a null value).
309
     */
310
    public function getRuntimeProperty(string $name)
311
    {
312
        return $this->runtimeProperties[$name] ?? null;
313
    }
314
315
    public function __toString() : string
316
    {
317
        return $this->getPath();
318
    }
319
320
    /**
321
     * Retrieves the last modified date for the specified file or folder.
322
     *
323
     * Note: If the target does not exist, returns null.
324
     *
325
     * @return DateTime|NULL
326
     */
327
    public function getModifiedDate() : ?DateTime
328
    {
329
        $time = filemtime($this->getPath());
330
        if($time === false) {
331
            return null;
332
        }
333
334
        $date = new DateTime();
335
        $date->setTimestamp($time);
336
        return $date;
337
    }
338
}
339