-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Filesystem] introduced new Exception base classes #8908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
45111d2
353404f
e0faf7f
068ab9a
1d0fbdb
584e918
ee56fca
4747212
6470f43
fe2a038
1e8251b
b326363
92ed07b
855c8ba
f2a3400
5cffa94
ad7f2f5
9815341
3c115f8
9c43e07
ae8758f
971e685
a791908
bdf9666
8d61e71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Filesystem\Exception; | ||
|
||
/** | ||
* Exception class thrown when a file couldn't be found | ||
* | ||
* @author Christian Gärtner <christiangaertner.film@googlemail.com> | ||
*/ | ||
class FileNotFoundException extends IOException | ||
{ | ||
public function __construct($path, $message = null, $code = 0, \Exception $previous = null) | ||
{ | ||
if ($message === null) { | ||
$message = sprintf('File "%s" could not be found', $path); | ||
} | ||
|
||
$this->setPath($path); | ||
|
||
parent::__construct($message, $code, $previous); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,10 +15,29 @@ | |
* Exception class thrown when a filesystem operation failure happens | ||
* | ||
* @author Romain Neutron <imprec@gmail.com> | ||
* @author Christian Gärtner <christiangaertner.film@googlemail.com> | ||
* | ||
* @api | ||
*/ | ||
class IOException extends \RuntimeException implements ExceptionInterface | ||
class IOException extends \RuntimeException implements IOExceptionInterface | ||
{ | ||
|
||
private $path; | ||
|
||
/** | ||
* Set the path associated with this IOException | ||
* @param string $path The path | ||
*/ | ||
public function setPath($path) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dont think the path should be mutable. So instead pass it as constructor argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was suggested initially but it is a BC break There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not if is an optional parameter at the end. the path should not be optional, so its not optimal. but using a setter makes it optional as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could implement both... I mean adding this parameter to the constructor with a default of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove the setPath method because it's not part of the interface anyway; so can rarely be used and also makes no sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
{ | ||
$this->path = $path; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getPath() | ||
{ | ||
return $this->path; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Filesystem\Exception; | ||
|
||
/** | ||
* IOException interface for file and input/output stream releated exceptions thrown by the component. | ||
* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra line to be removed |
||
* @author Christian Gärtner <christiangaertner.film@googlemail.com> | ||
*/ | ||
interface IOExceptionInterface extends ExceptionInterface | ||
{ | ||
/** | ||
* Returns the associated path for the exception | ||
* | ||
* @return string The path. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing space between descr. and return |
||
*/ | ||
public function getPath(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
namespace Symfony\Component\Filesystem; | ||
|
||
use Symfony\Component\Filesystem\Exception\IOException; | ||
use Symfony\Component\Filesystem\Exception\FileNotFoundException; | ||
|
||
/** | ||
* Provides basic utility to manipulate the file system. | ||
|
@@ -31,12 +32,13 @@ class Filesystem | |
* @param string $targetFile The target filename | ||
* @param boolean $override Whether to override an existing file or not | ||
* | ||
* @throws IOException When copy fails | ||
* @throws FileNotFoundException When orginFile doesn't exist | ||
* @throws IOException When copy fails | ||
*/ | ||
public function copy($originFile, $targetFile, $override = false) | ||
{ | ||
if (stream_is_local($originFile) && !is_file($originFile)) { | ||
throw new IOException(sprintf('Failed to copy %s because file not exists', $originFile)); | ||
throw new FileNotFoundException($originFile, sprintf('Failed to copy %s because file does not exist', $originFile)); | ||
} | ||
|
||
$this->mkdir(dirname($targetFile)); | ||
|
@@ -57,7 +59,9 @@ public function copy($originFile, $targetFile, $override = false) | |
unset($source, $target); | ||
|
||
if (!is_file($targetFile)) { | ||
throw new IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile)); | ||
$e = new IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile)); | ||
$e->setPath($originFile); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -78,7 +82,9 @@ public function mkdir($dirs, $mode = 0777) | |
} | ||
|
||
if (true !== @mkdir($dir, $mode, true)) { | ||
throw new IOException(sprintf('Failed to create %s', $dir)); | ||
$e = new IOException(sprintf('Failed to create %s', $dir)); | ||
$e->setPath($dir); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -115,7 +121,9 @@ public function touch($files, $time = null, $atime = null) | |
foreach ($this->toIterator($files) as $file) { | ||
$touch = $time ? @touch($file, $time, $atime) : @touch($file); | ||
if (true !== $touch) { | ||
throw new IOException(sprintf('Failed to touch %s', $file)); | ||
$e = new IOException(sprintf('Failed to touch %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -140,17 +148,23 @@ public function remove($files) | |
$this->remove(new \FilesystemIterator($file)); | ||
|
||
if (true !== @rmdir($file)) { | ||
throw new IOException(sprintf('Failed to remove directory %s', $file)); | ||
$e = new IOException(sprintf('Failed to remove directory %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} else { | ||
// https://bugs.php.net/bug.php?id=52176 | ||
if (defined('PHP_WINDOWS_VERSION_MAJOR') && is_dir($file)) { | ||
if (true !== @rmdir($file)) { | ||
throw new IOException(sprintf('Failed to remove file %s', $file)); | ||
$e = new IOException(sprintf('Failed to remove file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} else { | ||
if (true !== @unlink($file)) { | ||
throw new IOException(sprintf('Failed to remove file %s', $file)); | ||
$e = new IOException(sprintf('Failed to remove file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -174,7 +188,9 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) | |
$this->chmod(new \FilesystemIterator($file), $mode, $umask, true); | ||
} | ||
if (true !== @chmod($file, $mode & ~$umask)) { | ||
throw new IOException(sprintf('Failed to chmod file %s', $file)); | ||
$e = new IOException(sprintf('Failed to chmod file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -196,11 +212,15 @@ public function chown($files, $user, $recursive = false) | |
} | ||
if (is_link($file) && function_exists('lchown')) { | ||
if (true !== @lchown($file, $user)) { | ||
throw new IOException(sprintf('Failed to chown file %s', $file)); | ||
$e = new IOException(sprintf('Failed to chown file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} else { | ||
if (true !== @chown($file, $user)) { | ||
throw new IOException(sprintf('Failed to chown file %s', $file)); | ||
$e = new IOException(sprintf('Failed to chown file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -223,11 +243,15 @@ public function chgrp($files, $group, $recursive = false) | |
} | ||
if (is_link($file) && function_exists('lchgrp')) { | ||
if (true !== @lchgrp($file, $group)) { | ||
throw new IOException(sprintf('Failed to chgrp file %s', $file)); | ||
$e = new IOException(sprintf('Failed to chgrp file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} else { | ||
if (true !== @chgrp($file, $group)) { | ||
throw new IOException(sprintf('Failed to chgrp file %s', $file)); | ||
$e = new IOException(sprintf('Failed to chgrp file %s', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -247,11 +271,15 @@ public function rename($origin, $target, $overwrite = false) | |
{ | ||
// we check that target does not exist | ||
if (!$overwrite && is_readable($target)) { | ||
throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target)); | ||
$e = new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target)); | ||
$e->setPath($target); | ||
throw $e; | ||
} | ||
|
||
if (true !== @rename($origin, $target)) { | ||
throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target)); | ||
$e = new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target)); | ||
$e->setPath($target); | ||
throw $e; | ||
} | ||
} | ||
|
||
|
@@ -288,10 +316,14 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false) | |
$report = error_get_last(); | ||
if (is_array($report)) { | ||
if (defined('PHP_WINDOWS_VERSION_MAJOR') && false !== strpos($report['message'], 'error code(1314)')) { | ||
throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?'); | ||
$e = new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe you should use sprintf There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sprintf for what? This is just a plain string with no variable insertion. In addition to that the I' ve only changed the exception throwing, not the constructing of it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ChristianGaertner is right, there is no need for a sprintf call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh ok, sorry 👶 |
||
$e->setPath(null); | ||
throw $e; | ||
} | ||
} | ||
throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir)); | ||
$e = new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir)); | ||
$e->setPath($targetDir); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -389,7 +421,9 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o | |
} elseif (is_dir($file)) { | ||
$this->mkdir($target); | ||
} else { | ||
throw new IOException(sprintf('Unable to guess "%s" file type.', $file)); | ||
$e = new IOException(sprintf('Unable to guess "%s" file type.', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} else { | ||
if (is_link($file)) { | ||
|
@@ -399,7 +433,9 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o | |
} elseif (is_file($file)) { | ||
$this->copy($file, $target, isset($options['override']) ? $options['override'] : false); | ||
} else { | ||
throw new IOException(sprintf('Unable to guess "%s" file type.', $file)); | ||
$e = new IOException(sprintf('Unable to guess "%s" file type.', $file)); | ||
$e->setPath($file); | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
@@ -427,20 +463,6 @@ public function isAbsolutePath($file) | |
return false; | ||
} | ||
|
||
/** | ||
* @param mixed $files | ||
* | ||
* @return \Traversable | ||
*/ | ||
private function toIterator($files) | ||
{ | ||
if (!$files instanceof \Traversable) { | ||
$files = new \ArrayObject(is_array($files) ? $files : array($files)); | ||
} | ||
|
||
return $files; | ||
} | ||
|
||
/** | ||
* Atomically dumps content into a file. | ||
* | ||
|
@@ -456,16 +478,34 @@ public function dumpFile($filename, $content, $mode = 0666) | |
if (!is_dir($dir)) { | ||
$this->mkdir($dir); | ||
} elseif (!is_writable($dir)) { | ||
throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir)); | ||
$e = new IOException(sprintf('Unable to write to the "%s" directory.', $dir)); | ||
$e->setPath($dir); | ||
throw $e; | ||
} | ||
|
||
$tmpFile = tempnam($dir, basename($filename)); | ||
|
||
if (false === @file_put_contents($tmpFile, $content)) { | ||
throw new IOException(sprintf('Failed to write file "%s".', $filename)); | ||
$e = new IOException(sprintf('Failed to write file "%s".', $filename)); | ||
$e->setPath($filename); | ||
throw $e; | ||
} | ||
|
||
$this->rename($tmpFile, $filename, true); | ||
$this->chmod($filename, $mode); | ||
} | ||
|
||
/** | ||
* @param mixed $files | ||
* | ||
* @return \Traversable | ||
*/ | ||
private function toIterator($files) | ||
{ | ||
if (!$files instanceof \Traversable) { | ||
$files = new \ArrayObject(is_array($files) ? $files : array($files)); | ||
} | ||
|
||
return $files; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Filesystem\Tests; | ||
|
||
use Symfony\Component\Filesystem\Exception\IOException; | ||
use Symfony\Component\Filesystem\Exception\FileNotFoundException; | ||
|
||
/** | ||
* Test class for Filesystem. | ||
*/ | ||
class ExceptionTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
public function testSetPath() | ||
{ | ||
$e = new IOException(); | ||
$e->setPath('/foo'); | ||
$reflection = new \ReflectionProperty($e, 'path'); | ||
$reflection->setAccessible(true); | ||
|
||
$this->assertEquals('/foo', $reflection->getValue($e), 'The path should get stored in the "path" property'); | ||
} | ||
|
||
public function testGetPath() | ||
{ | ||
$e = new IOException(); | ||
$e->setPath('/foo'); | ||
$this->assertEquals('/foo', $e->getPath(), 'The pass should be returned.'); | ||
} | ||
|
||
public function testGeneratedMessage() | ||
{ | ||
$e = new FileNotFoundException('/foo'); | ||
$this->assertEquals('/foo', $e->getPath()); | ||
$this->assertEquals('File "/foo" could not be found', $e->getMessage(), 'A message should be generated.'); | ||
} | ||
|
||
public function testCustomMessage() | ||
{ | ||
$e = new FileNotFoundException('/foo', 'bar'); | ||
$this->assertEquals('bar', $e->getMessage(), 'A custom message should be possible still.'); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect indenting, Symfony uses 4 spaces.
And
@api
get marked later.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Thanks for the notice.