From 1f7b7536709507d242071812b327578df3084650 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 23 Nov 2016 21:33:32 +0100 Subject: [PATCH] [Filesystem] Add appendToFile() --- src/Symfony/Component/Filesystem/CHANGELOG.md | 5 ++ .../Component/Filesystem/Filesystem.php | 27 ++++++- .../Filesystem/Tests/FilesystemTest.php | 75 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Filesystem/CHANGELOG.md b/src/Symfony/Component/Filesystem/CHANGELOG.md index 09ca3508c02a0..4a275e86f0cad 100644 --- a/src/Symfony/Component/Filesystem/CHANGELOG.md +++ b/src/Symfony/Component/Filesystem/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +3.3.0 +----- + + * added `appendToFile()` to append contents to existing files + 3.2.0 ----- diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index b24caa07a8b46..970a050a8e5fc 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -624,7 +624,7 @@ public function tempnam($dir, $prefix) * @param string $filename The file to be written to * @param string $content The data to write into the file * - * @throws IOException If the file cannot be written to. + * @throws IOException If the file cannot be written to */ public function dumpFile($filename, $content) { @@ -648,6 +648,31 @@ public function dumpFile($filename, $content) $this->rename($tmpFile, $filename, true); } + /** + * Appends content to an existing file. + * + * @param string $filename The file to which to append content + * @param string $content The content to append + * + * @throws IOException If the file is not writable + */ + public function appendToFile($filename, $content) + { + $dir = dirname($filename); + + if (!is_dir($dir)) { + $this->mkdir($dir); + } + + if (!is_writable($dir)) { + throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir); + } + + if (false === @file_put_contents($filename, $content, FILE_APPEND)) { + throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename); + } + } + /** * @param mixed $files * diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index c1ec8a4139114..61baf1b50cf49 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1406,6 +1406,81 @@ public function testDumpFileWithZlibScheme() $this->assertSame('bar', file_get_contents($filename)); } + public function testAppendToFile() + { + $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.txt'; + + // skip mode check on Windows + if ('\\' !== DIRECTORY_SEPARATOR) { + $oldMask = umask(0002); + } + + $this->filesystem->dumpFile($filename, 'foo'); + + $this->filesystem->appendToFile($filename, 'bar'); + + $this->assertFileExists($filename); + $this->assertSame('foobar', file_get_contents($filename)); + + // skip mode check on Windows + if ('\\' !== DIRECTORY_SEPARATOR) { + $this->assertFilePermissions(664, $filename, 'The written file should keep the same permissions as before.'); + umask($oldMask); + } + } + + public function testAppendToFileWithScheme() + { + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('HHVM does not handle the file:// scheme correctly'); + } + + $scheme = 'file://'; + $filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt'; + $this->filesystem->dumpFile($filename, 'foo'); + + $this->filesystem->appendToFile($filename, 'bar'); + + $this->assertFileExists($filename); + $this->assertSame('foobar', file_get_contents($filename)); + } + + public function testAppendToFileWithZlibScheme() + { + $scheme = 'compress.zlib://'; + $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt'; + $this->filesystem->dumpFile($filename, 'foo'); + + // Zlib stat uses file:// wrapper so remove it + $this->assertSame('foo', file_get_contents(str_replace($scheme, '', $filename))); + + $this->filesystem->appendToFile($filename, 'bar'); + + $this->assertFileExists($filename); + $this->assertSame('foobar', file_get_contents($filename)); + } + + public function testAppendToFileCreateTheFileIfNotExists() + { + $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.txt'; + + // skip mode check on Windows + if ('\\' !== DIRECTORY_SEPARATOR) { + $oldMask = umask(0002); + } + + $this->filesystem->appendToFile($filename, 'bar'); + + // skip mode check on Windows + if ('\\' !== DIRECTORY_SEPARATOR) { + $this->assertFilePermissions(664, $filename); + umask($oldMask); + } + + $this->assertFileExists($filename); + $this->assertSame('bar', file_get_contents($filename)); + } + public function testCopyShouldKeepExecutionPermission() { $this->markAsSkippedIfChmodIsMissing();