Passed
Branch master (eb004c)
by Adrian Florin
02:26
created

File::resetErrorHandler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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 41
    public function __construct(string $filenameWithPath)
74
    {
75 41
        $pathHelper = new PathHelper();
76 41
        $this->filenameWithPath = $pathHelper->normalizePathSeparator($filenameWithPath);
77 41
        $filename = $pathHelper->extractFilenameFromPath($this->filenameWithPath);
78 41
        if (empty($filename) || false === $this->validatePath($this->filenameWithPath)) {
79 2
            throw new \RuntimeException(
80 2
                sprintf('Given path %s does not represents a file!', $filenameWithPath)
81
            );
82
        }
83 39
        list($this->name, $this->extension) = $pathHelper->splitFilename($filename);
84 39
        $this->hasExtension = (bool)$this->extension;
85 39
        $this->errorHandler = new ErrorToExceptionConverter();
86 39
    }
87
88
    /**
89
     * States whether the file actually exists on disk
90
     * @return bool
91
     */
92 40
    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 40
        return file_exists($this->filenameWithPath);
95
    }
96
97
    /**
98
     * States whether the file is readable
99
     * @return bool
100
     */
101 6
    public function isReadable(): bool
102
    {
103 6
        return is_readable($this->filenameWithPath);
104
    }
105
106
    /**
107
     * @return bool
108
     */
109 7
    public function isWritable(): bool
110
    {
111 7
        if ($this->exists()) {
112 6
            return is_writable($this->filenameWithPath);
113
        }
114 1
        $parts = explode(DIRECTORY_SEPARATOR, $this->filenameWithPath);
115 1
        array_pop($parts);
116 1
        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 3
    public function write(ContentInterface $content): File
127
    {
128 3
        if ($this->isWritable() === false) {
129 1
            throw new PermissionDeniedException("The current file is not writable!");
130
        }
131 2
        file_put_contents($this->filenameWithPath, $content->get());
132 2
        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 6
    public function getContent(): ContentInterface
142
    {
143 6
        if ($this->exists() === false) {
144 2
            throw new FileNotFoundException(sprintf("%s does not exists!", $this->filenameWithPath));
145
        }
146 4
        if ($this->isReadable() === false) {
147 1
            throw new PermissionDeniedException(
148 1
                sprintf("You do not have permissions to read file %s!", $this->filenameWithPath)
149
            );
150
        }
151 3
        $this->convertErrors();
152 3
        $stringContent = file_get_contents($this->filenameWithPath);
153 2
        $this->resetErrorHandler();
154 2
        if (false === $stringContent) {
155 1
            throw new IOException(
156 1
                sprintf("Could not retrieve content! Error message: %s", error_get_last()['message'])
157
            );
158
        }
159 1
        return $this->getContentFactory()
160 1
            ->create($this->extension, $stringContent);
161
    }
162
163
    /**
164
     * Deletes the current file
165
     * @return bool
166
     * @throws \NeedleProject\FileIo\Exception\IOException
167
     */
168 3
    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 3
        if ($this->exists() === false) {
171 2
            return false;
172
        }
173 1
        $this->convertErrors();
174 1
        $unlinkResult = unlink($this->filenameWithPath);
175 1
        $this->resetErrorHandler();
176 1
        return $unlinkResult;
177
    }
178
179
    /**
180
     * State existence of a file's extension
181
     * @return bool
182
     */
183 10
    public function hasExtension(): bool
184
    {
185 10
        return $this->hasExtension;
186
    }
187
188
    /**
189
     * Get file's extension
190
     * @return string
191
     */
192 4
    public function getExtension(): string
193
    {
194 4
        return $this->extension;
195
    }
196
197
    /**
198
     * Get file's name without extension
199
     * @return string
200
     */
201 4
    public function getName(): string
202
    {
203 4
        return $this->name;
204
    }
205
206
    /**
207
     * Get file's name with extension
208
     * @return string
209
     */
210 5
    public function getBasename(): string
211
    {
212 5
        if (false === $this->hasExtension()) {
213 1
            return $this->name;
214
        }
215 4
        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 1
    protected function getContentFactory(): ContentFactory
223
    {
224 1
        if (is_null($this->contentFactory)) {
225 1
            $this->contentFactory = new ContentFactory();
226
        }
227 1
        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 40
    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 40
        return !($this->exists() && is_dir($filenameWithPath));
238
    }
239
240
    /**
241
     * Convert errors to Exception type objects
242
     */
243 4
    protected function convertErrors()
244
    {
245 4
        $this->errorHandler->convertErrorsToExceptions(E_ALL, IOException::class);
246 4
    }
247
248
    /**
249
     * Undo error to exception conversion
250
     */
251 3
    protected function resetErrorHandler()
252
    {
253 3
        $this->errorHandler->restoreErrorHandler();
254 3
    }
255
}
256