|
11 | 11 |
|
12 | 12 | use Nette;
|
13 | 13 | use PhpParser;
|
| 14 | +use PhpParser\Modifiers; |
14 | 15 | use PhpParser\Node;
|
15 | 16 | use PhpParser\NodeFinder;
|
16 | 17 | use PhpParser\ParserFactory;
|
@@ -323,14 +324,37 @@ private function addPropertyToClass(ClassLike $class, Node\Stmt\Property $node):
|
323 | 324 | foreach ($node->props as $item) {
|
324 | 325 | $prop = $class->addProperty($item->name->toString());
|
325 | 326 | $prop->setStatic($node->isStatic());
|
326 |
| - $prop->setVisibility($this->toVisibility($node->flags)); |
| 327 | + $prop->setVisibility($this->toVisibility($node->flags), $this->toSetterVisibility($node->flags)); |
327 | 328 | $prop->setType($node->type ? $this->toPhp($node->type) : null);
|
328 | 329 | if ($item->default) {
|
329 | 330 | $prop->setValue($this->toValue($item->default));
|
330 | 331 | }
|
331 | 332 |
|
332 | 333 | $prop->setReadOnly((method_exists($node, 'isReadonly') && $node->isReadonly()) || ($class instanceof ClassType && $class->isReadOnly()));
|
333 | 334 | $this->addCommentAndAttributes($prop, $node);
|
| 335 | + |
| 336 | + $prop->setAbstract((bool) ($node->flags & Node\Stmt\Class_::MODIFIER_ABSTRACT)); |
| 337 | + $prop->setFinal((bool) ($node->flags & Node\Stmt\Class_::MODIFIER_FINAL)); |
| 338 | + $this->addHooksToProperty($prop, $node); |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + |
| 343 | + private function addHooksToProperty(Property|PromotedParameter $prop, Node\Stmt\Property|Node\Param $node): void |
| 344 | + { |
| 345 | + if (!class_exists(Node\PropertyHook::class)) { |
| 346 | + return; |
| 347 | + } |
| 348 | + |
| 349 | + foreach ($node->hooks as $hookNode) { |
| 350 | + $hook = $prop->addHook($hookNode->name->toString()); |
| 351 | + $hook->setFinal((bool) ($hookNode->flags & Modifiers::FINAL)); |
| 352 | + $this->setupFunction($hook, $hookNode); |
| 353 | + if ($hookNode->body === null) { |
| 354 | + $hook->setAbstract(); |
| 355 | + } elseif (!is_array($hookNode->body)) { |
| 356 | + $hook->setBody($this->getReformattedContents([$hookNode->body], 1), short: true); |
| 357 | + } |
334 | 358 | }
|
335 | 359 | }
|
336 | 360 |
|
@@ -380,7 +404,7 @@ private function addFunctionToFile(PhpFile $phpFile, Node\Stmt\Function_ $node):
|
380 | 404 |
|
381 | 405 |
|
382 | 406 | private function addCommentAndAttributes(
|
383 |
| - PhpFile|ClassLike|Constant|Property|GlobalFunction|Method|Parameter|EnumCase|TraitUse $element, |
| 407 | + PhpFile|ClassLike|Constant|Property|GlobalFunction|Method|Parameter|EnumCase|TraitUse|PropertyHook $element, |
384 | 408 | Node $node,
|
385 | 409 | ): void
|
386 | 410 | {
|
@@ -408,19 +432,29 @@ private function addCommentAndAttributes(
|
408 | 432 | }
|
409 | 433 |
|
410 | 434 |
|
411 |
| - private function setupFunction(GlobalFunction|Method $function, Node\FunctionLike $node): void |
| 435 | + private function setupFunction(GlobalFunction|Method|PropertyHook $function, Node\FunctionLike $node): void |
412 | 436 | {
|
413 | 437 | $function->setReturnReference($node->returnsByRef());
|
414 |
| - $function->setReturnType($node->getReturnType() ? $this->toPhp($node->getReturnType()) : null); |
| 438 | + if (!$function instanceof PropertyHook) { |
| 439 | + $function->setReturnType($node->getReturnType() ? $this->toPhp($node->getReturnType()) : null); |
| 440 | + } |
| 441 | + |
415 | 442 | foreach ($node->getParams() as $item) {
|
416 |
| - $visibility = $this->toVisibility($item->flags); |
417 |
| - $isReadonly = (bool) ($item->flags & Node\Stmt\Class_::MODIFIER_READONLY); |
418 |
| - $param = $visibility |
419 |
| - ? ($function->addPromotedParameter($item->var->name))->setVisibility($visibility)->setReadonly($isReadonly) |
420 |
| - : $function->addParameter($item->var->name); |
| 443 | + $getVisibility = $this->toVisibility($item->flags); |
| 444 | + $setVisibility = $this->toSetterVisibility($item->flags); |
| 445 | + if ($getVisibility || $setVisibility) { |
| 446 | + $param = $function->addPromotedParameter($item->var->name) |
| 447 | + ->setVisibility($getVisibility, $setVisibility) |
| 448 | + ->setReadonly((bool) ($item->flags & Node\Stmt\Class_::MODIFIER_READONLY)); |
| 449 | + $this->addHooksToProperty($param, $item); |
| 450 | + } else { |
| 451 | + $param = $function->addParameter($item->var->name); |
| 452 | + } |
421 | 453 | $param->setType($item->type ? $this->toPhp($item->type) : null);
|
422 | 454 | $param->setReference($item->byRef);
|
423 |
| - $function->setVariadic($item->variadic); |
| 455 | + if (!$function instanceof PropertyHook) { |
| 456 | + $function->setVariadic($item->variadic); |
| 457 | + } |
424 | 458 | if ($item->default) {
|
425 | 459 | $param->setDefaultValue($this->toValue($item->default));
|
426 | 460 | }
|
@@ -491,6 +525,18 @@ private function toVisibility(int $flags): ?string
|
491 | 525 | }
|
492 | 526 |
|
493 | 527 |
|
| 528 | + private function toSetterVisibility(int $flags): ?string |
| 529 | + { |
| 530 | + return match (true) { |
| 531 | + !class_exists(Node\PropertyHook::class) => null, |
| 532 | + (bool) ($flags & Modifiers::PUBLIC_SET) => ClassType::VisibilityPublic, |
| 533 | + (bool) ($flags & Modifiers::PROTECTED_SET) => ClassType::VisibilityProtected, |
| 534 | + (bool) ($flags & Modifiers::PRIVATE_SET) => ClassType::VisibilityPrivate, |
| 535 | + default => null, |
| 536 | + }; |
| 537 | + } |
| 538 | + |
| 539 | + |
494 | 540 | private function toPhp(Node $value): string
|
495 | 541 | {
|
496 | 542 | $dolly = clone $value;
|
|
0 commit comments