public function copyDirectory(string $source, string $target, int $flags = null) : bool
    {
        if (!$this->exists($source)) {
            return false;
        }

        if (!$this->isDirectory($target) && !$this->makeDirectory($target, 0777, true)) {
            return false;
        }

        if ($flags === null) {
            $flags = FilesystemIterator::SKIP_DOTS;
        }

        $items = new FilesystemIterator($source, $flags);

        foreach ($items as $item) {
            if ($item->isDir()) {
                if (!$this->copyDirectory($item->getRealPath(), $target . '/' . $item->getBasename(), $flags)) {
                    return false;
                }
            } elseif ($item->isFile()) {
                if (!$this->copyFile($item->getRealPath(), $target . '/' . $item->getBasename())) {
                    return false;
                }
            }
        }

        return true;
    }