Completed
Push — master ( 6d07d8...b3d918 )
by Vitaly
28s
created

ClassGenerator::defName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 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
    public function __construct(string $className = null, AbstractGenerator $parent = null)
56
    {
57
        $this->className = $className;
58
59
        parent::__construct($parent);
60
    }
61
62
    /**
63
     * Set class file description.
64
     *
65
     * @param array $description Collection of class file description lines
66
     *
67
     * @return ClassGenerator
68
     */
69
    public function defDescription(array $description) : ClassGenerator
70
    {
71
        $commentsGenerator = new CommentsGenerator($this);
72
        foreach ($description as $line) {
73
            $commentsGenerator->defLine($line);
74
        }
75
76
        $this->fileDescription = $commentsGenerator->code();
77
78
        return $this;
79
    }
80
81
    /**
82
     * Set class namespace.
83
     *
84
     * @param string $namespace
85
     *
86
     * @return ClassGenerator
87
     */
88
    public function defNamespace(string $namespace) : ClassGenerator
89
    {
90
        $this->namespace = $namespace;
91
92
        return $this;
93
    }
94
95
    /**
96
     * Set class name.
97
     *
98
     * @param string $className
99
     *
100
     * @return ClassGenerator
101
     */
102
    public function defName(string $className) : ClassGenerator
103
    {
104
        $this->className = $className;
105
106
        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
    public function defUse(string $use, string $alias = null) : ClassGenerator
118
    {
119
        // Store the alias of class
120
        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
            $this->uses[$alias] = $use;
122
        } else {
123
            $this->uses[] = $use;
124
        }
125
126
        return $this;
127
    }
128
129
    /**
130
     * Set parent class.
131
     *
132
     * @param string $className Parent class name
133
     *
134
     * @return ClassGenerator
135
     */
136
    public function defExtends(string $className) : ClassGenerator
137
    {
138
        $this->parentClassName = $className;
139
140
        return $this;
141
    }
142
143
    /**
144
     * Set implements interfaces.
145
     *
146
     * @param string $interfaceName Interface name
147
     *
148
     * @return ClassGenerator
149
     */
150
    public function defImplements(string $interfaceName) : ClassGenerator
151
    {
152
        $this->interfaces[] = $interfaceName;
153
154
        return $this;
155
    }
156
157
    /**
158
     * Set class trait use.
159
     *
160
     * @param string $trait Trait class name
161
     *
162
     * @return ClassGenerator
163
     */
164
    public function defTrait(string $trait) : ClassGenerator
165
    {
166
        $this->traits[] = $trait;
167
168
        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
    public function defProtectedMethod(string $name) : MethodGenerator
244
    {
245
        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
    public function defMethod(string $name) : MethodGenerator
256
    {
257
        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
    public function defProtectedStaticMethod(string $name) : MethodGenerator
268
    {
269
        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
    public function defStaticMethod(string $name) : MethodGenerator
280
    {
281
        return $this->defMethod($name)->defStatic();
282
    }
283
284
    /**
285
     * Set class constant.
286
     *
287
     * @param string $name
288
     * @param mixed $value
289
     *
290
     * @return $this|ClassConstantGenerator
291
     */
292
    public function defConstant(string $name, $value, string $type, string $description) : ClassConstantGenerator
293
    {
294
        return (new ClassConstantGenerator($name, $value, $this))
295
            ->setIndentation($this->indentation)
296
            ->increaseIndentation()
297
            ->defComment()
298
                ->defLine($type.' '.$description)
299
            ->end();
300
    }
301
302
    protected function buildUsesCode(array $formattedCode) : array
303
    {
304
        // Add uses
305
        foreach ($this->uses as $alias => $use) {
306
            $formattedCode[] = 'use ' . $use . (is_string($alias) ? ' as ' . $alias : '') . ';';
307
        }
308
309
        // One empty line after uses if we have them
310
        if (count($this->uses)) {
311
            $formattedCode[] = '';
312
        }
313
314
        return $formattedCode;
315
    }
316
317
    protected function buildCommentsCode(array $formattedCode) : array
318
    {
319
        // Add comments
320
        if (array_key_exists(CommentsGenerator::class, $this->generatedCode)) {
321
            $formattedCode[] = $this->generatedCode[CommentsGenerator::class];
322
        }
323
324
        return $formattedCode;
325
    }
326
327
    protected function buildTraitsCode(array $formattedCode, string $innerIndentation) : array
328
    {
329
        // Add traits
330
        foreach ($this->traits as $trait) {
331
            $formattedCode[] = $innerIndentation . 'use ' . $trait . ';';
332
        }
333
334
        // One empty line after traits if we have them
335
        if (count($this->traits)) {
336
            $formattedCode[] = '';
337
        }
338
339
        return $formattedCode;
340
    }
341
342
    protected function buildFileDescriptionCode(array $formattedCode) : array
343
    {
344
        // Prepend file description if present
345
        if ($this->fileDescription !== null) {
346
            array_unshift($formattedCode, $this->fileDescription);
347
        }
348
349
        return $formattedCode;
350
    }
351
352
    protected function buildConstantsCode(array $formattedCode) : array
353
    {
354
        // Add constants
355
        if (array_key_exists(ClassConstantGenerator::class, $this->generatedCode)) {
356
            $formattedCode[] = $this->generatedCode[ClassConstantGenerator::class];
357
        }
358
359
        return $formattedCode;
360
    }
361
362
    protected function buildPropertiesCode(array $formattedCode) : array
363
    {
364
        if (array_key_exists(PropertyGenerator::class, $this->generatedCode)) {
365
            $formattedCode[] = $this->generatedCode[PropertyGenerator::class];
366
        }
367
368
        return $formattedCode;
369
    }
370
371
    protected function buildMethodsCode(array $formattedCode) : array
372
    {
373
        if (array_key_exists(MethodGenerator::class, $this->generatedCode)) {
374
            $formattedCode[] = $this->generatedCode[MethodGenerator::class];
375
        }
376
377
        return $formattedCode;
378
    }
379
380
    protected function buildNamespaceCode(array $formattedCode = []) : array
381
    {
382
        if ($this->namespace === null) {
383
            throw new \InvalidArgumentException('Class namespace should be defined');
384
        }
385
386
        $formattedCode[] = 'namespace ' . $this->namespace . ';';
387
388
        // One empty line after namespace
389
        $formattedCode[] = '';
390
391
        return $formattedCode;
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     * @throws \InvalidArgumentException
397
     * @throws ClassNameNotFoundException
398
     */
399
    public function code(int $indentation = 0) : string
400
    {
401
        if (!$this->className) {
402
            throw new ClassNameNotFoundException('Class name should be defined');
403
        }
404
405
        $formattedCode = $this->buildNamespaceCode();
406
        $formattedCode = $this->buildFileDescriptionCode($formattedCode);
407
        $formattedCode = $this->buildUsesCode($formattedCode);
408
        $formattedCode = $this->buildCommentsCode($formattedCode);
409
410
        // Add previously generated code
411
        $formattedCode[] = $this->buildDefinition();
412
        $formattedCode[] = '{';
413
414
        $indentationString = $this->indentation($indentation);
415
        $innerIndentation = $this->indentation(1);
416
417
        $formattedCode = $this->buildTraitsCode($formattedCode, $innerIndentation);
418
        $formattedCode = $this->buildConstantsCode($formattedCode);
419
        $formattedCode = $this->buildPropertiesCode($formattedCode);
420
        $formattedCode = $this->buildMethodsCode($formattedCode);
421
422
        $formattedCode[] = '}';
423
424
        return implode("\n" . $indentationString, $formattedCode);
425
    }
426
427
    /**
428
     * Build class definition.
429
     *
430
     * @return string Function definition
431
     */
432
    protected function buildDefinition()
433
    {
434
        return ($this->isFinal ? 'final ' : '') .
435
        ($this->isAbstract ? 'abstract ' : '') .
436
        'class ' .
437
        $this->className .
438
        ($this->parentClassName ? ' extends ' . $this->parentClassName : '') .
439
        (count($this->interfaces) ? rtrim(' implements ' . implode(', ', $this->interfaces), ', ') : '');
440
    }
441
}
442