diff --git a/src/Utils/FileSystem.php b/src/Utils/FileSystem.php index 16d5ffd10..a4fea42fd 100644 --- a/src/Utils/FileSystem.php +++ b/src/Utils/FileSystem.php @@ -26,7 +26,7 @@ final class FileSystem public static function createDir(string $dir, int $mode = 0777): void { if (!is_dir($dir) && !@mkdir($dir, $mode, true) && !is_dir($dir)) { // @ - dir may already exist - throw new Nette\IOException("Unable to create directory '$dir' with mode " . decoct($mode) . '. ' . Helpers::getLastError()); + throw new Nette\IOException("Unable to create directory '" . self::normalizePath($dir) . "' with mode " . decoct($mode) . '. ' . Helpers::getLastError()); } } @@ -39,10 +39,10 @@ public static function createDir(string $dir, int $mode = 0777): void public static function copy(string $origin, string $target, bool $overwrite = true): void { if (stream_is_local($origin) && !file_exists($origin)) { - throw new Nette\IOException("File or directory '$origin' not found."); + throw new Nette\IOException("File or directory '" . self::normalizePath($origin) . "' not found."); } elseif (!$overwrite && file_exists($target)) { - throw new Nette\InvalidStateException("File or directory '$target' already exists."); + throw new Nette\InvalidStateException("File or directory '" . self::normalizePath($target) . "' already exists."); } elseif (is_dir($origin)) { static::createDir($target); @@ -64,7 +64,7 @@ public static function copy(string $origin, string $target, bool $overwrite = tr && ($d = @fopen($target, 'wb')) && @stream_copy_to_stream($s, $d) === false ) { // @ is escalated to exception - throw new Nette\IOException("Unable to copy file '$origin' to '$target'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to copy file '" . self::normalizePath($origin) . "' to '" . self::normalizePath($target) . "'. " . Helpers::getLastError()); } } } @@ -79,7 +79,7 @@ public static function delete(string $path): void if (is_file($path) || is_link($path)) { $func = DIRECTORY_SEPARATOR === '\\' && is_dir($path) ? 'rmdir' : 'unlink'; if (!@$func($path)) { // @ is escalated to exception - throw new Nette\IOException("Unable to delete '$path'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to delete '" . self::normalizePath($path) . "'. " . Helpers::getLastError()); } } elseif (is_dir($path)) { @@ -87,7 +87,7 @@ public static function delete(string $path): void static::delete($item->getPathname()); } if (!@rmdir($path)) { // @ is escalated to exception - throw new Nette\IOException("Unable to delete directory '$path'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to delete directory '" . self::normalizePath($path) . "'. " . Helpers::getLastError()); } } } @@ -101,10 +101,10 @@ public static function delete(string $path): void public static function rename(string $origin, string $target, bool $overwrite = true): void { if (!$overwrite && file_exists($target)) { - throw new Nette\InvalidStateException("File or directory '$target' already exists."); + throw new Nette\InvalidStateException("File or directory '" . self::normalizePath($target) . "' already exists."); } elseif (!file_exists($origin)) { - throw new Nette\IOException("File or directory '$origin' not found."); + throw new Nette\IOException("File or directory '" . self::normalizePath($origin) . "' not found."); } else { static::createDir(dirname($target)); @@ -112,7 +112,7 @@ public static function rename(string $origin, string $target, bool $overwrite = static::delete($target); } if (!@rename($origin, $target)) { // @ is escalated to exception - throw new Nette\IOException("Unable to rename file or directory '$origin' to '$target'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to rename file or directory '" . self::normalizePath($origin) . "' to '" . self::normalizePath($target) . "'. " . Helpers::getLastError()); } } } @@ -126,7 +126,7 @@ public static function read(string $file): string { $content = @file_get_contents($file); // @ is escalated to exception if ($content === false) { - throw new Nette\IOException("Unable to read file '$file'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to read file '" . self::normalizePath($file) . "'. " . Helpers::getLastError()); } return $content; } @@ -140,10 +140,31 @@ public static function write(string $file, string $content, ?int $mode = 0666): { static::createDir(dirname($file)); if (@file_put_contents($file, $content) === false) { // @ is escalated to exception - throw new Nette\IOException("Unable to write file '$file'. " . Helpers::getLastError()); + throw new Nette\IOException("Unable to write file '" . self::normalizePath($file) . "'. " . Helpers::getLastError()); } if ($mode !== null && !@chmod($file, $mode)) { // @ is escalated to exception - throw new Nette\IOException("Unable to chmod file '$file' to mode " . decoct($mode) . '. ' . Helpers::getLastError()); + throw new Nette\IOException("Unable to chmod file '" . self::normalizePath($file) . "' to mode " . decoct($mode) . '. ' . Helpers::getLastError()); + } + } + + + /** + * Fixes permissions to a specific file or directory. Directories can be fixed recursively. + * @throws Nette\IOException on error occurred + */ + public static function makeWritable(string $path, int $dirMode = 0777, int $fileMode = 0666): void + { + if (is_file($path)) { + if (!@chmod($path, $fileMode)) { // @ is escalated to exception + throw new Nette\IOException("Unable to chmod file '$path' to mode " . decoct($fileMode) . '. ' . Helpers::getLastError()); + } + } elseif (is_dir($path)) { + foreach (new \FilesystemIterator($path) as $item) { + static::makeWritable($item->getPathname(), $dirMode, $fileMode); + } + if (!@chmod($path, $dirMode)) { // @ is escalated to exception + throw new Nette\IOException("Unable to chmod directory '$path' to mode " . decoct($dirMode) . '. ' . Helpers::getLastError()); + } } } diff --git a/tests/Utils/Reflection.getReturnType.phpt b/tests/Utils/Reflection.getReturnType.phpt index e4002c5dd..993a22747 100644 --- a/tests/Utils/Reflection.getReturnType.phpt +++ b/tests/Utils/Reflection.getReturnType.phpt @@ -63,6 +63,11 @@ class A public function nullableUnionType(): array|self|null { } + + + function unionType(): array|A + { + } } class AExt extends A diff --git a/tests/Utils/Reflection.getReturnType.x.phpt b/tests/Utils/Reflection.getReturnType.x.phpt new file mode 100644 index 000000000..0f7cedb7b --- /dev/null +++ b/tests/Utils/Reflection.getReturnType.x.phpt @@ -0,0 +1,24 @@ +