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