Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexanderschnitzler/f664b458f2bc47833c7a55f93b5a363d to your computer and use it in GitHub Desktop.
Save alexanderschnitzler/f664b458f2bc47833c7a55f93b5a363d to your computer and use it in GitHub Desktop.
InjectMethodToConstructorInjectionRector.php
<?php
declare(strict_types=1);
namespace FriendsOfTYPO3\Rector\TYPO3\Rector\Extbase;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use PhpParser\Node\Param;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\PostRector\ValueObject\PropertyMetadata;
final class InjectMethodToConstructorInjectionRector extends AbstractRector
{
private $classDependencyManipulator;
public function __construct(ClassDependencyManipulator $classDependencyManipulator) {
$this->classDependencyManipulator = $classDependencyManipulator;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'',
[
new CodeSample(<<<'CODE_SAMPLE'
namespace App\Service;
use \TYPO3\CMS\Core\Cache\CacheManager;
class Service
{
private CacheManager $cacheManager;
public function injectCacheManager(CacheManager $cacheManager): void
{
$this->cacheManager = $cacheManager;
}
}
CODE_SAMPLE, <<<'CODE_SAMPLE'
namespace App\Service;
use \TYPO3\CMS\Core\Cache\CacheManager;
class Service
{
private CacheManager $cacheManager;
public function __construct(CacheManager $cacheManager)
{
$this->cacheManager = $cacheManager;
}
}
CODE_SAMPLE
)
]
);
}
/**
* List of nodes this class checks, classes that implements \PhpParser\Node
* See beautiful map of all nodes https://github.com/rectorphp/rector/blob/master/docs/NodesOverview.md
*
* @return class-string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* Process Node of matched type
*/
public function refactor(Node $node): ?Node
{
/** @var Class_ $node */
if ($this->shouldSkip($node)) {
return null;
}
$injectMethods = array_filter($node->getMethods(), function ($classMethod) {
return strncmp((string)$classMethod->name, 'inject', 6) === 0;
});
if ($injectMethods === []) {
return null;
}
foreach ($injectMethods as $injectMethod) {
$params = $injectMethod->getParams();
if (empty($params)) {
continue;
}
reset($params);
/** @var Param $param */
$param = current($params);
if (!$param->type instanceof FullyQualified) {
continue;
}
$this->classDependencyManipulator->addConstructorDependency(
$node,
new PropertyMetadata(
(string)$param->var->name,
new ObjectType((string)$param->type),
Class_::MODIFIER_PROTECTED
)
);
$this->removeNodeFromStatements($node, $injectMethod);
}
return $node;
}
private function shouldSkip(Class_ $class): bool
{
return $class->getMethods() === [];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment