ClassGenerator   B
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 420
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 77.78%

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 7
dl 0
loc 420
ccs 84
cts 108
cp 0.7778
rs 8.2857
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A defDescription() 0 11 2
A defNamespace() 0 6 1
A defName() 0 6 1
A defUse() 0 11 2
A defExtends() 0 6 1
A defImplements() 0 6 1
A defTrait() 0 6 1
A defProtectedMethod() 0 4 1
A defMethod() 0 4 1
A defProtectedStaticMethod() 0 4 1
A defStaticMethod() 0 4 1
A defProtectedProperty() 0 4 1
A defProperty() 0 9 1
A defProtectedStaticProperty() 0 4 1
A defStaticProperty() 0 4 1
A defConstant() 0 9 1
B code() 0 28 2
A buildNamespaceCode() 0 13 2
A buildFileDescriptionCode() 0 9 2
A buildUsesCode() 0 14 4
B buildDefinition() 0 9 5
A buildTraitsCode() 0 14 3
A getClassName() 0 4 1
A getNamespace() 0 4 1
1
<?php declare(strict_types=1);
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 03.09.16 at 09:58
5
 */
6
namespace samsonframework\generator;
7
8
use samsonframework\generator\exception\ClassNameNotFoundException;
9
10
/**
11
 * Class generator class.
12
 *
13
 * @author Vitaly Egorov <[email protected]>
14
 */
15
class ClassGenerator extends AbstractGenerator
16
{
17
    use AbstractFinalTrait;
18
19
    /** OOP public visibility */
20
    const VISIBILITY_PUBLIC = 'public';
21
22
    /** OOP protected visibility */
23
    const VISIBILITY_PROTECTED = 'protected';
24
25
    /** OOP private visibility */
26
    const VISIBILITY_PRIVATE = 'private';
27
28
    /** @var string Class name */
29
    protected $className;
30
31
    /** @var string Parent class name */
32
    protected $parentClassName;
33
34
    /** @var string Class namespace */
35
    protected $namespace;
36
37
    /** @var array Collection of class uses */
38
    protected $uses = [];
39
40
    /** @var array Collection of class interfaces */
41
    protected $interfaces = [];
42
43
    /** @var array Collection of class used traits */
44
    protected $traits = [];
45
46
    /** @var string Multi-line file description */
47
    protected $fileDescription;
48
49
    /**
50
     * ClassGenerator constructor.
51
     *
52
     * @param string            $className Class name
53
     * @param AbstractGenerator $parent    Parent generator
54
     */
55 24
    public function __construct(string $className = null, AbstractGenerator $parent = null)
56
    {
57 24
        $this->className = $className;
58
59 24
        parent::__construct($parent);
60 24
    }
61
62
    /**
63
     * Set class file description.
64
     *
65
     * @param array $description Collection of class file description lines
66
     *
67
     * @return ClassGenerator
68
     */
69 1
    public function defDescription(array $description): ClassGenerator
70
    {
71 1
        $commentsGenerator = new CommentsGenerator($this);
72 1
        foreach ($description as $line) {
73 1
            $commentsGenerator->defLine($line);
74
        }
75
76 1
        $this->fileDescription = $commentsGenerator->code();
77
78 1
        return $this;
79
    }
80
81
    /**
82
     * Set class namespace.
83
     *
84
     * @param string $namespace
85
     *
86
     * @return ClassGenerator
87
     */
88 23
    public function defNamespace(string $namespace): ClassGenerator
89
    {
90 23
        $this->namespace = $namespace;
91
92 23
        return $this;
93
    }
94
95
    /**
96
     * Set class name.
97
     *
98
     * @param string $className
99
     *
100
     * @return ClassGenerator
101
     */
102 1
    public function defName(string $className): ClassGenerator
103
    {
104 1
        $this->className = $className;
105
106 1
        return $this;
107
    }
108
109
    /**
110
     * Set class use.
111
     *
112
     * @param string $use   Use class name
113
     * @param string $alias Use class name
114
     *
115
     * @return ClassGenerator
116
     */
117 2
    public function defUse(string $use, string $alias = null): ClassGenerator
118
    {
119
        // Store the alias of class
120 2
        if ($alias) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $alias of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
121 1
            $this->uses[$alias] = $use;
122
        } else {
123 2
            $this->uses[] = $use;
124
        }
125
126 2
        return $this;
127
    }
128
129
    /**
130
     * Set parent class.
131
     *
132
     * @param string $className Parent class name
133
     *
134
     * @return ClassGenerator
135
     */
136 2
    public function defExtends(string $className): ClassGenerator
137
    {
138 2
        $this->parentClassName = $className;
139
140 2
        return $this;
141
    }
142
143
    /**
144
     * Set implements interfaces.
145
     *
146
     * @param string $interfaceName Interface name
147
     *
148
     * @return ClassGenerator
149
     */
150 3
    public function defImplements(string $interfaceName): ClassGenerator
151
    {
152 3
        $this->interfaces[] = $interfaceName;
153
154 3
        return $this;
155
    }
156
157
    /**
158
     * Set class trait use.
159
     *
160
     * @param string $trait Trait class name
161
     *
162
     * @return ClassGenerator
163
     */
164 1
    public function defTrait(string $trait): ClassGenerator
165
    {
166 1
        $this->traits[] = $trait;
167
168 1
        return $this;
169
    }
170
171
    /**
172
     * Set protected class property.
173
     *
174
     * @param string $name        Property name
175
     * @param string $type        Property type
176
     * @param mixed  $value       Property value
177
     * @param string $description Property description
178
     *
179
     * @return PropertyGenerator
180
     */
181
    public function defProtectedProperty(string $name, string $type, $value, string $description = null): PropertyGenerator
182
    {
183
        return $this->defProperty($name, $type, $value, $description)->defProtected();
184
    }
185
186
    /**
187
     * Set class property.
188
     *
189
     * @param string $name        Property name
190
     * @param string $type        Property type
191
     * @param mixed  $value       Property value
192
     * @param string $description Property description
193
     *
194
     * @return PropertyGenerator
195
     */
196
    public function defProperty(string $name, string $type, $value = null, string $description = null): PropertyGenerator
197
    {
198
        return (new PropertyGenerator($name, $value, $this))
199
            ->setIndentation($this->indentation)
200
            ->increaseIndentation()
201
            ->defComment()
202
            ->defVar($type, $description)
203
            ->end();
204
    }
205
206
    /**
207
     * Set protected static class property.
208
     *
209
     * @param string $name        Property name
210
     * @param string $type        Property type
211
     * @param mixed  $value       Property value
212
     * @param string $description Property description
213
     *
214
     * @return PropertyGenerator
215
     */
216
    public function defProtectedStaticProperty(string $name, string $type, $value, string $description = null): PropertyGenerator
217
    {
218
        return $this->defStaticProperty($name, $type, $value, $description)->defProtected();
219
    }
220
221
    /**
222
     * Set static class property.
223
     *
224
     * @param string $name        Property name
225
     * @param string $type        Property type
226
     * @param mixed  $value       Property value
227
     * @param string $description Property description
228
     *
229
     * @return PropertyGenerator
230
     */
231
    public function defStaticProperty(string $name, string $type, $value, string $description = null): PropertyGenerator
232
    {
233
        return $this->defProperty($name, $type, $value, $description)->defStatic();
234
    }
235
236
    /**
237
     * Set protected class method.
238
     *
239
     * @param string $name Method name
240
     *
241
     * @return MethodGenerator
242
     */
243 1
    public function defProtectedMethod(string $name): MethodGenerator
244
    {
245 1
        return $this->defMethod($name)->defProtected();
246
    }
247
248
    /**
249
     * Set public class method.
250
     *
251
     * @param string $name Method name
252
     *
253
     * @return MethodGenerator
254
     */
255 6
    public function defMethod(string $name): MethodGenerator
256
    {
257 6
        return (new MethodGenerator($name, $this))->setIndentation($this->indentation)->increaseIndentation();
258
    }
259
260
    /**
261
     * Set protected static class method.
262
     *
263
     * @param string $name Method name
264
     *
265
     * @return MethodGenerator
266
     */
267 1
    public function defProtectedStaticMethod(string $name): MethodGenerator
268
    {
269 1
        return $this->defStaticMethod($name)->defProtected();
270
    }
271
272
    /**
273
     * Set public static class method.
274
     *
275
     * @param string $name Method name
276
     *
277
     * @return MethodGenerator
278
     */
279 2
    public function defStaticMethod(string $name): MethodGenerator
280
    {
281 2
        return $this->defMethod($name)->defStatic();
282
    }
283
284
    /**
285
     * Set class constant.
286
     *
287
     * @param string $name
288
     * @param mixed  $value
289
     * @param string $type
290
     * @param string $description
291
     *
292
     * @return $this|ClassConstantGenerator
293
     */
294
    public function defConstant(string $name, $value, string $type, string $description): ClassConstantGenerator
295
    {
296
        return (new ClassConstantGenerator($name, $value, $this))
297
            ->setIndentation($this->indentation)
298
            ->increaseIndentation()
299
            ->defComment()
300
            ->defLine($type . ' ' . $description)
301
            ->end();
302
    }
303
304
    /**
305
     * @inheritdoc
306
     * @throws \InvalidArgumentException
307
     * @throws ClassNameNotFoundException
308
     */
309 22
    public function code(): string
310
    {
311 22
        if (!$this->className) {
312 1
            throw new ClassNameNotFoundException('Class name should be defined');
313
        }
314
315 21
        $formattedCode = $this->buildNamespaceCode();
316 20
        $formattedCode = $this->buildFileDescriptionCode($formattedCode);
317 20
        $formattedCode = $this->buildUsesCode($formattedCode);
318 20
        $formattedCode = $this->buildNestedCode(CommentsGenerator::class, $formattedCode);
319
320
        // Add previously generated code
321 20
        $formattedCode[] = $this->buildDefinition();
322 20
        $formattedCode[] = '{';
323
324 20
        $indentationString = $this->indentation($this->indentation);
325 20
        $innerIndentation = $this->indentation(1);
326
327 20
        $formattedCode = $this->buildTraitsCode($formattedCode, $innerIndentation);
328 20
        $formattedCode = $this->buildNestedCode(ClassConstantGenerator::class, $formattedCode);
329 20
        $formattedCode = $this->buildNestedCode(PropertyGenerator::class, $formattedCode);
330 20
        $formattedCode = $this->buildNestedCode(MethodGenerator::class, $formattedCode);
331
332
        // Close class and add one empty line
333 20
        $formattedCode[] = '}' . "\n";
334
335 20
        return implode("\n" . $indentationString, $formattedCode);
336
    }
337
338 21
    protected function buildNamespaceCode(array $formattedCode = []): array
339
    {
340 21
        if ($this->namespace === null) {
341 1
            throw new \InvalidArgumentException('Class namespace should be defined');
342
        }
343
344 20
        $formattedCode[] = 'namespace ' . $this->namespace . ';';
345
346
        // One empty line after namespace
347 20
        $formattedCode[] = '';
348
349 20
        return $formattedCode;
350
    }
351
352 20
    protected function buildFileDescriptionCode(array $formattedCode): array
353
    {
354
        // Prepend file description if present
355 20
        if ($this->fileDescription !== null) {
356 1
            array_unshift($formattedCode, $this->fileDescription);
357
        }
358
359 20
        return $formattedCode;
360
    }
361
362 20
    protected function buildUsesCode(array $formattedCode): array
363
    {
364
        // Add uses
365 20
        foreach ($this->uses as $alias => $use) {
366 2
            $formattedCode[] = 'use ' . $use . (is_string($alias) ? ' as ' . $alias : '') . ';';
367
        }
368
369
        // One empty line after uses if we have them
370 20
        if (count($this->uses)) {
371 2
            $formattedCode[] = '';
372
        }
373
374 20
        return $formattedCode;
375
    }
376
377
    /**
378
     * Build class definition.
379
     *
380
     * @return string Function definition
381
     */
382 19
    protected function buildDefinition()
383
    {
384 19
        return ($this->isFinal ? 'final ' : '') .
385 19
            ($this->isAbstract ? 'abstract ' : '') .
386 19
            'class ' .
387 19
            $this->className .
388 19
            ($this->parentClassName ? ' extends ' . $this->parentClassName : '') .
389 19
            (count($this->interfaces) ? rtrim(' implements ' . implode(', ', $this->interfaces), ', ') : '');
390
    }
391
392
    /**
393
     * Build traits definition code.
394
     *
395
     * @param array  $formattedCode    Collection of code
396
     * @param string $innerIndentation Inner indentation
397
     *
398
     * @return array Collection of code with trait uses
399
     */
400 20
    protected function buildTraitsCode(array $formattedCode, string $innerIndentation): array
401
    {
402
        // Add traits
403 20
        foreach ($this->traits as $trait) {
404 1
            $formattedCode[] = $innerIndentation . 'use ' . $trait . ';';
405
        }
406
407
        // One empty line after traits if we have them
408 20
        if (count($this->traits)) {
409 1
            $formattedCode[] = '';
410
        }
411
412 20
        return $formattedCode;
413
    }
414
415
    /**
416
     * Get generated class name.
417
     *
418
     * @return string Generated class name
419
     */
420
    public function getClassName(): string
421
    {
422
        return $this->className;
423
    }
424
425
    /**
426
     * Get generated class namespace.
427
     *
428
     * @return string Generated class namespace
429
     */
430
    public function getNamespace(): string
431
    {
432
        return $this->namespace;
433
    }
434
}
435