Passed
Branch master (5ddafc)
by Caen
03:34
created

validateSubdirectoryCanBeUsed()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 2
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Console\Commands;
6
7
use function array_unique;
8
use function basename;
9
use function config;
10
use Hyde\Console\Concerns\Command;
11
use Hyde\Facades\Filesystem;
12
use Hyde\Hyde;
13
use Hyde\Pages\BladePage;
14
use Hyde\Pages\DocumentationPage;
15
use Hyde\Pages\HtmlPage;
16
use Hyde\Pages\MarkdownPage;
17
use Hyde\Pages\MarkdownPost;
18
use InvalidArgumentException;
19
use function realpath;
20
use function str_replace;
21
22
/**
23
 * @see \Hyde\Framework\Testing\Feature\Commands\ChangeSourceDirectoryCommandTest
24
 */
25
class ChangeSourceDirectoryCommand extends Command
26
{
27
    /** @var string */
28
    protected $signature = 'change:sourceDirectory {name : The new source directory name }';
29
30
    /** @var string */
31
    protected $description = 'Change the source directory for your project.';
32
33
    protected $hidden = true;
34
35
    public function handle(): int
36
    {
37
        try {
38
            $newDirectoryName = $this->getValidatedName((string) $this->argument('name'));
39
        } catch (InvalidArgumentException $exception) {
40
            $this->error($exception->getMessage());
41
42
            return 409;
43
        }
44
45
        $this->gray(' > Creating directory');
46
        Filesystem::ensureDirectoryExists($newDirectoryName);
47
48
        $this->gray(' > Moving source directories');
49
        foreach ($this->getPageDirectories() as $directory) {
50
            Filesystem::moveDirectory($directory, $this->assembleSubdirectoryPath($newDirectoryName, $directory));
51
        }
52
53
        $this->gray(' > Updating configuration file');
54
        $this->updateConfigurationFile($newDirectoryName, (string) config('hyde.source_root', ''));
55
56
        // We could also check if there are any more page classes (from packages) and add a note that they may need manual attention
57
58
        $this->info('All done!');
59
60
        return Command::SUCCESS;
61
    }
62
63
    /** @return string[] */
64
    protected function getPageDirectories(): array
65
    {
66
        return array_unique([
67
            HtmlPage::$sourceDirectory,
68
            BladePage::$sourceDirectory,
69
            MarkdownPage::$sourceDirectory,
70
            MarkdownPost::$sourceDirectory,
71
            DocumentationPage::$sourceDirectory,
72
        ]);
73
    }
74
75
    protected function getValidatedName(string $name): string
76
    {
77
        $this->validateName($name);
78
        $this->validateDirectoryCanBeUsed($name);
79
        $this->infoComment('Setting', $name, 'as the project source directory!');
80
81
        return $name;
82
    }
83
84
    protected function validateName(string $name): void
85
    {
86
        if (realpath(Hyde::path($name)) === realpath(Hyde::path(config('hyde.source_root', '')))) {
87
            throw new InvalidArgumentException("The directory '$name' is already set as the project source root!");
88
        }
89
    }
90
91
    protected function validateDirectoryCanBeUsed(string $name): void
92
    {
93
        if (Filesystem::isFile($name)) {
94
            throw new InvalidArgumentException('A file already exists at this path!');
95
        }
96
97
        if (Filesystem::isDirectory($name) && ! Filesystem::isEmptyDirectory($name)) {
98
            // If any of the subdirectories we want to move already exist, we need to abort as we don't want to overwrite any existing files
99
            // The reason we check these individually is mainly so that the change can be reverted (by setting the $name to '/')
100
            foreach ($this->getPageDirectories() as $directory) {
101
                $this->validateSubdirectoryCanBeUsed($this->assembleSubdirectoryPath($name, $directory));
102
            }
103
        }
104
    }
105
106
    protected function validateSubdirectoryCanBeUsed(string $subdirectoryPath): void
107
    {
108
        if (Filesystem::isFile($subdirectoryPath) || $this->directoryContainsFiles($subdirectoryPath)) {
109
            throw new InvalidArgumentException('Directory already exists!');
110
        }
111
    }
112
113
    protected function assembleSubdirectoryPath(string $name, string $subdirectory): string
114
    {
115
        return "$name/".basename($subdirectory);
116
    }
117
118
    protected function directoryContainsFiles(string $subdirectory): bool
119
    {
120
        return Filesystem::isDirectory($subdirectory) && ! Filesystem::isEmptyDirectory($subdirectory);
121
    }
122
123
    protected function updateConfigurationFile(string $newDirectoryName, string $currentDirectoryName): void
124
    {
125
        $search = "'source_root' => '$currentDirectoryName',";
126
127
        $config = Filesystem::getContents('config/hyde.php');
128
        if (str_contains($config, $search)) {
129
            $config = str_replace($search, "'source_root' => '$newDirectoryName',", $config);
130
            Filesystem::putContents('config/hyde.php', $config);
131
        } else {
132
            $this->warn("Warning: Automatic configuration update failed, to finalize the change, please set the `source_root` setting to '$newDirectoryName' in `config/hyde.php`");
133
        }
134
    }
135
}
136