-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
269 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
include __DIR__.'/../vendor/autoload.php'; | ||
|
||
use League\Plates\RectorizeTemplate; | ||
use Rector\Config\RectorConfig; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->paths([ | ||
__DIR__.'/Templates/Layout.php', | ||
]); | ||
$rectorConfig->rule(RectorizeTemplate::class); | ||
}; | ||
|
||
// vendor/bin/rector process exampleTemplateClass/Templates --config ./exampleTemplateClass/rector.php |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
<?php | ||
|
||
declare (strict_types=1); | ||
|
||
namespace League\Plates; | ||
|
||
use League\Plates\Template\Template; | ||
use League\Plates\Template\TemplateClass; | ||
use League\Plates\Template\TemplateClassInterface; | ||
use PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\ConstructorNameSniff; | ||
use PhpParser\Comment\Doc; | ||
use PhpParser\Node; | ||
use PhpParser\Node\Name; | ||
use PhpParser\Node\Stmt\Class_; | ||
use PhpParser\Node\Stmt\ClassMethod; | ||
use Rector\Core\NodeAnalyzer\ParamAnalyzer; | ||
use Rector\Core\Rector\AbstractRector; | ||
use Rector\Core\ValueObject\MethodName; | ||
use Rector\NodeTypeResolver\NodeTypeResolver\ParamTypeResolver; | ||
use Rector\Removing\NodeManipulator\ComplexNodeRemover; | ||
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; | ||
use Rector\TypeDeclaration\NodeAnalyzer\CallTypesResolver; | ||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; | ||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; | ||
/** | ||
* @see \Rector\Tests\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector\RemoveUnusedConstructorParamRectorTest | ||
*/ | ||
final class RectorizeTemplate extends AbstractRector | ||
{ | ||
/** | ||
* @readonly | ||
* @var \Rector\Core\NodeAnalyzer\ParamAnalyzer | ||
*/ | ||
private $paramAnalyzer; | ||
/** | ||
* @readonly | ||
* @var \Rector\Removing\NodeManipulator\ComplexNodeRemover | ||
*/ | ||
private $complexNodeRemover; | ||
|
||
|
||
/** | ||
* @readonly | ||
* @var ParamTypeResolver | ||
*/ | ||
private $paramTypeResolver; | ||
|
||
public function __construct(ParamTypeResolver $paramTypeResolver, ParamAnalyzer $paramAnalyzer, ComplexNodeRemover $complexNodeRemover) | ||
{ | ||
$this->paramAnalyzer = $paramAnalyzer; | ||
$this->complexNodeRemover = $complexNodeRemover; | ||
$this->paramTypeResolver = $paramTypeResolver; | ||
} | ||
public function getRuleDefinition() : RuleDefinition | ||
{ | ||
return new RuleDefinition('Duplicate diplay to constructor except Template', [new CodeSample(<<<'CODE_SAMPLE' | ||
final class SomeTemplate | ||
{ | ||
public function display(string $name, Template $t): void | ||
{ | ||
// ... | ||
} | ||
} | ||
CODE_SAMPLE | ||
, <<<'CODE_SAMPLE' | ||
final class SomeClass | ||
{ | ||
public function display(string $name, Template $t): void | ||
{ | ||
// ... | ||
} | ||
public function __construct(public string $name) | ||
{ | ||
} | ||
} | ||
CODE_SAMPLE | ||
)]); | ||
} | ||
/** | ||
* @return array<class-string<Node>> | ||
*/ | ||
public function getNodeTypes() : array | ||
{ | ||
return [Class_::class]; | ||
} | ||
|
||
/** | ||
* @param Class_ $node | ||
*/ | ||
public function refactor(Node $node) : ?Node | ||
{ | ||
$implementedInterfaces = array_map( fn (Name $interface) => $interface->toString(), $node->implements ); | ||
if (! in_array(TemplateClassInterface::class, $implementedInterfaces, true)) { | ||
return null; | ||
} | ||
|
||
$displayMethod = $node->getMethod('display') ; | ||
if ($displayMethod === null) | ||
return null; | ||
|
||
|
||
if ($displayMethod->params === []) | ||
return $this->removeConstructor($node); | ||
|
||
$paramsForConstructor = []; | ||
$docBlockForConstructor = []; | ||
$methodDocBlock = $displayMethod?->getDocComment()?->getText() ?? ''; | ||
foreach($displayMethod->params as $parameter) { | ||
$paramType = $this->paramTypeResolver->resolve($parameter); | ||
if ($paramType instanceof FullyQualifiedObjectType && in_array($paramType->getClassName(), [Template::class, TemplateClass::class], true)) | ||
continue; | ||
|
||
$paramDocBlock = $this->getParameterDocblock($methodDocBlock, $this->getName($parameter)); | ||
if ($paramDocBlock !== null) | ||
$docBlockForConstructor[] = $paramDocBlock; | ||
|
||
$cloneParameter = clone $parameter; | ||
$cloneParameter->flags = 1; | ||
$paramsForConstructor[] = $cloneParameter; | ||
} | ||
|
||
if ($paramsForConstructor === []) | ||
return $this->removeConstructor($node); | ||
|
||
$constructor = $node->getMethod(MethodName::CONSTRUCT) ; | ||
$docBlockConstructor = $constructor?->getDocComment(); | ||
$newDocBlockConstructor = new Doc("/**\n * ".trim("Autogenerated constructor\n * ".implode("\n * ", $docBlockForConstructor), "\n *")."\n*/"); | ||
if ($paramsForConstructor === $constructor?->params || $docBlockConstructor === $newDocBlockConstructor) // TODO compare docblock | ||
return null; | ||
|
||
$this->removeConstructor($node); | ||
|
||
$constructor = new ClassMethod('__construct', [ | ||
'flags' => Node\Stmt\Class_::MODIFIER_PUBLIC, | ||
'params' => $paramsForConstructor, | ||
]); | ||
$constructor->setDocComment($newDocBlockConstructor); | ||
|
||
|
||
$node->stmts[] = $constructor; | ||
|
||
return $node; | ||
} | ||
|
||
private function removeConstructor(Class_ $class):null | ||
{ | ||
foreach ($class->stmts as $key => $stmt) { | ||
if ($stmt instanceof Node\Stmt\ClassMethod && $stmt->name->toString() === MethodName::CONSTRUCT) { | ||
unset($class->stmts[$key]); | ||
break; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private function getParameterDocblock(?string $methodDocblock, string $parameterName): ?string | ||
{ | ||
if ($methodDocblock === null) { | ||
return null; | ||
} | ||
|
||
// Regular expression to match a docblock for a specific parameter | ||
$pattern = '/@param\s+[^$]*?\$'.$parameterName.'\b([^@]*)/'; | ||
|
||
$patternIsFound = preg_match($pattern, $methodDocblock, $matches); | ||
|
||
if ($patternIsFound) { | ||
return trim($matches[0], '*/ '."\n"); | ||
} | ||
|
||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters