Skip to content

Commit 9355c28

Browse files
committed
[Filesystem] Added few new behaviors:
- add a IOException and a main filesystem exception interface - whenever an action fails, an IOException is thrown - add access to the second and third arguments of touch() function - add a recursive option for chmod() - add a chown() method - add a chgrp() method - Switch the 'unlink' global function in Filesystem::symlink to Filesystem::remove. BC break: mkdir() function now throws exception in case of failure instead of returning Boolean value.
1 parent 22d3e3e commit 9355c28

File tree

5 files changed

+402
-61
lines changed

5 files changed

+402
-61
lines changed

Exception/ExceptionInterface.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Filesystem\Exception;
13+
14+
/**
15+
* Exception interface for all exceptions thrown by the component.
16+
*
17+
* @author Romain Neutron <[email protected]>
18+
*
19+
* @api
20+
*/
21+
interface ExceptionInterface
22+
{
23+
24+
}

Exception/IOException.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Filesystem\Exception;
13+
14+
/**
15+
* Exception class thrown when a filesystem operation failure happens
16+
*
17+
* @author Romain Neutron <[email protected]>
18+
*
19+
* @api
20+
*/
21+
class IOException extends \RuntimeException implements ExceptionInterface
22+
{
23+
24+
}

Filesystem.php

+114-27
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Filesystem
2828
* @param string $originFile The original filename
2929
* @param string $targetFile The target filename
3030
* @param array $override Whether to override an existing file or not
31+
*
32+
* @throws Exception\IOException When copy fails
3133
*/
3234
public function copy($originFile, $targetFile, $override = false)
3335
{
@@ -40,30 +42,31 @@ public function copy($originFile, $targetFile, $override = false)
4042
}
4143

4244
if ($doCopy) {
43-
copy($originFile, $targetFile);
45+
if (true !== @copy($originFile, $targetFile)) {
46+
throw new Exception\IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile));
47+
}
4448
}
4549
}
4650

4751
/**
4852
* Creates a directory recursively.
4953
*
5054
* @param string|array|\Traversable $dirs The directory path
51-
* @param int $mode The directory mode
55+
* @param integer $mode The directory mode
5256
*
53-
* @return Boolean true if the directory has been created, false otherwise
57+
* @throws Exception\IOException On any directory creation failure
5458
*/
5559
public function mkdir($dirs, $mode = 0777)
5660
{
57-
$ret = true;
5861
foreach ($this->toIterator($dirs) as $dir) {
5962
if (is_dir($dir)) {
6063
continue;
6164
}
6265

63-
$ret = @mkdir($dir, $mode, true) && $ret;
66+
if (true !== @mkdir($dir, $mode, true)) {
67+
throw new Exception\IOException(sprintf('Failed to create %s', $dir));
68+
}
6469
}
65-
66-
return $ret;
6770
}
6871

6972
/**
@@ -85,21 +88,33 @@ public function exists($files)
8588
}
8689

8790
/**
88-
* Creates empty files.
91+
* Sets access and modification time of file.
8992
*
9093
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
94+
* @param integer $time The touch time as a unix timestamp
95+
* @param integer $atime The access time as a unix timestamp
96+
*
97+
* @throws Exception\IOException When touch fails
9198
*/
92-
public function touch($files)
99+
public function touch($files, $time = null, $atime = null)
93100
{
101+
if (null === $time) {
102+
$time = time();
103+
}
104+
94105
foreach ($this->toIterator($files) as $file) {
95-
touch($file);
106+
if (true !== @touch($file, $time, $atime)) {
107+
throw new Exception\IOException(sprintf('Failed to touch %s', $file));
108+
}
96109
}
97110
}
98111

99112
/**
100113
* Removes files or directories.
101114
*
102115
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
116+
*
117+
* @throws Exception\IOException When removal fails
103118
*/
104119
public function remove($files)
105120
{
@@ -113,13 +128,19 @@ public function remove($files)
113128
if (is_dir($file) && !is_link($file)) {
114129
$this->remove(new \FilesystemIterator($file));
115130

116-
rmdir($file);
131+
if (true !== @rmdir($file)) {
132+
throw new Exception\IOException(sprintf('Failed to remove directory %s', $file));
133+
}
117134
} else {
118135
// https://bugs.php.net/bug.php?id=52176
119136
if (defined('PHP_WINDOWS_VERSION_MAJOR') && is_dir($file)) {
120-
rmdir($file);
137+
if (true !== @rmdir($file)) {
138+
throw new Exception\IOException(sprintf('Failed to remove file %s', $file));
139+
}
121140
} else {
122-
unlink($file);
141+
if (true !== @unlink($file)) {
142+
throw new Exception\IOException(sprintf('Failed to remove file %s', $file));
143+
}
123144
}
124145
}
125146
}
@@ -128,14 +149,76 @@ public function remove($files)
128149
/**
129150
* Change mode for an array of files or directories.
130151
*
131-
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
132-
* @param integer $mode The new mode (octal)
133-
* @param integer $umask The mode mask (octal)
152+
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
153+
* @param integer $mode The new mode (octal)
154+
* @param integer $umask The mode mask (octal)
155+
* @param Boolean $recursive Whether change the mod recursively or not
156+
*
157+
* @throws Exception\IOException When the change fail
134158
*/
135-
public function chmod($files, $mode, $umask = 0000)
159+
public function chmod($files, $mode, $umask = 0000, $recursive = false)
136160
{
137161
foreach ($this->toIterator($files) as $file) {
138-
@chmod($file, $mode & ~$umask);
162+
if ($recursive && is_dir($file) && !is_link($file)) {
163+
$this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
164+
}
165+
if (true !== @chmod($file, $mode & ~$umask)) {
166+
throw new Exception\IOException(sprintf('Failed to chmod file %s', $file));
167+
}
168+
}
169+
}
170+
171+
/**
172+
* Change the owner of an array of files or directories
173+
*
174+
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner
175+
* @param string $user The new owner user name
176+
* @param Boolean $recursive Whether change the owner recursively or not
177+
*
178+
* @throws Exception\IOException When the change fail
179+
*/
180+
public function chown($files, $user, $recursive = false)
181+
{
182+
foreach ($this->toIterator($files) as $file) {
183+
if ($recursive && is_dir($file) && !is_link($file)) {
184+
$this->chown(new \FilesystemIterator($file), $user, true);
185+
}
186+
if (is_link($file) && function_exists('lchown')) {
187+
if (true !== @lchown($file, $user)) {
188+
throw new Exception\IOException(sprintf('Failed to chown file %s', $file));
189+
}
190+
} else {
191+
if (true !== @chown($file, $user)) {
192+
throw new Exception\IOException(sprintf('Failed to chown file %s', $file));
193+
}
194+
}
195+
}
196+
}
197+
198+
/**
199+
* Change the group of an array of files or directories
200+
*
201+
* @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group
202+
* @param string $group The group name
203+
* @param Boolean $recursive Whether change the group recursively or not
204+
*
205+
* @throws Exception\IOException When the change fail
206+
*/
207+
public function chgrp($files, $group, $recursive = false)
208+
{
209+
foreach ($this->toIterator($files) as $file) {
210+
if ($recursive && is_dir($file) && !is_link($file)) {
211+
$this->chgrp(new \FilesystemIterator($file), $group, true);
212+
}
213+
if (is_link($file) && function_exists('lchgrp')) {
214+
if (true !== @lchgrp($file, $group)) {
215+
throw new Exception\IOException(sprintf('Failed to chgrp file %s', $file));
216+
}
217+
} else {
218+
if (true !== @chgrp($file, $group)) {
219+
throw new Exception\IOException(sprintf('Failed to chgrp file %s', $file));
220+
}
221+
}
139222
}
140223
}
141224

@@ -145,18 +228,18 @@ public function chmod($files, $mode, $umask = 0000)
145228
* @param string $origin The origin filename
146229
* @param string $target The new filename
147230
*
148-
* @throws \RuntimeException When target file already exists
149-
* @throws \RuntimeException When origin cannot be renamed
231+
* @throws Exception\IOException When target file already exists
232+
* @throws Exception\IOException When origin cannot be renamed
150233
*/
151234
public function rename($origin, $target)
152235
{
153236
// we check that target does not exist
154237
if (is_readable($target)) {
155-
throw new \RuntimeException(sprintf('Cannot rename because the target "%s" already exist.', $target));
238+
throw new Exception\IOException(sprintf('Cannot rename because the target "%s" already exist.', $target));
156239
}
157240

158-
if (false === @rename($origin, $target)) {
159-
throw new \RuntimeException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
241+
if (true !== @rename($origin, $target)) {
242+
throw new Exception\IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
160243
}
161244
}
162245

@@ -166,6 +249,8 @@ public function rename($origin, $target)
166249
* @param string $originDir The origin directory path
167250
* @param string $targetDir The symbolic link name
168251
* @param Boolean $copyOnWindows Whether to copy files if on Windows
252+
*
253+
* @throws Exception\IOException When symlink fails
169254
*/
170255
public function symlink($originDir, $targetDir, $copyOnWindows = false)
171256
{
@@ -180,14 +265,16 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false)
180265
$ok = false;
181266
if (is_link($targetDir)) {
182267
if (readlink($targetDir) != $originDir) {
183-
unlink($targetDir);
268+
$this->remove($targetDir);
184269
} else {
185270
$ok = true;
186271
}
187272
}
188273

189274
if (!$ok) {
190-
symlink($originDir, $targetDir);
275+
if (true !== @symlink($originDir, $targetDir)) {
276+
throw new Exception\IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir));
277+
}
191278
}
192279
}
193280

@@ -235,7 +322,7 @@ public function makePathRelative($endPath, $startPath)
235322
* - $options['override'] Whether to override an existing file on copy or not (see copy())
236323
* - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
237324
*
238-
* @throws \RuntimeException When file type is unknown
325+
* @throws Exception\IOException When file type is unknown
239326
*/
240327
public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
241328
{
@@ -262,7 +349,7 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o
262349
} elseif (is_file($file) || ($copyOnWindows && is_link($file))) {
263350
$this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
264351
} else {
265-
throw new \RuntimeException(sprintf('Unable to guess "%s" file type.', $file));
352+
throw new Exception\IOException(sprintf('Unable to guess "%s" file type.', $file));
266353
}
267354
}
268355
}

README.md

+20-12
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,37 @@ Filesystem Component
33

44
Filesystem provides basic utility to manipulate the file system:
55

6-
use Symfony\Component\Filesystem\Filesystem;
6+
```php
7+
<?php
78

8-
$filesystem = new Filesystem();
9+
use Symfony\Component\Filesystem\Filesystem;
910

10-
$filesystem->copy($originFile, $targetFile, $override = false);
11+
$filesystem = new Filesystem();
1112

12-
$filesystem->mkdir($dirs, $mode = 0777);
13+
$filesystem->copy($originFile, $targetFile, $override = false);
1314

14-
$filesystem->touch($files);
15+
$filesystem->mkdir($dirs, $mode = 0777);
1516

16-
$filesystem->remove($files);
17+
$filesystem->touch($files, $time = null, $atime = null);
1718

18-
$filesystem->chmod($files, $mode, $umask = 0000);
19+
$filesystem->remove($files);
1920

20-
$filesystem->rename($origin, $target);
21+
$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);
2122

22-
$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);
23+
$filesystem->chown($files, $user, $recursive = false);
2324

24-
$filesystem->makePathRelative($endPath, $startPath);
25+
$filesystem->chgrp($files, $group, $recursive = false);
2526

26-
$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());
27+
$filesystem->rename($origin, $target);
2728

28-
$filesystem->isAbsolutePath($file);
29+
$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);
30+
31+
$filesystem->makePathRelative($endPath, $startPath);
32+
33+
$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());
34+
35+
$filesystem->isAbsolutePath($file);
36+
```
2937

3038
Resources
3139
---------

0 commit comments

Comments
 (0)