Passed
Pull Request — master (#51)
by Dmitriy
13:46
created

Generator   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Test Coverage

Coverage 72.86%

Importance

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

23 Methods

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