Completed
Pull Request — master (#75)
by Vladimir
02:42
created

File::getLastModified()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * @copyright 2018 Vladimir Jimenez
5
 * @license   https://github.com/stakx-io/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Filesystem;
9
10
use allejo\stakx\Service;
11
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
12
13
/**
14
 * A representation of a file on a given filesystem, virtual or physical.
15
 *
16
 * This class extends \SplFileInfo and adds new methods along with overriding some methods solely because I feel that
17
 * some of the naming can be misleading.
18
 *
19
 * @since 0.2.0
20
 */
21
final class File extends \SplFileInfo
22
{
23
    /** @var string The path relative to the site's working directory. */
24
    private $relativePath;
25
26
    /** @var string The original raw path given to the constructor. */
27
    private $rawPath;
28
29
    /**
30
     * File Constructor.
31
     *
32
     * @param string $filePath an absolute file path or a path relative to the current working directory
33
     *
34
     * @since 0.2.0
35
     *
36
     * @throws FileNotFoundException
37
     */
38 167
    public function __construct($filePath)
39
    {
40 167
        $this->rawPath = $filePath;
41 167
        $realPath = self::realpath($filePath);
42
43 167
        if ($realPath === false)
44
        {
45 3
            throw $this->buildNotFoundException();
46
        }
47
48 165
        parent::__construct($realPath);
49
50 165
        $this->relativePath = str_replace(Service::getWorkingDirectory() . DIRECTORY_SEPARATOR, '', $this->getAbsolutePath());
51
52 165
        $this->isSafeToRead();
53 165
    }
54
55
    /**
56
     * Get a new File object for another file relative to this file.
57
     *
58
     * @param string $path
59
     *
60
     * @return File
61
     */
62 11
    public function createFileForRelativePath($path)
63
    {
64 11
        return new File(Service::getWorkingDirectory() . DIRECTORY_SEPARATOR . $path);
65
    }
66
67
    /**
68
     * Whether or not this file exists on the filesystem.
69
     *
70
     * @return bool
71
     */
72 158
    public function exists()
73
    {
74 158
        return file_exists($this->getAbsolutePath());
75
    }
76
77
    /**
78
     * Get the name of the file without an extension.
79
     *
80
     * @param null $suffix this value will be discarded and is only needed to be able to override the \SplFileInfo
81
     *                     definition
82
     *
83
     * @since 0.2.0
84
     *
85
     * @return string
86
     */
87 97
    public function getBasename($suffix = null)
88
    {
89 97
        return parent::getBasename('.' . $this->getExtension());
90
    }
91
92
    /**
93
     * Get the name of the with the extension.
94
     *
95
     * @since 0.2.0
96
     *
97
     * @return string
98
     */
99 93
    public function getFilename()
100
    {
101 93
        return parent::getBasename();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getBasename() instead of getFilename()). Are you sure this is correct? If so, you might want to change this to $this->getBasename().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
102
    }
103
104
    /**
105
     * Get the absolute path to this file.
106
     *
107
     * @since 0.2.0
108
     *
109
     * @return string
110
     */
111 165
    public function getAbsolutePath()
112
    {
113 165
        return $this->getPathname();
114
    }
115
116
    /**
117
     * Get the path to the parent folder of this file.
118
     *
119
     * @since 0.2.0
120
     *
121
     * @return string
122
     */
123 1
    public function getParentFolder()
124
    {
125 1
        return $this->getPath();
126
    }
127
128
    /**
129
     * Get the file path to this file, relative to where it was created; likely the current working directory.
130
     *
131
     * @since 0.2.0
132
     *
133
     * @return string
134
     */
135 138
    public function getRelativeFilePath()
136
    {
137 138
        return $this->relativePath;
138
    }
139
140
    /**
141
     * Get the path to the parent folder this file, relative to where it was created; likely the current working directory.
142
     *
143
     * @since 0.2.0
144
     *
145
     * @return string
146
     */
147 2
    public function getRelativeParentFolder()
148
    {
149 2
        return dirname($this->getRelativeFilePath());
150
    }
151
152
    /**
153
     * Gets the last modified time.
154
     *
155
     * @return int The last modified time for the file, in a Unix timestamp
156
     */
157
    public function getLastModified()
158
    {
159
        return $this->getMTime();
160
    }
161
162
    /**
163
     * Get the contents of this file.
164
     *
165
     * @since 0.2.0
166
     *
167
     * @throws \RuntimeException when the file could not be read
168
     *
169
     * @return string
170
     */
171 157
    public function getContents()
172
    {
173 157
        if (!$this->exists())
174
        {
175 1
            throw $this->buildNotFoundException();
176
        }
177
178 157
        $content = file_get_contents($this->getAbsolutePath());
179
180 157
        if ($content === false)
181
        {
182
            $error = error_get_last();
183
            throw new \RuntimeException($error['message']);
184
        }
185
186 157
        return $content;
187
    }
188
189
    /**
190
     * Check if a file is safe to read.
191
     *
192
     * @throws FileNotFoundException
193
     */
194 165
    private function isSafeToRead()
195
    {
196 165
        if (self::isVFS($this->getAbsolutePath()))
197
        {
198 119
            return;
199
        }
200
201 51
        if (strpos($this->getAbsolutePath(), Service::getWorkingDirectory()) !== 0)
202
        {
203
            throw $this->buildNotFoundException();
204
        }
205 51
    }
206
207 4
    private function buildNotFoundException()
208
    {
209 4
        return new FileNotFoundException(
210 4
            sprintf('The given path "%s" does not exist or is outside the website working directory', $this->rawPath),
211 4
            0,
212 4
            null,
213 4
            $this->rawPath
214
        );
215
    }
216
217
    /**
218
     * A vfsStream friendly way of getting the realpath() of something.
219
     *
220
     * @param string $path
221
     *
222
     * @return string
223
     */
224 167
    public static function realpath($path)
225
    {
226 167
        return self::isVFS($path) ? $path : realpath($path);
227
    }
228
229
    /**
230
     * Check whether a given path is on the virtual filesystem.
231
     *
232
     * @param string $path
233
     *
234
     * @return bool
235
     */
236 167
    private static function isVFS($path)
237
    {
238 167
        return substr($path, 0, 6) == 'vfs://';
239
    }
240
}
241