Passed
Push — master ( 3764eb...eb004c )
by Adrian Florin
04:02
created

File::convertErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file is part of the NeedleProject\FileIo package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
namespace NeedleProject\FileIo;
9
10
use NeedleProject\FileIo\Content\ContentInterface;
11
use NeedleProject\FileIo\Exception\FileNotFoundException;
12
use NeedleProject\FileIo\Exception\IOException;
13
use NeedleProject\FileIo\Exception\PermissionDeniedException;
14
use NeedleProject\FileIo\Factory\ContentFactory;
15
use NeedleProject\FileIo\Helper\PathHelper;
16
use NeedleProject\Common\Util\ErrorToExceptionConverter;
17
18
/**
19
 * Class File
20
 *
21
 * @package NeedleProject\FileIo
22
 * @author Adrian Tilita <[email protected]>
23
 * @copyright 2017 Adrian Tilita
24
 * @license https://opensource.org/licenses/MIT MIT Licence
25
 */
26
class File
27
{
28
    /**
29
     * File extension separator
30
     * @const string
31
     */
32
    const EXTENSION_SEPARATOR = '.';
33
34
    /**
35
     * File's name including the path
36
     * @var null|string
37
     */
38
    private $filenameWithPath = null;
39
40
    /**
41
     * File's extension - For no extension a blank string will be used
42
     * @var null|string
43
     */
44
    private $extension = null;
45
46
    /**
47
     * File's name without extension
48
     * @var null|string
49
     */
50
    private $name = null;
51
52
    /**
53
     * Whether the file has an extension or if it is set by us
54
     * @var bool
55
     */
56
    private $hasExtension = false;
57
58
    /**
59
     * @var null|ContentFactory
60
     */
61
    private $contentFactory = null;
62
63
    /**
64
     * @var null|ErrorToExceptionConverter
65
     */
66
    private $errorHandler = null;
67
68
    /**
69
     * File constructor.
70
     *
71
     * @param string $filenameWithPath
72
     */
73
    public function __construct(string $filenameWithPath)
74
    {
75
        $pathHelper = new PathHelper();
76
        $this->filenameWithPath = $pathHelper->normalizePathSeparator($filenameWithPath);
77
        $filename = $pathHelper->extractFilenameFromPath($this->filenameWithPath);
78
        if (empty($filename) || false === $this->validatePath($this->filenameWithPath)) {
79
            throw new \RuntimeException(
80
                sprintf('Given path %s does not represents a file!', $filenameWithPath)
81
            );
82
        }
83
        list($this->name, $this->extension) = $pathHelper->splitFilename($filename);
84
        $this->hasExtension = (bool)$this->extension;
85
        $this->errorHandler = new ErrorToExceptionConverter();
86
    }
87
88
    /**
89
     * States whether the file actually exists on disk
90
     * @return bool
91
     */
92
    public function exists(): bool
0 ignored issues
show
Coding Style introduced by
function exists() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
93
    {
94
        return file_exists($this->filenameWithPath);
95
    }
96
97
    /**
98
     * States whether the file is readable
99
     * @return bool
100
     */
101
    public function isReadable(): bool
102
    {
103
        return is_readable($this->filenameWithPath);
104
    }
105
106
    /**
107
     * @return bool
108
     */
109
    public function isWritable(): bool
110
    {
111
        if ($this->exists()) {
112
            return is_writable($this->filenameWithPath);
113
        }
114
        $parts = explode(DIRECTORY_SEPARATOR, $this->filenameWithPath);
115
        array_pop($parts);
116
        return is_writable(implode(DIRECTORY_SEPARATOR, $parts));
117
    }
118
119
    /**
120
     * Write content to the current file
121
     *
122
     * @param \NeedleProject\FileIo\Content\ContentInterface $content
123
     * @return \NeedleProject\FileIo\File
124
     * @throws \NeedleProject\FileIo\Exception\PermissionDeniedException
125
     */
126
    public function write(ContentInterface $content): File
127
    {
128
        if ($this->isWritable() === false) {
129
            throw new PermissionDeniedException("The current file is not writable!");
130
        }
131
        file_put_contents($this->filenameWithPath, $content->get());
132
        return $this;
133
    }
134
135
    /**
136
     * @return \NeedleProject\FileIo\Content\ContentInterface
137
     * @throws \NeedleProject\FileIo\Exception\FileNotFoundException
138
     * @throws \NeedleProject\FileIo\Exception\IOException
139
     * @throws \NeedleProject\FileIo\Exception\PermissionDeniedException
140
     */
141
    public function getContent(): ContentInterface
142
    {
143
        if ($this->exists() === false) {
144
            throw new FileNotFoundException(sprintf("%s does not exists!", $this->filenameWithPath));
145
        }
146
        if ($this->isReadable() === false) {
147
            throw new PermissionDeniedException(
148
                sprintf("You do not have permissions to read file %s!", $this->filenameWithPath)
149
            );
150
        }
151
        $this->convertErrors();
152
        $stringContent = file_get_contents($this->filenameWithPath);
153
        $this->resetErrorHandler();
154
        if (false === $stringContent) {
155
            throw new IOException(
156
                sprintf("Could not retrieve content! Error message: %s", error_get_last()['message'])
157
            );
158
        }
159
        return $this->getContentFactory()
160
            ->create($this->extension, $stringContent);
161
    }
162
163
    /**
164
     * Deletes the current file
165
     * @return bool
166
     * @throws \NeedleProject\FileIo\Exception\IOException
167
     */
168
    public function delete(): bool
0 ignored issues
show
Coding Style introduced by
function delete() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
169
    {
170
        if ($this->exists() === false) {
171
            return false;
172
        }
173
        $this->convertErrors();
174
        $unlinkResult = unlink($this->filenameWithPath);
175
        $this->resetErrorHandler();
176
        return $unlinkResult;
177
    }
178
179
    /**
180
     * State existence of a file's extension
181
     * @return bool
182
     */
183
    public function hasExtension(): bool
184
    {
185
        return $this->hasExtension;
186
    }
187
188
    /**
189
     * Get file's extension
190
     * @return string
191
     */
192
    public function getExtension(): string
193
    {
194
        return $this->extension;
195
    }
196
197
    /**
198
     * Get file's name without extension
199
     * @return string
200
     */
201
    public function getName(): string
202
    {
203
        return $this->name;
204
    }
205
206
    /**
207
     * Get file's name with extension
208
     * @return string
209
     */
210
    public function getBasename(): string
211
    {
212
        if (false === $this->hasExtension()) {
213
            return $this->name;
214
        }
215
        return $this->name . static::EXTENSION_SEPARATOR . $this->extension;
216
    }
217
218
    /**
219
     * Returns a factory responsible for creating appropriate content
220
     * @return \NeedleProject\FileIo\Factory\ContentFactory
221
     */
222
    protected function getContentFactory(): ContentFactory
223
    {
224
        if (is_null($this->contentFactory)) {
225
            $this->contentFactory = new ContentFactory();
226
        }
227
        return $this->contentFactory;
228
    }
229
230
    /**
231
     * Validate if the given path is not a directory
232
     * @param string $filenameWithPath
233
     * @return bool
234
     */
235
    private function validatePath(string $filenameWithPath): bool
0 ignored issues
show
Coding Style introduced by
function validatePath() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
236
    {
237
        return !($this->exists() && is_dir($filenameWithPath));
238
    }
239
240
    /**
241
     * Convert errors to Exception type objects
242
     */
243
    protected function convertErrors()
244
    {
245
        $this->errorHandler->convertErrorsToExceptions(E_ALL, IOException::class);
246
    }
247
248
    /**
249
     * Undo error to exception conversion
250
     */
251
    protected function resetErrorHandler()
252
    {
253
        $this->errorHandler->restoreErrorHandler();
254
    }
255
}
256