Lines 54.23% 32 / 59
Methods 38.46% 5 / 13
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 70.00% 7 / 10 0.00% 0 / 1 4.43
 create 87.50% 7 / 8 0.00% 0 / 1 4.03
 exists 100.00% 1 / 1 100.00% 1 / 1 1
 setPermissions 0.00% 0 / 1 0.00% 0 / 1 2
 delete 66.66% 2 / 3 0.00% 0 / 1 2.15
 copy 47.05% 8 / 17 0.00% 0 / 1 8.71
 write 100.00% 1 / 1 100.00% 1 / 1 1
 getContents 66.66% 2 / 3 0.00% 0 / 1 2.15
 getExtension 100.00% 2 / 2 100.00% 1 / 1 2
 getMimeType 0.00% 0 / 3 0.00% 0 / 1 12
 [Lucent\Filesystem\FileSystemObject] getDirectory 100.00% 1 / 1 100.00% 1 / 1 1
 [Lucent\Filesystem\FileSystemObject] getName 100.00% 1 / 1 100.00% 1 / 1 1
 [Lucent\Filesystem\FileSystemObject] rename 0.00% 0 / 8 0.00% 0 / 1 12
16class File extends FileSystemObject
17{
18    /**
19     * Creates a new File instance
20     *
21     * @param string $path The path to the file (relative or absolute)
22     * @param mixed $content Optional content to write to the file
23     * @param bool $absolute Whether the provided path is absolute (true) or relative to root (false)
24     */
25    public function __construct(string $path, mixed $content = null, bool $absolute = false)
26    {
27        if (!$absolute) {
28            $path = FileSystem::resolvePath($path);
29        }
30
31        // Normalize the path so `..`/`.` segments are resolved before the
32        // containment guard runs.
33        $path = FileSystem::normalizePath($path);
34
35        // Containment guard: never allow a path to escape the configured root.
36        if (!FileSystem::isWithinRoot($path)) {
37            throw new \RuntimeException(
38                "File path '{$path}' escapes the configured root path '" . FileSystem::rootPath() . "'"
39            );
40        }
41
42        $this->path = $path;
43
44        if ($content !== null) {
45            $this->create($content);
46        }
47    }
48
49    /**
50     * Creates the file with the given content
51     *
52     * Creates parent directories if they don't exist
53     *
54     * @param mixed $params Content to write to the file
55     * @return bool True if successful, false otherwise
56     */
57    public function create(mixed $params = null): bool
58    {
59        if (!file_exists($this->path)) {
60            $directory = dirname($this->path);
61
62            // Create directory if it doesn't exist
63            if (!is_dir($directory)) {
64                mkdir($directory, 0755, true);
65            }
66
67            if ($params !== null) {
68                return $this->write($params);
69            } else {
70                return touch($this->path);
71            }
72
73        }
74
75        return true;
76    }
77
78    /**
79     * Checks if the file exists
80     *
81     * @return bool True if the file exists, false otherwise
82     */
83    public function exists(): bool
84    {
85        return file_exists($this->path);
86    }
87
88    public function setPermissions(int $permissions): bool
89    {
90        return chmod($this->path, $permissions);
91    }
92
93    /**
94     * Deletes the file
95     *
96     * @return bool True if successfully deleted, false otherwise
97     */
98    public function delete(): bool
99    {
100        if (!$this->exists())
101            return false;
102
103        return unlink($this->path);
104    }
105
106    /**
107     * Copies the file to a new location
108     *
109     * @param string $name The name for the copied file
110     * @param Folder $folder The destination folder
111     * @param bool $absolute Whether the path is absolute
112     * @return FileSystemObject|null The new file object if successful, null otherwise
113     */
114    public function copy(string $name, Folder $folder, bool $absolute = false): ?FileSystemObject
115    {
116        // Construct destination path
117        $destinationPath = $folder->path . DIRECTORY_SEPARATOR . $name;
118
119        // Check source file
120        if (!file_exists($this->path)) {
121            Log::channel("lucent.filesystem")->error("[File] Copy error, source file does not exist:\n  Path: {$this->path}");
122            return null;
123        }
124
125        // Check destination folder
126        if (!is_dir($folder->path)) {
127            Log::channel("lucent.filesystem")->error("[File] Copy error, destination folder does not exist:\n  Path: {$folder->path}");
128            return null;
129        }
130
131        // Check write permissions
132        if (!is_writable($folder->path)) {
133            Log::channel("lucent.filesystem")->error("[File] Write error, destination folder is not writeable:\n  Path: {$folder->path}");
134            return null;
135        }
136
137        // Create the new file object WITHOUT writing content - passing null
138        // avoids creating an empty destination file before the copy runs.
139        $copy = new File($destinationPath, null, true);
140
141        // Perform copy operation
142        $success = copy($this->path, $copy->path);
143
144        // Check for PHP errors during copy
145        if (!$success) {
146            $error = error_get_last()['message'] ?? 'Unknown error';
147            Log::channel("lucent.filesystem")->critical("[File] PHP Error during copy: {$error}\n  From: {$this->path}\n  To: {$copy->path}");
148            return null;
149        }
150
151        return $copy;
152    }
153
154    /**
155     * Writes content to the file
156     *
157     * @param mixed $content Content to write to the file
158     * @return bool True if successful, false otherwise
159     */
160    public function write(mixed $content = null): bool
161    {
162        return file_put_contents($this->path, $content) !== false;
163    }
164
165    /**
166     * Gets the contents of the file
167     *
168     * @return string The file contents (empty string if the file doesn't exist)
169     */
170    public function getContents(): string
171    {
172        if (!$this->exists()) {
173            return "";
174        }
175
176        return file_get_contents($this->path);
177    }
178
179    /**
180     * Gets the file extension
181     *
182     * @return string The file extension
183     */
184    public function getExtension(): string
185    {
186        $extension = pathinfo($this->path, PATHINFO_EXTENSION);
187        return $extension ? '.' . $extension : '';
188    }
189
190    /**
191     * Gets the file mime-type
192     *
193     * @return string The file mime-type
194     */
195    public function getMimeType(): string
196    {
197        if (!file_exists($this->path)) {
198            return 'application/octet-stream';
199        }
200
201        return mime_content_type($this->path) ?: 'application/octet-stream';
202    }
203}

Inherited from Lucent\Filesystem\FileSystemObject

26    public function getDirectory(): Folder
27    {
28        return new Folder(dirname($this->path), true);
29    }
36    public function getName(): string
37    {
38        return basename($this->path);
39    }
70    public function rename(string $newName): bool
71    {
72        // Get the directory path of the current object
73        $directory = $this->getDirectory()->path;
74
75        // Construct the new full path
76        $newPath = $directory . DIRECTORY_SEPARATOR . $newName;
77
78        // Check if the target already exists
79        if (file_exists($newPath)) {
80            throw new \RuntimeException("Cannot rename: target '{$newPath}' already exists");
81        }
82
83        // Perform the rename operation
84        if (rename($this->path, $newPath)) {
85            // Update the path property to reflect the new path
86            $this->path = $newPath;
87            return true;
88        }
89
90        return false;
91    }