• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 11331827224

14 Oct 2024 04:52PM UTC coverage: 80.589% (-1.4%) from 82.008%
11331827224

Pull #568

github

web-flow
Merge 57ab8f089 into 158b2db46
Pull Request #568: feat(generator/console): add make:controller command

53 of 206 new or added lines in 8 files covered. (25.73%)

10 existing lines in 5 files now uncovered.

6813 of 8454 relevant lines covered (80.59%)

39.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Tempest/Console/src/Commands/Generators/MakeControllerCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Commands\Generators;
6

7
use function Tempest\Support\str;
8
use Tempest\Validation\Rules\NotEmpty;
9
use Tempest\Validation\Rules\EndsWith;
10
use Tempest\Support\PathHelper;
11
use Tempest\Generation\ClassManipulator;
12
use Tempest\Core\Composer;
13
use Tempest\Console\Stubs\ControllerStub;
14
use Tempest\Console\ConsoleCommand;
15
use Tempest\Console\ConsoleArgument;
16
use Tempest\Console\Console;
17
use Tempest\Support\StringHelper;
18

19
final class MakeControllerCommand
20
{
NEW
21
    public function __construct(
×
22
        protected readonly Composer $composer,
23
        protected readonly Console $console,
24
    ) {
NEW
25
    }
×
26

NEW
27
    #[ConsoleCommand(
×
28
        name       : 'make:controller',
29
        description: 'Create a new controller class with a basic route',
30
        aliases    : ['controller:make', 'controller:create', 'create:controller'],
31
    )]
32
    public function __invoke(
33
        #[ConsoleArgument(
34
            help: 'The name of the controller class to create ( "Controller" will be suffixed )',
35
        )]
36
        string $controllerClassname,
37
        ?string $controllerPath = null,
38
        ?string $controllerView = null,
39
    ): void {
NEW
40
        $pathPrefix  = 'Controllers';
×
NEW
41
        $classSuffix = 'Controller';
×
42

43
        // Separate input path and classname
NEW
44
        $classname = PathHelper::toClassName($controllerClassname);
×
NEW
45
        $inputPath = str(PathHelper::make($controllerClassname))->replace($classname, '')->toString();
×
NEW
46
        $classname = str($classname)
×
NEW
47
            ->pascal()
×
NEW
48
            ->finish($classSuffix)
×
NEW
49
            ->toString();
×
50

51
        // Prepare the suggested path from the project namespace
NEW
52
        $suggestedPath = str(PathHelper::make(
×
NEW
53
            $this->composer->mainNamespace->path,
×
NEW
54
            $pathPrefix,
×
NEW
55
            $inputPath,
×
NEW
56
        ))
×
NEW
57
            ->finish(DIRECTORY_SEPARATOR)
×
NEW
58
            ->toString();
×
59

NEW
60
        $targetPath = $this->promptTargetPath(
×
NEW
61
            classname    : $classname,
×
NEW
62
            suggestedPath: $suggestedPath . $classname . '.php',
×
NEW
63
            rules        : [new NotEmpty(), new EndsWith('.php')]
×
NEW
64
        );
×
65

NEW
66
        if (! $this->prepareFilesystem($targetPath)) {
×
NEW
67
            $this->console->error('The operation has been aborted.');
×
NEW
68
            return;
×
69
        }
70

71
        // Transform stub to class
NEW
72
        $namespace        = PathHelper::toRegisteredNamespace($targetPath);
×
NEW
73
        $classname        = PathHelper::toClassName($targetPath);
×
NEW
74
        $classManipulator = (new ClassManipulator(ControllerStub::class))
×
NEW
75
            ->setNamespace($namespace)
×
NEW
76
            ->setClassName($classname)
×
NEW
77
            ->manipulate(fn( StringHelper $code ) => ! is_null( $controllerPath ) ? $code->replace('dummy-path', $controllerPath) : $code)
×
NEW
78
            ->manipulate(fn( StringHelper $code ) => ! is_null( $controllerView ) ? $code->replace('dummy-view', $controllerView) : $code);
×
79

80
        // Write the file
NEW
81
        file_put_contents(
×
NEW
82
            $targetPath,
×
NEW
83
            $classManipulator->print()
×
NEW
84
        );
×
85

NEW
86
        $this->console->success(sprintf('Controller successfully created at "%s".', $targetPath));
×
87
    }
88

89
    /**
90
     * Prompt the target path to the user.
91
     *
92
     * @param string $classname The name of the class.
93
     * @param string $suggestedPath The suggested path.
94
     * @param array $rules The validation rules.
95
     *
96
     * @return string The validated target path.
97
     */
NEW
98
    protected function promptTargetPath(string $classname, string $suggestedPath, array $rules = []): string
×
99
    {
NEW
100
        return $this->console->ask(
×
NEW
101
            question  : sprintf('Where do you want to save the controller "%s"?', $classname),
×
NEW
102
            default   : $suggestedPath,
×
NEW
103
            validation: $rules
×
NEW
104
        );
×
105
    }
106

107
    /**
108
     * Prepare the directory structure for the new file.
109
     * It can also ask the user if they want to overwrite the file if it already exists.
110
     *
111
     * @param string $targetPath The path to the target file.
112
     *
113
     * @return boolean Whether the filesystem is ready to write the file.
114
     */
NEW
115
    protected function prepareFilesystem(string $targetPath): bool
×
116
    {
117
        // Maybe delete the file if it exists and we force the override
NEW
118
        if (file_exists($targetPath)) {
×
NEW
119
            $shouldOverride = $this->console->confirm(
×
NEW
120
                question: sprintf('"%s" already exists, do you want to overwrite it?', $targetPath),
×
NEW
121
                default : false,
×
NEW
122
            );
×
123

NEW
124
            if (! $shouldOverride) {
×
NEW
125
                return false;
×
126
            }
127

NEW
128
            @unlink($targetPath);
×
129
        }
130

131
        // Recursively create directories before writing the file
NEW
132
        if (! file_exists(dirname($targetPath))) {
×
NEW
133
            mkdir(dirname($targetPath), recursive: true);
×
134
        }
135

NEW
136
        return true;
×
137
    }
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc