Completed
Push — master ( 1b23d9...6d07d8 )
by Vitaly
02:46 queued 11s
created

ClassGenerator::buildDefinition()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 7
nc 16
nop 0
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
/**
9
 * Class generator class.
10
 *
11
 * @author Vitaly Egorov <[email protected]>
12
 */
13
class ClassGenerator extends AbstractGenerator
14
{
15
    use AbstractFinalTrait;
16
17
    /** OOP public visibility */
18
    const VISIBILITY_PUBLIC = 'public';
19
20
    /** OOP protected visibility */
21
    const VISIBILITY_PROTECTED = 'protected';
22
23
    /** OOP private visibility */
24
    const VISIBILITY_PRIVATE = 'private';
25
26
    /** @var string Class name */
27
    protected $className;
28
29
    /** @var string Parent class name */
30
    protected $parentClassName;
31
32
    /** @var string Class namespace */
33
    protected $namespace;
34
35
    /** @var array Collection of class uses */
36
    protected $uses = [];
37
38
    /** @var array Collection of class interfaces */
39
    protected $interfaces = [];
40
41
    /** @var array Collection of class used traits */
42
    protected $traits = [];
43
44
    /** @var string Multi-line file description */
45
    protected $fileDescription;
46
47
    /**
48
     * ClassGenerator constructor.
49
     *
50
     * @param string           $className Class name
51
     * @param AbstractGenerator $parent    Parent generator
52
     */
53
    public function __construct(string $className, AbstractGenerator $parent = null)
54
    {
55
        $this->className = $className;
56
57
        parent::__construct($parent);
58
    }
59
60
    /**
61
     * Set class file description.
62
     *
63
     * @param array $description Collection of class file description lines
64
     *
65
     * @return ClassGenerator
66
     */
67
    public function defDescription(array $description) : ClassGenerator
68
    {
69
        $commentsGenerator = new CommentsGenerator($this);
70
        foreach ($description as $line) {
71
            $commentsGenerator->defLine($line);
72
        }
73
74
        $this->fileDescription = $commentsGenerator->code();
75
76
        return $this;
77
    }
78
79
    /**
80
     * Set class namespace.
81
     *
82
     * @param string $namespace
83
     *
84
     * @return ClassGenerator
85
     */
86
    public function defNamespace(string $namespace) : ClassGenerator
87
    {
88
        $this->namespace = $namespace;
89
90
        return $this;
91
    }
92
93
    /**
94
     * Set class use.
95
     *
96
     * @param string $use Use class name
97
     * @param string $alias Use class name
98
     *
99
     * @return ClassGenerator
100
     */
101
    public function defUse(string $use, string $alias = null) : ClassGenerator
102
    {
103
        // Store the alias of class
104
        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...
105
            $this->uses[$alias] = $use;
106
        } else {
107
            $this->uses[] = $use;
108
        }
109
110
        return $this;
111
    }
112
113
    /**
114
     * Set parent class.
115
     *
116
     * @param string $className Parent class name
117
     *
118
     * @return ClassGenerator
119
     */
120
    public function defExtends(string $className) : ClassGenerator
121
    {
122
        $this->parentClassName = $className;
123
124
        return $this;
125
    }
126
127
    /**
128
     * Set implements interfaces.
129
     *
130
     * @param string $interfaceName Interface name
131
     *
132
     * @return ClassGenerator
133
     */
134
    public function defImplements(string $interfaceName) : ClassGenerator
135
    {
136
        $this->interfaces[] = $interfaceName;
137
138
        return $this;
139
    }
140
141
    /**
142
     * Set class trait use.
143
     *
144
     * @param string $trait Trait class name
145
     *
146
     * @return ClassGenerator
147
     */
148
    public function defTrait(string $trait) : ClassGenerator
149
    {
150
        $this->traits[] = $trait;
151
152
        return $this;
153
    }
154
155
    /**
156
     * Set protected class property.
157
     *
158
     * @param string $name        Property name
159
     * @param string $type        Property type
160
     * @param mixed  $value       Property value
161
     * @param string $description Property description
162
     *
163
     * @return PropertyGenerator
164
     */
165
    public function defProtectedProperty(string $name, string $type, $value, string $description = null) : PropertyGenerator
166
    {
167
        return $this->defProperty($name, $type, $value, $description)->defProtected();
168
    }
169
170
    /**
171
     * Set class property.
172
     *
173
     * @param string $name        Property name
174
     * @param string $type        Property type
175
     * @param mixed  $value       Property value
176
     * @param string $description Property description
177
     *
178
     * @return PropertyGenerator
179
     */
180
    public function defProperty(string $name, string $type, $value = null, string $description = null) : PropertyGenerator
181
    {
182
        return (new PropertyGenerator($name, $value, $this))
183
            ->setIndentation($this->indentation)
184
            ->increaseIndentation()
185
            ->defComment()
186
            ->defVar($type, $description)
187
            ->end();
188
    }
189
190
    /**
191
     * Set protected static class property.
192
     *
193
     * @param string $name        Property name
194
     * @param string $type        Property type
195
     * @param mixed  $value       Property value
196
     * @param string $description Property description
197
     *
198
     * @return PropertyGenerator
199
     */
200
    public function defProtectedStaticProperty(string $name, string $type, $value, string $description = null) : PropertyGenerator
201
    {
202
        return $this->defStaticProperty($name, $type, $value, $description)->defProtected();
203
    }
204
205
    /**
206
     * Set static class property.
207
     *
208
     * @param string $name        Property name
209
     * @param string $type        Property type
210
     * @param mixed  $value       Property value
211
     * @param string $description Property description
212
     *
213
     * @return PropertyGenerator
214
     */
215
    public function defStaticProperty(string $name, string $type, $value, string $description = null) : PropertyGenerator
216
    {
217
        return $this->defProperty($name, $type, $value, $description)->defStatic();
218
    }
219
220
    /**
221
     * Set protected class method.
222
     *
223
     * @param string $name Method name
224
     *
225
     * @return MethodGenerator
226
     */
227
    public function defProtectedMethod(string $name) : MethodGenerator
228
    {
229
        return $this->defMethod($name)->defProtected();
230
    }
231
232
    /**
233
     * Set public class method.
234
     *
235
     * @param string $name Method name
236
     *
237
     * @return MethodGenerator
238
     */
239
    public function defMethod(string $name) : MethodGenerator
240
    {
241
        return (new MethodGenerator($name, $this))->setIndentation($this->indentation)->increaseIndentation();
242
    }
243
244
    /**
245
     * Set protected static class method.
246
     *
247
     * @param string $name Method name
248
     *
249
     * @return MethodGenerator
250
     */
251
    public function defProtectedStaticMethod(string $name) : MethodGenerator
252
    {
253
        return $this->defStaticMethod($name)->defProtected();
254
    }
255
256
    /**
257
     * Set public static class method.
258
     *
259
     * @param string $name Method name
260
     *
261
     * @return MethodGenerator
262
     */
263
    public function defStaticMethod(string $name) : MethodGenerator
264
    {
265
        return $this->defMethod($name)->defStatic();
266
    }
267
268
    /**
269
     * Set class constant.
270
     *
271
     * @param string $name
272
     * @param mixed $value
273
     *
274
     * @return $this|ClassConstantGenerator
275
     */
276
    public function defConstant(string $name, $value, string $type, string $description) : ClassConstantGenerator
277
    {
278
        return (new ClassConstantGenerator($name, $value, $this))
279
            ->setIndentation($this->indentation)
280
            ->increaseIndentation()
281
            ->defComment()
282
                ->defLine($type.' '.$description)
283
            ->end();
284
    }
285
286
    protected function buildUsesCode(array $formattedCode) : array
287
    {
288
        // Add uses
289
        foreach ($this->uses as $alias => $use) {
290
            $formattedCode[] = 'use ' . $use . (is_string($alias) ? ' as ' . $alias : '') . ';';
291
        }
292
293
        // One empty line after uses if we have them
294
        if (count($this->uses)) {
295
            $formattedCode[] = '';
296
        }
297
298
        return $formattedCode;
299
    }
300
301
    protected function buildCommentsCode(array $formattedCode) : array
302
    {
303
        // Add comments
304
        if (array_key_exists(CommentsGenerator::class, $this->generatedCode)) {
305
            $formattedCode[] = $this->generatedCode[CommentsGenerator::class];
306
        }
307
308
        return $formattedCode;
309
    }
310
311
    protected function buildTraitsCode(array $formattedCode, string $innerIndentation) : array
312
    {
313
        // Add traits
314
        foreach ($this->traits as $trait) {
315
            $formattedCode[] = $innerIndentation . 'use ' . $trait . ';';
316
        }
317
318
        // One empty line after traits if we have them
319
        if (count($this->traits)) {
320
            $formattedCode[] = '';
321
        }
322
323
        return $formattedCode;
324
    }
325
326
    protected function buildFileDescriptionCode(array $formattedCode) : array
327
    {
328
        // Prepend file description if present
329
        if ($this->fileDescription !== null) {
330
            array_unshift($formattedCode, $this->fileDescription);
331
        }
332
333
        return $formattedCode;
334
    }
335
336
    protected function buildConstantsCode(array $formattedCode) : array
337
    {
338
        // Add constants
339
        if (array_key_exists(ClassConstantGenerator::class, $this->generatedCode)) {
340
            $formattedCode[] = $this->generatedCode[ClassConstantGenerator::class];
341
        }
342
343
        return $formattedCode;
344
    }
345
346
    protected function buildPropertiesCode(array $formattedCode) : array
347
    {
348
        if (array_key_exists(PropertyGenerator::class, $this->generatedCode)) {
349
            $formattedCode[] = $this->generatedCode[PropertyGenerator::class];
350
        }
351
352
        return $formattedCode;
353
    }
354
355
    protected function buildMethodsCode(array $formattedCode) : array
356
    {
357
        if (array_key_exists(MethodGenerator::class, $this->generatedCode)) {
358
            $formattedCode[] = $this->generatedCode[MethodGenerator::class];
359
        }
360
361
        return $formattedCode;
362
    }
363
364
    protected function buildNamespaceCode(array $formattedCode = []) : array
365
    {
366
        if ($this->namespace === null) {
367
            throw new \InvalidArgumentException('Class namespace should be defined');
368
        }
369
370
        $formattedCode[] = 'namespace ' . $this->namespace . ';';
371
372
        // One empty line after namespace
373
        $formattedCode[] = '';
374
375
        return $formattedCode;
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     * @throws \InvalidArgumentException
381
     */
382
    public function code(int $indentation = 0) : string
383
    {
384
        $formattedCode = $this->buildNamespaceCode();
385
        $formattedCode = $this->buildFileDescriptionCode($formattedCode);
386
        $formattedCode = $this->buildUsesCode($formattedCode);
387
        $formattedCode = $this->buildCommentsCode($formattedCode);
388
389
        // Add previously generated code
390
        $formattedCode[] = $this->buildDefinition();
391
        $formattedCode[] = '{';
392
393
        $indentationString = $this->indentation($indentation);
394
        $innerIndentation = $this->indentation(1);
395
396
        $formattedCode = $this->buildTraitsCode($formattedCode, $innerIndentation);
397
        $formattedCode = $this->buildConstantsCode($formattedCode);
398
        $formattedCode = $this->buildPropertiesCode($formattedCode);
399
        $formattedCode = $this->buildMethodsCode($formattedCode);
400
401
        $formattedCode[] = '}';
402
403
        return implode("\n" . $indentationString, $formattedCode);
404
    }
405
406
    /**
407
     * Build class definition.
408
     *
409
     * @return string Function definition
410
     */
411
    protected function buildDefinition()
412
    {
413
        return ($this->isFinal ? 'final ' : '') .
414
        ($this->isAbstract ? 'abstract ' : '') .
415
        'class ' .
416
        $this->className .
417
        ($this->parentClassName ? ' extends ' . $this->parentClassName : '') .
418
        (count($this->interfaces) ? rtrim(' implements ' . implode(', ', $this->interfaces), ', ') : '');
419
    }
420
}
421