1 | <?php declare(strict_types=1); |
||
34 | use DocblockPart; |
||
35 | use LongDescriptionPart; |
||
36 | use QualifiedNamePart; |
||
37 | |||
38 | /** @var Map */ |
||
39 | private Map $useStatements; |
||
|
|||
40 | |||
41 | /** @var Set */ |
||
42 | private Set $requiredFiles; |
||
43 | |||
44 | /** @var Map */ |
||
45 | private Map $methods; |
||
46 | |||
47 | /** |
||
48 | * Creates a new struct |
||
49 | * |
||
50 | * @param string $name the fqcn |
||
51 | * |
||
52 | * @return static |
||
53 | */ |
||
54 | public static function create(string $name = ''): self { |
||
55 | 13 | return new static($name); |
|
56 | 13 | } |
|
57 | |||
58 | /** |
||
59 | * Creates a new struct |
||
60 | * |
||
61 | * @param string $name the fqcn |
||
62 | */ |
||
63 | public function __construct(string $name = '') { |
||
64 | 56 | $this->setQualifiedName($name); |
|
65 | 56 | $this->docblock = new Docblock(); |
|
66 | 56 | $this->useStatements = new Map(); |
|
67 | 56 | $this->requiredFiles = new Set(); |
|
68 | 56 | $this->methods = new Map(); |
|
69 | 56 | } |
|
70 | 56 | ||
71 | /** |
||
72 | * Sets requried files |
||
73 | * |
||
74 | * @param array|Set $files |
||
75 | * |
||
76 | * @return $this |
||
77 | */ |
||
78 | 1 | public function setRequiredFiles(array|Set $files): self { |
|
79 | 1 | $this->requiredFiles = is_array($files) ? new Set($files) : $files; |
|
80 | |||
81 | 1 | return $this; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * Adds a new required file |
||
86 | * |
||
87 | * @param string $file |
||
88 | * |
||
89 | * @return $this |
||
90 | 2 | */ |
|
91 | 2 | public function addRequiredFile(string $file): self { |
|
92 | $this->requiredFiles->add($file); |
||
93 | 2 | ||
94 | return $this; |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Returns required files |
||
99 | * |
||
100 | * @return Set collection of filenames |
||
101 | 17 | */ |
|
102 | 17 | public function getRequiredFiles(): Set { |
|
103 | return $this->requiredFiles; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Sets use statements |
||
108 | * |
||
109 | * @see #addUseStatement |
||
110 | * @see #declareUses() |
||
111 | * |
||
112 | * @param array $useStatements |
||
113 | 1 | * |
|
114 | 1 | * @return $this |
|
115 | 1 | */ |
|
116 | 1 | public function setUseStatements(array $useStatements): self { |
|
117 | $this->useStatements->clear(); |
||
118 | foreach ($useStatements as $alias => $useStatement) { |
||
119 | 1 | $this->addUseStatement($useStatement, $alias); |
|
120 | } |
||
121 | |||
122 | return $this; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Adds a use statement with an optional alias |
||
127 | * |
||
128 | * @param string $qualifiedName |
||
129 | 5 | * @param string $alias |
|
130 | 5 | * |
|
131 | 4 | * @return $this |
|
132 | 2 | */ |
|
133 | public function addUseStatement(string $qualifiedName, string $alias = ''): self { |
||
134 | 4 | if ($alias === '') { |
|
135 | $alias = str_contains($qualifiedName, '\\') ? |
||
136 | substr($qualifiedName, strrpos($qualifiedName, '\\') + 1) : $qualifiedName; |
||
137 | } |
||
138 | 5 | ||
139 | $this->useStatements->set($alias, $qualifiedName); |
||
140 | 5 | ||
141 | return $this; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Clears all use statements |
||
146 | * |
||
147 | * @return $this |
||
148 | 1 | */ |
|
149 | 1 | public function clearUseStatements(): self { |
|
150 | $this->useStatements->clear(); |
||
151 | 1 | ||
152 | return $this; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Declares multiple use statements at once. |
||
157 | * |
||
158 | * @param string ...$uses use statements multiple qualified names |
||
159 | * |
||
160 | 1 | * @return $this |
|
161 | 1 | */ |
|
162 | 1 | public function declareUses(string ...$uses): self { |
|
163 | foreach ($uses as $name) { |
||
164 | 1 | $this->declareUse($name); |
|
165 | } |
||
166 | |||
167 | return $this; |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * Declares a "use $fullClassName" with " as $alias" if $alias is available, |
||
172 | * and returns its alias (or not qualified classname) to be used in your actual |
||
173 | * php code. |
||
174 | * |
||
175 | * If the class has already been declared you get only the set alias. |
||
176 | * |
||
177 | * @param string $qualifiedName |
||
178 | 1 | * @param string $alias |
|
179 | 1 | * |
|
180 | 1 | * @return string the used alias |
|
181 | 1 | */ |
|
182 | public function declareUse(string $qualifiedName, string $alias = ''): string { |
||
183 | 1 | $qualifiedName = trim($qualifiedName, '\\'); |
|
184 | if (!$this->hasUseStatement($qualifiedName)) { |
||
185 | $this->addUseStatement($qualifiedName, $alias); |
||
186 | } |
||
187 | |||
188 | return $this->getUseAlias($qualifiedName); |
||
189 | } |
||
190 | |||
191 | /** |
||
192 | 3 | * Returns whether the given use statement is present |
|
193 | 3 | * |
|
194 | * @param string $qualifiedName |
||
195 | * |
||
196 | * @return bool |
||
197 | */ |
||
198 | public function hasUseStatement(string $qualifiedName): bool { |
||
199 | return $this->useStatements->contains($qualifiedName); |
||
200 | } |
||
201 | |||
202 | 1 | public function hasUseStatementsToRender(): bool { |
|
203 | 1 | if ($this->useStatements->isEmpty()) { |
|
204 | return false; |
||
205 | } |
||
206 | |||
207 | return $this->useStatements->search( |
||
208 | fn (string $stmt) => str_contains($stmt, '\\') || $this->getNamespace() !== '' |
||
209 | ); |
||
210 | } |
||
211 | |||
212 | 3 | /** |
|
213 | 3 | * Returns the usable alias for a qualified name |
|
214 | 3 | * |
|
215 | * @param string $qualifiedName |
||
216 | * |
||
217 | * @return string the alias |
||
218 | */ |
||
219 | public function getUseAlias(string $qualifiedName): string { |
||
220 | return $this->useStatements->getKey($qualifiedName) ?? ''; |
||
221 | } |
||
222 | 17 | ||
223 | 17 | /** |
|
224 | * Removes a use statement |
||
225 | * |
||
226 | * @param string $qualifiedName |
||
227 | * |
||
228 | * @return $this |
||
229 | */ |
||
230 | public function removeUseStatement(string $qualifiedName): self { |
||
231 | if ($this->useStatements->contains($qualifiedName)) { |
||
232 | 1 | $this->useStatements->remove($this->useStatements->getKey($qualifiedName)); |
|
233 | 1 | } |
|
234 | 1 | ||
235 | return $this; |
||
236 | } |
||
237 | 1 | ||
238 | 1 | /** |
|
239 | 1 | * Returns all use statements |
|
240 | * |
||
241 | * @return Map collection of use statements |
||
242 | 1 | */ |
|
243 | public function getUseStatements(): Map { |
||
244 | return $this->useStatements; |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Sets a collection of methods |
||
249 | * |
||
250 | * @param PhpMethod[] $methods |
||
251 | 15 | * |
|
252 | 15 | * @return $this |
|
253 | 15 | */ |
|
254 | public function setMethods(array $methods): self { |
||
255 | 15 | $this->clearMethods(); |
|
256 | foreach ($methods as $method) { |
||
257 | $this->setMethod($method); |
||
258 | } |
||
259 | |||
260 | return $this; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Adds a method |
||
265 | 2 | * |
|
266 | 2 | * @param PhpMethod $method |
|
267 | 1 | * |
|
268 | * @return $this |
||
269 | */ |
||
270 | 2 | public function setMethod(PhpMethod $method): self { |
|
271 | 1 | $method->setParent($this); |
|
272 | $this->methods->set($method->getName(), $method); |
||
273 | 1 | ||
274 | 1 | return $this; |
|
275 | 1 | } |
|
276 | |||
277 | 1 | /** |
|
278 | * Removes a method |
||
279 | * |
||
280 | * @param string|PhpMethod $nameOrMethod method name or Method instance |
||
281 | * |
||
282 | * @throws \InvalidArgumentException if the method cannot be found |
||
283 | * |
||
284 | * @return $this |
||
285 | */ |
||
286 | 2 | public function removeMethod(string|PhpMethod $nameOrMethod): self { |
|
287 | 2 | $name = (string) $nameOrMethod; |
|
288 | 1 | ||
289 | if (!$this->methods->has($name)) { |
||
290 | throw new \InvalidArgumentException("The method `$name` does not exist."); |
||
291 | 2 | } |
|
292 | $m = $this->methods->get($name); |
||
293 | $m->setParent(null); |
||
294 | $this->methods->remove($name); |
||
295 | |||
296 | return $this; |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Checks whether a method exists or not |
||
301 | 9 | * |
|
302 | 9 | * @param string|PhpMethod $nameOrMethod method name or Method instance |
|
303 | 1 | * |
|
304 | * @return bool `true` if it exists and `false` if not |
||
305 | */ |
||
306 | 9 | public function hasMethod(string|PhpMethod $nameOrMethod): bool { |
|
307 | 2 | return $this->methods->has((string) $nameOrMethod); |
|
308 | } |
||
309 | |||
310 | 8 | /** |
|
311 | * Returns a method |
||
312 | * |
||
313 | * @param string $name the methods name |
||
314 | * |
||
315 | * @throws \InvalidArgumentException if the method cannot be found |
||
316 | * |
||
317 | * @return PhpMethod |
||
318 | 17 | */ |
|
319 | 17 | public function getMethod(string $name): PhpMethod { |
|
320 | if (!$this->methods->has($name)) { |
||
321 | throw new \InvalidArgumentException("The method `$name` does not exist."); |
||
322 | } |
||
323 | |||
324 | return $this->methods->get($name); |
||
325 | } |
||
326 | |||
327 | 1 | /** |
|
328 | 1 | * Returns all methods |
|
329 | * |
||
330 | * @return Map collection of methods |
||
331 | */ |
||
332 | public function getMethods(): Map { |
||
333 | return $this->methods; |
||
334 | } |
||
335 | |||
336 | 1 | /** |
|
337 | 1 | * Returns all method names |
|
338 | 1 | * |
|
339 | * @return Set |
||
340 | 1 | */ |
|
341 | public function getMethodNames(): Set { |
||
342 | 1 | return $this->methods->keys(); |
|
343 | } |
||
344 | |||
345 | /** |
||
346 | * Clears all methods |
||
347 | * |
||
348 | * @return $this |
||
349 | */ |
||
350 | 11 | public function clearMethods(): self { |
|
351 | 11 | $this->methods->each(fn (string $key, PhpMethod $method) => $method->setParent(null)); |
|
352 | 11 | $this->methods->clear(); |
|
353 | 11 | ||
354 | return $this; |
||
355 | 11 | } |
|
356 | 7 | ||
357 | /** |
||
358 | * Generates a docblock from provided information |
||
359 | 11 | */ |
|
360 | public function generateDocblock(): void { |
||
361 | $docblock = $this->getDocblock(); |
||
362 | $docblock->setShortDescription($this->getDescription()); |
||
367 |