Skip to content

Commit

Permalink
feat: improve the rector so that it examines traits too
Browse files Browse the repository at this point in the history
refs #0 @0m
  • Loading branch information
Naugrimm committed Jun 18, 2024
1 parent f3de519 commit d8d9ade
Showing 1 changed file with 77 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

namespace Utils\Rector\Rector;

use Exception;
use Naugrim\BMEcat\Nodes\Concerns\HasSerializableAttributes;
use Naugrim\BMEcat\Nodes\Contact\Details;
use Naugrim\BMEcat\Nodes\Contracts\NodeInterface;
use Naugrim\BMEcat\Nodes\Crypto\PublicKey;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\PhpParser\AstResolver;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
Expand Down Expand Up @@ -85,6 +87,10 @@ class Address implements NodeInterface
]);
}

public function __construct(private AstResolver $astResolver)
{
}

/**
* @return array<class-string<Node>>
*/
Expand All @@ -95,6 +101,7 @@ public function getNodeTypes(): array

/**
* @param Class_ $node
* @throws Exception
*/
public function refactor(Node $node): ?Node
{
Expand All @@ -104,65 +111,21 @@ public function refactor(Node $node): ?Node

$existingLines = $this->getDocCommentLinesWithoutHeaderAndTrailer($node);

foreach ($node->getProperties() as $property) {
if ($property->type === null) {
continue;
}

if ($property->isPublic()) {
foreach ($node->getTraitUses() as $traitUse) {
if ($traitUse->traits[0]->toString() === HasSerializableAttributes::class) {
continue;
}

$propertyName = $property->props[0]->name->toString();
$propertyType = null;
$getterReturnType = null;

if ($property->type instanceof Node\Identifier) {
$propertyType = $getterReturnType = $this->getName($property->type);
if ($propertyType === 'array') {
foreach ($property->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
if ($attr->name->toCodeString() === "\\".\JMS\Serializer\Annotation\Type::class) {
$value = $attr->args[0]->value;
if ($value instanceof Node\Scalar\String_) {
if (preg_match('/^array<(?<inner>.*)>/', $value->value, $match) === 1) {
if (str_contains($match['inner'], "\\")) {
$propertyType = "\\".$match['inner']."|array";
}
$getterReturnType = $match['inner']."[]";
break 2;
}
} elseif ($value instanceof Node\Expr\BinaryOp\Concat && $value->left->left->value === 'array<' && $value->left->right instanceof Node\Expr\ClassConstFetch) {
$propertyType = "\\".$this->getName($value->left->right->class)."[]|array";
$getterReturnType = $propertyType;
break 2;
}
}
}
}
}
} elseif ($property->type instanceof Node\NullableType) {
$innerType = $property->type->type;
if ($innerType instanceof Node\Name\FullyQualified) {
$propertyType = "null|array|\\".$this->getName($innerType);
$getterReturnType = "\\".$this->getName($innerType)."|null";
} else {
$propertyType = $getterReturnType = $this->getName($property->type->type)."|null";
}
} elseif ($property->type instanceof Node\Name\FullyQualified) {
$propertyType = "array|\\" . $this->getName($property->type);
$getterReturnType = "\\" . $this->getName($property->type);
}
$trait = $this->astResolver->resolveClassFromName($traitUse->traits[0]->toString());

if ($propertyType === null) {
throw new \Exception("No propertyType for ".$propertyName." in class ".$this->getName($node));
foreach ($trait->getProperties() as $property) {
$this->handleProperty($node, $property, $existingLines);
}
}

$setterLine = sprintf('@method self set%s(%s $%s)', ucfirst($propertyName), $propertyType, $propertyName);
$getterLine = sprintf('@method %s get%s()', $getterReturnType, ucfirst($propertyName));

$existingLines[] = $setterLine;
$existingLines[] = $getterLine;
foreach ($node->getProperties() as $property) {
$this->handleProperty($node, $property, $existingLines);
}

$newDocComment = $this->createDocCommentFromExistingLines($existingLines);
Expand Down Expand Up @@ -216,4 +179,66 @@ private function createDocCommentFromExistingLines(array $existingLines) : Doc

return new Doc(implode(PHP_EOL, $docCommentLines));
}

private function handleProperty(Node $node, Node\Stmt\Property $property, array &$existingLines)
{
if ($property->type === null) {
return;
}

if ($property->isPublic()) {
return;
}

$propertyName = $property->props[0]->name->toString();
$propertyType = null;
$getterReturnType = null;

if ($property->type instanceof Node\Identifier) {
$propertyType = $getterReturnType = $this->getName($property->type);
if ($propertyType === 'array') {
foreach ($property->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
if ($attr->name->toCodeString() === "\\".\JMS\Serializer\Annotation\Type::class) {
$value = $attr->args[0]->value;
if ($value instanceof Node\Scalar\String_) {
if (preg_match('/^array<(?<inner>.*)>/', $value->value, $match) === 1) {
if (str_contains($match['inner'], "\\")) {
$propertyType = "\\".$match['inner']."|array";
}
$getterReturnType = $match['inner']."[]";
break 2;
}
} elseif ($value instanceof Node\Expr\BinaryOp\Concat && $value->left->left->value === 'array<' && $value->left->right instanceof Node\Expr\ClassConstFetch) {
$propertyType = "\\".$this->getName($value->left->right->class)."[]|array";
$getterReturnType = $propertyType;
break 2;
}
}
}
}
}
} elseif ($property->type instanceof Node\NullableType) {
$innerType = $property->type->type;
if ($innerType instanceof Node\Name\FullyQualified) {
$propertyType = "null|array|\\".$this->getName($innerType);
$getterReturnType = "\\".$this->getName($innerType)."|null";
} else {
$propertyType = $getterReturnType = $this->getName($property->type->type)."|null";
}
} elseif ($property->type instanceof Node\Name\FullyQualified) {
$propertyType = "array|\\" . $this->getName($property->type);
$getterReturnType = "\\" . $this->getName($property->type);
}

if ($propertyType === null) {
throw new \Exception("No propertyType for ".$propertyName." in class ".$this->getName($node));
}

$setterLine = sprintf('@method self set%s(%s $%s)', ucfirst($propertyName), $propertyType, $propertyName);
$getterLine = sprintf('@method %s get%s()', $getterReturnType, ucfirst($propertyName));

$existingLines[] = $setterLine;
$existingLines[] = $getterLine;
}
}

0 comments on commit d8d9ade

Please sign in to comment.