Completed
Push — master ( d56900...650414 )
by Vitaly
02:50
created

ClassGenerator::code()   C

Complexity

Conditions 7
Paths 33

Size

Total Lines 46
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 46
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 20
nc 33
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 samsonphp\generator;
7
8
/**
9
 * Class generator class.
10
 *
11
 * @author Vitaly Egorov <[email protected]>
12
 */
13
class ClassGenerator extends AbstractGenerator
14
{
15
    /** OOP public visibility */
16
    const VISIBILITY_PUBLIC = 'public';
17
18
    /** OOP protected visibility */
19
    const VISIBILITY_PROTECTED = 'protected';
20
21
    /** OOP private visibility */
22
    const VISIBILITY_PRIVATE = 'private';
23
24
    /** @var string Class name */
25
    protected $className;
26
27
    /** @var string Class namespace */
28
    protected $namespace;
29
30
    /** @var array Collection of class uses */
31
    protected $uses = [];
32
33
    /** @var string Multiline file description */
34
    protected $fileDescription;
35
36
    /** @var array Class constants */
37
    protected $constants;
38
39
    /** @var array Class static properties */
40
    protected $staticProperties;
41
42
    /** @var array Class static methods */
43
    protected $staticMethods;
44
45
    /** @var array Class properties */
46
    protected $properties;
47
48
    /** @var array Class methods */
49
    protected $methods;
50
51
    /** @var bool Flag that class is abstract */
52
    protected $isAbstract;
53
54
    /** @var bool Flag that class is final */
55
    protected $isFinal;
56
57
    /**
58
     * ClassGenerator constructor.
59
     *
60
     * @param string           $className Class name
61
     * @param GenericGenerator $parent    Parent generator
62
     */
63
    public function __construct(string $className, GenericGenerator $parent = null)
64
    {
65
        $this->className = $className;
66
67
        parent::__construct($parent);
68
    }
69
70
    /**
71
     * Set class to be final.
72
     *
73
     * @return ClassGenerator
74
     */
75
    public function defFinal() : ClassGenerator
76
    {
77
        if ($this->isAbstract) {
78
            throw new \InvalidArgumentException('Class cannot be final as it is already abstract');
79
        }
80
81
        $this->isFinal = true;
82
83
        return $this;
84
    }
85
86
    /**
87
     * Set class to be abstract.
88
     *
89
     * @return ClassGenerator
90
     */
91
    public function defAbstract() : ClassGenerator
92
    {
93
        if ($this->isFinal) {
94
            throw new \InvalidArgumentException('Class cannot be abstract as it is already final');
95
        }
96
97
        $this->isAbstract = true;
98
99
        return $this;
100
    }
101
102
    /**
103
     * Set class file description.
104
     *
105
     * @param array $description Collection of class file description lines
106
     *
107
     * @return ClassGenerator
108
     */
109
    public function defDescription(array $description) : ClassGenerator
110
    {
111
        $commentsGenerator = new CommentsGenerator($this);
112
        foreach ($description as $line) {
113
            $commentsGenerator->defLine($line);
114
        }
115
116
        $this->fileDescription = $commentsGenerator->code();
117
118
        return $this;
119
    }
120
121
    /**
122
     * Set class namespace.
123
     *
124
     * @param string $namespace
125
     *
126
     * @return ClassGenerator
127
     */
128
    public function defNamespace(string $namespace) : ClassGenerator
129
    {
130
        $this->namespace = $namespace;
131
132
        return $this;
133
    }
134
135
    /**
136
     * Set class use.
137
     *
138
     * @param string $use
139
     *
140
     * @return ClassGenerator
141
     */
142
    public function defUse(string $use) : ClassGenerator
143
    {
144
        $this->uses[] = $use;
145
146
        return $this;
147
    }
148
149
    /**
150
     * Set protected class property.
151
     *
152
     * @param string $name Property name
153
     * @param mixed $value Property value
154
     *
155
     * @return PropertyGenerator
156
     */
157
    public function defProtectedProperty(string $name, $value) : PropertyGenerator
158
    {
159
        return $this->defProperty($name, $value)->defProtected();
160
    }
161
162
    /**
163
     * Set class property.
164
     *
165
     * @param string $name Property name
166
     * @param mixed $value Property value
167
     *
168
     * @return PropertyGenerator
169
     */
170
    public function defProperty(string $name, $value) : PropertyGenerator
171
    {
172
        return new PropertyGenerator($name, $value, $this);
173
    }
174
175
    /**
176
     * Set protected static class property.
177
     *
178
     * @param string $name Property name
179
     * @param mixed $value Property value
180
     *
181
     * @return PropertyGenerator
182
     */
183
    public function defProtectedStaticProperty(string $name, $value) : PropertyGenerator
184
    {
185
        return $this->defStaticProperty($name, $value)->defProtected();
186
    }
187
188
    /**
189
     * Set static class property.
190
     *
191
     * @param string $name Property name
192
     * @param mixed $value Property value
193
     *
194
     * @return PropertyGenerator
195
     */
196
    public function defStaticProperty(string $name, $value) : PropertyGenerator
197
    {
198
        return $this->defProperty($name, $value)->defStatic();
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     * @throws \InvalidArgumentException
204
     */
205
    public function code(int $indentation = 0) : string
206
    {
207
        if ($this->namespace === null) {
208
            throw new \InvalidArgumentException('Class namespace should be defined');
209
        }
210
211
        $formattedCode = ['namespace ' . $this->namespace . ';'];
212
213
        // One empty line after namespace
214
        $formattedCode[] = '';
215
216
        // Add uses
217
        foreach ($this->uses as $use) {
218
            $formattedCode[] = 'use ' . $use . ';';
219
        }
220
221
        // One empty line after uses if we have them
222
        if (count($this->uses)) {
223
            $formattedCode[] = '';
224
        }
225
226
        // Add comments
227
        if (array_key_exists(CommentsGenerator::class, $this->generatedCode)) {
228
            $formattedCode[] = $this->generatedCode[CommentsGenerator::class];
229
        }
230
231
        // Add previously generated code
232
        $formattedCode[] = $this->buildDefinition();
233
        $formattedCode[] = '{';
234
235
        // Prepend file description if present
236
        if ($this->fileDescription !== null) {
237
            array_unshift($formattedCode, $this->fileDescription);
238
        }
239
240
        // Add properties
241
        if (array_key_exists(PropertyGenerator::class, $this->generatedCode)) {
242
            $formattedCode[] = $this->indentation($indentation + 1) . $this->generatedCode[PropertyGenerator::class];
243
        }
244
245
        $formattedCode[] = '}';
246
247
        $code = implode("\n" . $this->indentation($indentation), $formattedCode);
248
249
        return $code;
250
    }
251
252
    /**
253
     * Build function definition.
254
     *
255
     * @return string Function definition
256
     */
257
    protected function buildDefinition()
258
    {
259
        return ($this->isFinal ? 'final ' : '') .
260
        ($this->isAbstract ? 'abstract ' : '') .
261
        'class ' .
262
        $this->className;
263
    }
264
}
265