Passed
Pull Request — master (#52)
by Wilmer
02:40
created

Generator   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 233
Duplicated Lines 0 %

Test Coverage

Coverage 72.86%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 25
eloc 72
c 2
b 0
f 0
dl 0
loc 233
ccs 51
cts 70
cp 0.7286
rs 10

23 Methods

Rating   Name   Duplication   Size   Complexity  
A generate() 0 17 2
A getViewFile() 0 9 2
A setBaseClass() 0 3 1
A getControllerNamespace() 0 3 1
A setActions() 0 3 1
A setControllerNamespace() 0 3 1
A getName() 0 3 1
A getActionIDs() 0 6 1
A attributeLabels() 0 7 1
A getBaseClass() 0 3 1
A getControllerFile() 0 4 1
A getViewsPath() 0 3 1
A hints() 0 17 1
A setControllerClass() 0 3 1
A getControllerID() 0 4 1
A requiredTemplates() 0 5 1
A getActions() 0 3 1
A getDescription() 0 3 1
A setViewsPath() 0 3 1
A successMessage() 0 3 1
A stickyAttributes() 0 3 1
A rules() 0 24 1
A getControllerClass() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Gii\Generator\Controller;
6
7
use Closure;
8
use Yiisoft\Strings\Inflector;
9
use Yiisoft\Strings\StringHelper;
10
use Yiisoft\Validator\Rule\Callback;
11
use Yiisoft\Validator\Rule\Regex;
12
use Yiisoft\Validator\Rule\Required;
13
use Yiisoft\Validator\RuleInterface;
14
use Yiisoft\Yii\Gii\CodeFile;
15
use Yiisoft\Yii\Gii\Generator\AbstractGenerator;
16
17
/**
18
 * This generator will generate a controller and one or a few action view files.
19
 */
20
final class Generator extends AbstractGenerator
21
{
22
    private string $controllerNamespace = 'App\\Controller';
23
    /**
24
     * @var string the controller class name
25
     */
26
    private string $controllerClass = '';
27
    /**
28
     * @var string|null the controller's views path
29
     */
30
    private ?string $viewsPath = null;
31
    /**
32
     * @var string the base class of the controller
33
     */
34
    private string $baseClass = 'App\\Controller';
35
    /**
36
     * @var string list of action IDs separated by commas or spaces
37
     */
38
    private string $actions = 'index';
39
40
    public function getName(): string
41
    {
42
        return 'Controller Generator';
43
    }
44
45
    public function getDescription(): string
46
    {
47
        return 'This generator helps you to quickly generate a new controller class with
48
            one or several controller actions and their corresponding views.';
49
    }
50
51
    /**
52
     * @return Closure[]|Closure[][]|RuleInterface[]|RuleInterface[][]
53
     */
54 3
    public function rules(): array
55
    {
56 3
        return array_merge(
57 3
            parent::rules(),
58
            [
59
                'controllerClass' => [
60 3
                    new Required(),
61 3
                    new Regex(
62
                        pattern: '/^[A-Z][\w]*Controller$/',
63
                        message: 'Only word characters are allowed, and the class name must start with a capital letter and end with "Controller".'
64
                    ),
65 3
                    new Callback([$this, 'validateNewClass']),
66
                ],
67
                'baseClass' => [
68 3
                    new Required(),
69 3
                    new Regex(
70
                        pattern: '/^[\w\\\\]*$/',
71
                        message: 'Only word characters and backslashes are allowed.'
72
                    ),
73
                ],
74
                'actions' => [
75 3
                    new Regex(
76
                        pattern: '/^[a-z][a-z0-9\\-,\\s]*$/',
77
                        message: 'Only a-z, 0-9, dashes (-), spaces and commas are allowed.'
78
                    ),
79
                ],
80
            ]
81
        );
82
    }
83
84
    public function attributeLabels(): array
85
    {
86
        return [
87
            'baseClass' => 'Base Class',
88
            'controllerClass' => 'Controller Class',
89
            'viewsPath' => 'Views Path',
90
            'actions' => 'Action IDs',
91
        ];
92
    }
93
94 1
    public function requiredTemplates(): array
95
    {
96
        return [
97 1
            'controller.php',
98
            'view.php',
99
        ];
100
    }
101
102
    public function stickyAttributes(): array
103
    {
104
        return ['baseClass'];
105
    }
106
107
    public function hints(): array
108
    {
109
        return [
110
            'controllerClass' => 'This is the name of the controller class to be generated. You should
111
                provide a fully qualified namespaced class (e.g. <code>App\Controller\PostController</code>),
112
                and class name should be in CamelCase ending with the word <code>Controller</code>. Make sure the class
113
                is using the same namespace as specified by your application\'s controllerNamespace property.',
114
            'actions' => 'Provide one or multiple action IDs to generate empty action method(s) in the controller. Separate multiple action IDs with commas or spaces.
115
                Action IDs should be in lower case. For example:
116
                <ul>
117
                    <li><code>index</code> generates <code>index()</code></li>
118
                    <li><code>create-order</code> generates <code>createOrder()</code></li>
119
                </ul>',
120
            'viewsPath' => 'Specify the directory for storing the view scripts for the controller. You may use path alias here, e.g.,
121
                <code>/var/www/app/controllers/views/order</code>, <code>@app/views/order</code>. If not set, it will default
122
                to <code>@app/views/ControllerID</code>',
123
            'baseClass' => 'This is the class that the new controller class will extend from. Please make sure the class exists and can be autoloaded.',
124
        ];
125
    }
126
127
    public function successMessage(): string
128
    {
129
        return 'The controller has been generated successfully.';
130
    }
131
132 2
    public function generate(): array
133
    {
134 2
        $files = [];
135
136 2
        $files[] = (new CodeFile(
137 2
            $this->getControllerFile(),
138 2
            $this->render('controller')
139 2
        ))->withBasePath($this->aliases->get('@root'));
140
141 2
        foreach ($this->getActionIDs() as $action) {
142 2
            $files[] = (new CodeFile(
143 2
                $this->getViewFile($action),
144 2
                $this->render('view', ['action' => $action])
145 2
            ))->withBasePath($this->aliases->get('@root'));
146
        }
147
148 2
        return $files;
149
    }
150
151
    /**
152
     * Normalizes [[actions]] into an array of action IDs.
153
     *
154
     * @return array an array of action IDs entered by the user
155
     */
156 2
    public function getActionIDs(): array
157
    {
158 2
        $actions = array_unique(preg_split('/[\s,]+/', $this->actions, -1, PREG_SPLIT_NO_EMPTY));
159 2
        sort($actions);
160
161 2
        return $actions;
162
    }
163
164
    /**
165
     * @return string the controller class file path
166
     */
167 2
    public function getControllerFile(): string
168
    {
169 2
        return $this->aliases->get(
170 2
            sprintf('%s/%s.php', $this->getDirectory() ?? '', $this->getControllerClass())
171
        );
172
    }
173
174
    /**
175
     * @return string the controller ID
176
     */
177 2
    public function getControllerID(): string
178
    {
179 2
        $name = StringHelper::baseName($this->controllerClass);
180 2
        return (new Inflector())->pascalCaseToId(substr($name, 0, -10));
181
    }
182
183
    /**
184
     * @param string $action the action ID
185
     *
186
     * @return string the action view file path
187
     */
188 2
    public function getViewFile(string $action): string
189
    {
190 2
        if (empty($this->getViewsPath())) {
191 2
            return $this->aliases->get(
192 2
                '@views/' . $this->getControllerID() . "/$action.php"
193
            );
194
        }
195
196
        return $this->aliases->get(str_replace('\\', '/', $this->getViewsPath()) . "/$action.php");
197
    }
198
199
    /**
200
     * @return string the namespace of the controller class
201
     */
202 1
    public function getControllerNamespace(): string
203
    {
204 1
        return $this->controllerNamespace;
205
    }
206
207
    /**
208
     * @param string $controllerNamespace
209
     */
210
    public function setControllerNamespace(string $controllerNamespace): void
211
    {
212
        $this->controllerNamespace = $controllerNamespace;
213
    }
214
215 3
    public function getControllerClass(): string
216
    {
217 3
        return $this->controllerClass;
218
    }
219
220 3
    public function setControllerClass(string $controllerClass): void
221
    {
222 3
        $this->controllerClass = $controllerClass;
223
    }
224
225 2
    public function getViewsPath(): ?string
226
    {
227 2
        return $this->viewsPath;
228
    }
229
230
    public function setViewsPath(?string $viewsPath): void
231
    {
232
        $this->viewsPath = $viewsPath;
233
    }
234
235 3
    public function getBaseClass(): string
236
    {
237 3
        return $this->baseClass;
238
    }
239
240
    public function setBaseClass(string $baseClass): void
241
    {
242
        $this->baseClass = $baseClass;
243
    }
244
245 3
    public function getActions(): string
246
    {
247 3
        return $this->actions;
248
    }
249
250 3
    public function setActions(string $actions): void
251
    {
252 3
        $this->actions = $actions;
253
    }
254
}
255