1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* Copyright 2011 Johannes M. Schmitt <[email protected]> |
4
|
|
|
* |
5
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
6
|
|
|
* you may not use this file except in compliance with the License. |
7
|
|
|
* You may obtain a copy of the License at |
8
|
|
|
* |
9
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
10
|
|
|
* |
11
|
|
|
* Unless required by applicable law or agreed to in writing, software |
12
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
13
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14
|
|
|
* See the License for the specific language governing permissions and |
15
|
|
|
* limitations under the License. |
16
|
|
|
*/ |
17
|
|
|
declare(strict_types=1); |
18
|
|
|
|
19
|
|
|
namespace gossi\codegen\model; |
20
|
|
|
|
21
|
|
|
use gossi\codegen\model\parts\DocblockPart; |
22
|
|
|
use gossi\codegen\model\parts\LongDescriptionPart; |
23
|
|
|
use gossi\codegen\model\parts\QualifiedNamePart; |
24
|
|
|
use gossi\codegen\utils\TypeUtils; |
25
|
|
|
use gossi\docblock\Docblock; |
26
|
|
|
use phootwork\collection\Map; |
27
|
|
|
use phootwork\collection\Set; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Represents an abstract php structure (class, trait or interface). |
31
|
|
|
* |
32
|
|
|
* @author Johannes M. Schmitt <[email protected]> |
33
|
|
|
* @author Thomas Gossmann |
34
|
|
|
*/ |
35
|
|
|
abstract class AbstractPhpStruct extends AbstractModel implements NamespaceInterface, DocblockInterface { |
36
|
|
|
|
37
|
|
|
use DocblockPart; |
38
|
|
|
use LongDescriptionPart; |
39
|
|
|
use QualifiedNamePart; |
40
|
|
|
|
41
|
|
|
/** @var Map|string[] */ |
42
|
|
|
private $useStatements; |
43
|
|
|
|
44
|
|
|
/** @var Set|string[] */ |
45
|
|
|
private $requiredFiles; |
46
|
|
|
|
47
|
|
|
/** @var Map|PhpMethod[] */ |
48
|
|
|
private $methods; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Creates a new struct |
52
|
|
|
* |
53
|
|
|
* @param string $name the fqcn |
54
|
|
|
* @return static |
55
|
|
|
*/ |
56
|
13 |
|
public static function create(?string $name = null) { |
57
|
13 |
|
return new static($name); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
public static function fromName(string $name): self |
61
|
|
|
{ |
62
|
|
|
$ref = new \ReflectionClass($name); |
63
|
|
|
|
64
|
|
|
return static::fromFile($ref->getFileName()); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Creates a new struct |
69
|
|
|
* |
70
|
|
|
* @param string $name the fqcn |
71
|
|
|
*/ |
72
|
57 |
|
public function __construct(?string $name = null) { |
73
|
57 |
|
$this->setQualifiedName($name); |
74
|
57 |
|
$this->docblock = new Docblock(); |
75
|
57 |
|
$this->useStatements = new Map(); |
76
|
57 |
|
$this->requiredFiles = new Set(); |
77
|
57 |
|
$this->methods = new Map(); |
78
|
57 |
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Sets requried files |
82
|
|
|
* |
83
|
|
|
* @param array $files |
84
|
|
|
* @return $this |
85
|
|
|
*/ |
86
|
1 |
|
public function setRequiredFiles(array $files) { |
87
|
1 |
|
$this->requiredFiles = new Set($files); |
88
|
|
|
|
89
|
1 |
|
return $this; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Adds a new required file |
94
|
|
|
* |
95
|
|
|
* @param string $file |
96
|
|
|
* @return $this |
97
|
|
|
*/ |
98
|
2 |
|
public function addRequiredFile(string $file) { |
99
|
2 |
|
$this->requiredFiles->add($file); |
100
|
|
|
|
101
|
2 |
|
return $this; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Returns required files |
106
|
|
|
* |
107
|
|
|
* @return Set collection of filenames |
108
|
|
|
*/ |
109
|
17 |
|
public function getRequiredFiles(): Set { |
110
|
17 |
|
return $this->requiredFiles; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Sets use statements |
115
|
|
|
* |
116
|
|
|
* @see #addUseStatement |
117
|
|
|
* @see #declareUses() |
118
|
|
|
* @param array $useStatements |
119
|
|
|
* @return $this |
120
|
|
|
*/ |
121
|
1 |
|
public function setUseStatements(array $useStatements) { |
122
|
1 |
|
$this->useStatements->clear(); |
123
|
1 |
|
foreach ($useStatements as $alias => $useStatement) { |
124
|
1 |
|
$this->addUseStatement($useStatement, $alias); |
125
|
|
|
} |
126
|
|
|
|
127
|
1 |
|
return $this; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Adds a use statement with an optional alias |
132
|
|
|
* |
133
|
|
|
* @param string|PhpTypeInterface $qualifiedName |
134
|
|
|
* @param null|string $alias |
135
|
|
|
* @return $this |
136
|
|
|
*/ |
137
|
13 |
|
public function addUseStatement($qualifiedName, string $alias = null) { |
138
|
13 |
|
if ($qualifiedName instanceof PhpTypeInterface) { |
139
|
8 |
|
$qualifiedName = $qualifiedName->getQualifiedName(); |
140
|
|
|
} |
141
|
|
|
|
142
|
13 |
|
if (TypeUtils::isGlobalQualifiedName($qualifiedName) || TypeUtils::isNativeType($qualifiedName)) { |
143
|
7 |
|
return $this; |
144
|
|
|
} |
145
|
|
|
|
146
|
7 |
|
if ($qualifiedName === $this->getNamespace()) { |
147
|
|
|
return $this; |
148
|
|
|
} |
149
|
7 |
|
if (!is_string($alias)) { |
150
|
6 |
|
if (false === strpos($qualifiedName, '\\')) { |
151
|
2 |
|
$alias = $qualifiedName; |
152
|
|
|
} else { |
153
|
6 |
|
$alias = substr($qualifiedName, strrpos($qualifiedName, '\\') + 1); |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
7 |
|
$this->useStatements->set($alias, $qualifiedName); |
158
|
|
|
|
159
|
7 |
|
return $this; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Clears all use statements |
164
|
|
|
* |
165
|
|
|
* @return $this |
166
|
|
|
*/ |
167
|
1 |
|
public function clearUseStatements() { |
168
|
1 |
|
$this->useStatements->clear(); |
169
|
|
|
|
170
|
1 |
|
return $this; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Declares multiple use statements at once. |
175
|
|
|
* |
176
|
|
|
* @param ... use statements multiple qualified names |
177
|
|
|
* @return $this |
178
|
|
|
*/ |
179
|
1 |
|
public function declareUses(string ...$uses) { |
180
|
1 |
|
foreach ($uses as $name) { |
181
|
1 |
|
$this->declareUse($name); |
182
|
|
|
} |
183
|
1 |
|
return $this; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Declares a "use $fullClassName" with " as $alias" if $alias is available, |
188
|
|
|
* and returns its alias (or not qualified classname) to be used in your actual |
189
|
|
|
* php code. |
190
|
|
|
* |
191
|
|
|
* If the class has already been declared you get only the set alias. |
192
|
|
|
* |
193
|
|
|
* @param string $qualifiedName |
194
|
|
|
* @param null|string $alias |
195
|
|
|
* @return string the used alias |
196
|
|
|
*/ |
197
|
1 |
|
public function declareUse(string $qualifiedName, string $alias = null) { |
198
|
1 |
|
$qualifiedName = trim($qualifiedName, '\\'); |
199
|
1 |
|
if (!$this->hasUseStatement($qualifiedName)) { |
200
|
1 |
|
$this->addUseStatement($qualifiedName, $alias); |
201
|
|
|
} |
202
|
1 |
|
return $this->getUseAlias($qualifiedName); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Returns whether the given use statement is present |
207
|
|
|
* |
208
|
|
|
* @param string $qualifiedName |
209
|
|
|
* @return bool |
210
|
|
|
*/ |
211
|
3 |
|
public function hasUseStatement(string $qualifiedName): bool { |
212
|
3 |
|
return $this->useStatements->contains($qualifiedName); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Returns the usable alias for a qualified name |
217
|
|
|
* |
218
|
|
|
* @param string $qualifiedName |
219
|
|
|
* @return string the alias |
220
|
|
|
*/ |
221
|
1 |
|
public function getUseAlias(string $qualifiedName): string { |
222
|
1 |
|
return $this->useStatements->getKey($qualifiedName); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Removes a use statement |
227
|
|
|
* |
228
|
|
|
* @param string $qualifiedName |
229
|
|
|
* @return $this |
230
|
|
|
*/ |
231
|
3 |
|
public function removeUseStatement(string $qualifiedName) { |
232
|
3 |
|
$this->useStatements->remove($this->useStatements->getKey($qualifiedName)); |
233
|
3 |
|
return $this; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* Returns all use statements |
238
|
|
|
* |
239
|
|
|
* @return Map collection of use statements |
240
|
|
|
*/ |
241
|
20 |
|
public function getUseStatements(): Map { |
242
|
20 |
|
return $this->useStatements; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Sets a collection of methods |
247
|
|
|
* |
248
|
|
|
* @param PhpMethod[] $methods |
249
|
|
|
* @return $this |
250
|
|
|
*/ |
251
|
1 |
|
public function setMethods(array $methods) { |
252
|
1 |
|
foreach ($this->methods as $method) { |
253
|
1 |
|
$method->setParent(null); |
254
|
|
|
} |
255
|
|
|
|
256
|
1 |
|
$this->methods->clear(); |
257
|
1 |
|
foreach ($methods as $method) { |
258
|
1 |
|
$this->addMethod($method); |
259
|
|
|
} |
260
|
|
|
|
261
|
1 |
|
return $this; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Adds a method |
266
|
|
|
* |
267
|
|
|
* @param PhpMethod $method |
268
|
|
|
* @return $this |
269
|
|
|
*/ |
270
|
16 |
|
public function addMethod(PhpMethod $method) { |
271
|
16 |
|
$method->setParent($this); |
272
|
16 |
|
$this->methods->set($method->getName(), $method); |
273
|
16 |
|
$types = $method->getTypes(); |
274
|
16 |
|
if ($types) { |
275
|
16 |
|
foreach ($types as $type) { |
276
|
4 |
|
$this->addUseStatement($type); |
277
|
4 |
|
$method->addType($type); |
278
|
|
|
} |
279
|
|
|
} |
280
|
|
|
|
281
|
16 |
|
foreach ($method->getParameters() as $parameter) { |
282
|
11 |
|
$types = $parameter->getTypes(); |
283
|
11 |
|
if ($types) { |
|
|
|
|
284
|
11 |
|
foreach ($types as $type) { |
285
|
5 |
|
$this->addUseStatement($type); |
286
|
5 |
|
$parameter->addType($type); |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
|
291
|
16 |
|
return $this; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Removes a method |
296
|
|
|
* |
297
|
|
|
* @param string|PhpMethod $nameOrMethod method name or Method instance |
298
|
|
|
* @throws \InvalidArgumentException if the method cannot be found |
299
|
|
|
* @return $this |
300
|
|
|
*/ |
301
|
2 |
|
public function removeMethod($nameOrMethod) { |
302
|
2 |
|
if ($nameOrMethod instanceof PhpMethod) { |
303
|
1 |
|
$nameOrMethod = $nameOrMethod->getName(); |
304
|
|
|
} |
305
|
|
|
|
306
|
2 |
|
if (!$this->methods->has($nameOrMethod)) { |
307
|
1 |
|
throw new \InvalidArgumentException(sprintf('The method "%s" does not exist.', $nameOrMethod)); |
308
|
|
|
} |
309
|
1 |
|
$m = $this->methods->get($nameOrMethod); |
310
|
1 |
|
$m->setParent(null); |
311
|
1 |
|
$this->methods->remove($nameOrMethod); |
312
|
|
|
|
313
|
1 |
|
return $this; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Checks whether a method exists or not |
318
|
|
|
* |
319
|
|
|
* @param string|PhpMethod $nameOrMethod method name or Method instance |
320
|
|
|
* @return bool `true` if it exists and `false` if not |
321
|
|
|
*/ |
322
|
2 |
|
public function hasMethod($nameOrMethod): bool { |
323
|
2 |
|
if ($nameOrMethod instanceof PhpMethod) { |
324
|
1 |
|
$nameOrMethod = $nameOrMethod->getName(); |
325
|
|
|
} |
326
|
|
|
|
327
|
2 |
|
return $this->methods->has($nameOrMethod); |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Returns a method |
332
|
|
|
* |
333
|
|
|
* @param string $nameOrMethod the methods name |
334
|
|
|
* @throws \InvalidArgumentException if the method cannot be found |
335
|
|
|
* @return PhpMethod |
336
|
|
|
*/ |
337
|
10 |
|
public function getMethod($nameOrMethod): PhpMethod { |
338
|
10 |
|
if ($nameOrMethod instanceof PhpMethod) { |
339
|
1 |
|
$nameOrMethod = $nameOrMethod->getName(); |
340
|
|
|
} |
341
|
|
|
|
342
|
10 |
|
if (!$this->methods->has($nameOrMethod)) { |
343
|
2 |
|
throw new \InvalidArgumentException(sprintf('The method "%s" does not exist.', $nameOrMethod)); |
344
|
|
|
} |
345
|
|
|
|
346
|
9 |
|
return $this->methods->get($nameOrMethod); |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Returns all methods |
351
|
|
|
* |
352
|
|
|
* @return Map|PhpMethod[] collection of methods |
353
|
|
|
*/ |
354
|
17 |
|
public function getMethods(): Map { |
355
|
17 |
|
return $this->methods; |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* Returns all method names |
360
|
|
|
* |
361
|
|
|
* @return Set |
362
|
|
|
*/ |
363
|
1 |
|
public function getMethodNames(): Set { |
364
|
1 |
|
return $this->methods->keys(); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Clears all methods |
369
|
|
|
* |
370
|
|
|
* @return $this |
371
|
|
|
*/ |
372
|
1 |
|
public function clearMethods() { |
373
|
1 |
|
foreach ($this->methods as $method) { |
374
|
1 |
|
$method->setParent(null); |
375
|
|
|
} |
376
|
1 |
|
$this->methods->clear(); |
377
|
|
|
|
378
|
1 |
|
return $this; |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Generates a docblock from provided information |
383
|
|
|
* |
384
|
|
|
* @return $this |
385
|
|
|
*/ |
386
|
11 |
|
public function generateDocblock() { |
387
|
11 |
|
$docblock = $this->getDocblock(); |
388
|
11 |
|
$docblock->setShortDescription($this->getDescription()); |
389
|
11 |
|
$docblock->setLongDescription($this->getLongDescription()); |
390
|
|
|
|
391
|
11 |
|
foreach ($this->methods as $method) { |
392
|
7 |
|
$method->generateDocblock(); |
393
|
|
|
} |
394
|
|
|
|
395
|
11 |
|
return $this; |
396
|
|
|
} |
397
|
|
|
} |
398
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.