Skip to content

[Filesystem] introduced new Exception base classes #9150

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

Merged
merged 2 commits into from
Sep 27, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@
*/
interface ExceptionInterface
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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 Fabien Potencier <fabien@symfony.com>
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
*/
class FileNotFoundException extends IOException
{
public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
{
if (null === $message) {
if (null === $path) {
$message = 'File could not be found.';
} else {
$message = sprintf('File "%s" could not be found.', $path);
}
}

parent::__construct($message, $code, $previous, $path);
}
}
19 changes: 18 additions & 1 deletion src/Symfony/Component/Filesystem/Exception/IOException.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,27 @@
* Exception class thrown when a filesystem operation failure happens
*
* @author Romain Neutron <imprec@gmail.com>
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class IOException extends \RuntimeException implements ExceptionInterface
class IOException extends \RuntimeException implements IOExceptionInterface
{
private $path;

public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
{
$this->path = $path;

parent::__construct($message, $code, $previous);
}

/**
* {@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.
*
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
*/
interface IOExceptionInterface extends ExceptionInterface
{
/**
* Returns the associated path for the exception
*
* @return string The path.
*/
public function getPath();
}
71 changes: 37 additions & 34 deletions src/Symfony/Component/Filesystem/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
}

$this->mkdir(dirname($targetFile));
Expand All @@ -57,7 +59,7 @@ 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));
throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
}
}
}
Expand All @@ -78,7 +80,7 @@ public function mkdir($dirs, $mode = 0777)
}

if (true !== @mkdir($dir, $mode, true)) {
throw new IOException(sprintf('Failed to create %s', $dir));
throw new IOException(sprintf('Failed to create "%s".', $dir), 0, null, $dir);
}
}
}
Expand Down Expand Up @@ -115,7 +117,7 @@ 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));
throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
}
}
}
Expand All @@ -140,17 +142,17 @@ public function remove($files)
$this->remove(new \FilesystemIterator($file));

if (true !== @rmdir($file)) {
throw new IOException(sprintf('Failed to remove directory %s', $file));
throw new IOException(sprintf('Failed to remove directory "%s".', $file), 0, null, $file);
}
} 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));
throw new IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
}
} else {
if (true !== @unlink($file)) {
throw new IOException(sprintf('Failed to remove file %s', $file));
throw new IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
}
}
}
Expand All @@ -174,7 +176,7 @@ 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));
throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
}
}
}
Expand All @@ -196,11 +198,11 @@ 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));
throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
}
} else {
if (true !== @chown($file, $user)) {
throw new IOException(sprintf('Failed to chown file %s', $file));
throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
}
}
}
Expand All @@ -223,11 +225,11 @@ 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));
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
}
} else {
if (true !== @chgrp($file, $group)) {
throw new IOException(sprintf('Failed to chgrp file %s', $file));
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
}
}
}
Expand All @@ -247,11 +249,11 @@ 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));
throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
}

if (true !== @rename($origin, $target)) {
throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
}
}

Expand Down Expand Up @@ -291,7 +293,8 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false)
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?');
}
}
throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir));

throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
}
}
}
Expand Down Expand Up @@ -389,7 +392,7 @@ 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));
throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
}
} else {
if (is_link($file)) {
Expand All @@ -399,7 +402,7 @@ 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));
throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
}
}
}
Expand Down Expand Up @@ -427,20 +430,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.
*
Expand All @@ -456,16 +445,30 @@ 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));
throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
}

$tmpFile = tempnam($dir, basename($filename));

if (false === @file_put_contents($tmpFile, $content)) {
throw new IOException(sprintf('Failed to write file "%s".', $filename));
throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
}

$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;
}
}
46 changes: 46 additions & 0 deletions src/Symfony/Component/Filesystem/Tests/ExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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 testGetPath()
{
$e = new IOException('', 0, null, '/foo');
$this->assertEquals('/foo', $e->getPath(), 'The pass should be returned.');
}

public function testGeneratedMessage()
{
$e = new FileNotFoundException(null, 0, null, '/foo');
$this->assertEquals('/foo', $e->getPath());
$this->assertEquals('File "/foo" could not be found.', $e->getMessage(), 'A message should be generated.');
}

public function testGeneratedMessageWithoutPath()
{
$e = new FileNotFoundException();
$this->assertEquals('File could not be found.', $e->getMessage(), 'A message should be generated.');
}

public function testCustomMessage()
{
$e = new FileNotFoundException('bar', 0, null, '/foo');
$this->assertEquals('bar', $e->getMessage(), 'A custom message should be possible still.');
}
}