rename StateHolder, to TokenSwitcher

This commit is contained in:
TomasVotruba 2017-08-08 01:59:37 +02:00
parent d8849f04cd
commit 7d5a1250eb
10 changed files with 182 additions and 140 deletions

View File

@ -1,21 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\NodeTraverser;
final class StateHolder
{
/**
* @var bool
*/
private $isAfterTraverseCalled = false;
public function setAfterTraverserIsCalled(): void
{
$this->isAfterTraverseCalled = true;
}
public function isAfterTraverseCalled(): bool
{
return $this->isAfterTraverseCalled;
}
}

View File

@ -0,0 +1,21 @@
<?php declare(strict_types=1);
namespace Rector\NodeTraverser;
final class TokenSwitcher
{
/**
* @var bool
*/
private $isEnabled = false;
public function enable(): void
{
$this->isEnabled = true;
}
public function isEnabled(): bool
{
return $this->isEnabled;
}
}

View File

@ -1,107 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\NodeVisitor\DependencyInjection;
use PhpCsFixer\DocBlock\DocBlock;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeVisitorAbstract;
use Rector\Builder\ConstructorMethodBuilder;
final class InjectAnnotationToConstructorNodeVisitor extends NodeVisitorAbstract
{
/**
* @var string
*/
private const ANNOTATION_INJECT = 'inject';
/**
* @var ConstructorMethodBuilder
*/
private $constructorMethodBuilder;
public function __construct(ConstructorMethodBuilder $constructorMethodBuilder)
{
$this->constructorMethodBuilder = $constructorMethodBuilder;
}
public function isCandidate(Node $node): bool
{
return $node instanceof Class_;
}
/**
* Called when entering a node.
*
* Return value semantics:
* * null
* => $node stays as-is
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
* => Children of $node are not traversed. $node stays as-is
* * NodeTraverser::STOP_TRAVERSAL
* => Traversal is aborted. $node stays as-is
* * otherwise
* => $node is set to the return value
*
* @return null|int|Node Replacement node (or special return value)
*/
public function enterNode(Node $node)
{
if ($node instanceof Class_) {
return $this->reconstruct($node);
}
return null;
}
private function reconstruct(Class_ $classNode): Node
{
foreach ($classNode->stmts as $classElementStatement) {
if (! $classElementStatement instanceof Property) {
continue;
}
$propertyNode = $classElementStatement;
$propertyDocBlock = $this->createDocBlockFromProperty($propertyNode);
$injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT);
if (! $injectAnnotations) {
continue;
}
$this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock);
$this->makePropertyPrivate($propertyNode);
$propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0]
->getTypes()[0];
$propertyName = (string) $propertyNode->props[0]->name;
$this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName);
}
return $classNode;
}
private function createDocBlockFromProperty(Property $propertyNode): DocBlock
{
return new DocBlock($propertyNode->getDocComment());
}
private function makePropertyPrivate(Property $propertyNode): void
{
$propertyNode->flags = Class_::MODIFIER_PRIVATE;
}
private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): void
{
$injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT);
foreach ($injectAnnotations as $injectAnnotation) {
$injectAnnotation->remove();
}
$propertyNode->setDocComment(new Doc($propertyDocBlock->getContent()));
}
}

View File

@ -0,0 +1,127 @@
<?php declare(strict_types=1);
namespace Rector\NodeVisitor\DependencyInjection;
use PhpCsFixer\DocBlock\DocBlock;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeVisitorAbstract;
use Rector\NodeTraverser\TokenSwitcher;
final class InjectAnnotationToConstructorRector extends NodeVisitorAbstract
{
/**
* @var string
*/
private const ANNOTATION_INJECT = 'inject';
/**
* @var TokenSwitcher
*/
private $tokenSwitcher;
// /**
// * @var ConstructorMethodBuilder
// */
// private $constructorMethodBuilder;
//
// public function __construct(ConstructorMethodBuilder $constructorMethodBuilder)
// {
// $this->constructorMethodBuilder = $constructorMethodBuilder;
// }
public function __construct(TokenSwitcher $tokenSwitcher)
{
$this->tokenSwitcher = $tokenSwitcher;
}
public function enterNode(Node $node): ?Node
{
if (! $this->isCandidate($node)) {
return null;
}
return $this->reconstructProperty($node);
}
public function isCandidate(Node $node): bool
{
if (! $node instanceof Property) {
return false;
}
if (! $this->hasInjectAnnotation($node)) {
return false;
}
$this->tokenSwitcher->enable();
return true;
}
// private function reconstruct(Class_ $classNode): Node
// {
// dump($classNode);
// die;
//
// foreach ($classNode->stmts as $classElementStatement) {
// if (! $classElementStatement instanceof Property) {
// continue;
// }
//
// $propertyNode = $classElementStatement;
//
// $propertyDocBlock = $this->createDocBlockFromNode($propertyNode);
// $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT);
// if (! $injectAnnotations) {
// continue;
// }
//
// $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock);
// $this->makePropertyPrivate($propertyNode);
//
// $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0]
// ->getTypes()[0];
// $propertyName = (string) $propertyNode->props[0]->name;
//
// $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName);
// }
//
// return $classNode;
// }
private function reconstructProperty($propertyNode): Property
{
$propertyDocBlock = $this->createDocBlockFromNode($propertyNode);
$propertyNode = $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock);
// $propertyNode->flags = Class_::MODIFIER_PRIVATE;
return $propertyNode;
}
private function hasInjectAnnotation(Property $propertyNode): bool
{
$propertyDocBlock = $this->createDocBlockFromNode($propertyNode);
return (bool) $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT);
}
private function createDocBlockFromNode(Node $node): DocBlock
{
return new DocBlock($node->getDocComment());
}
private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): Property
{
$injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT);
foreach ($injectAnnotations as $injectAnnotation) {
$injectAnnotation->remove();
}
$propertyNode->setDocComment(new Doc($propertyDocBlock->getContent()));
return $propertyNode;
}
}

View File

@ -8,7 +8,7 @@ use PhpParser\NodeVisitorAbstract;
use Rector\Builder\Class_\ClassPropertyCollector;
use Rector\Builder\ConstructorMethodBuilder;
use Rector\Builder\PropertyBuilder;
use Rector\NodeTraverser\StateHolder;
use Rector\NodeTraverser\TokenSwitcher;
/**
* Add new propertis to class and to contructor.
@ -31,20 +31,20 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract
private $newClassPropertyCollector;
/**
* @var StateHolder
* @var TokenSwitcher
*/
private $stateHolder;
private $tokenSwitcher;
public function __construct(
ConstructorMethodBuilder $constructorMethodBuilder,
PropertyBuilder $propertyBuilder,
ClassPropertyCollector $newClassPropertyCollector,
StateHolder $stateHolder
TokenSwitcher $tokenSwitcher
) {
$this->constructorMethodBuilder = $constructorMethodBuilder;
$this->propertyBuilder = $propertyBuilder;
$this->newClassPropertyCollector = $newClassPropertyCollector;
$this->stateHolder = $stateHolder;
$this->tokenSwitcher = $tokenSwitcher;
}
/**
@ -68,7 +68,7 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract
$propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className);
foreach ($propertiesForClass as $propertyType => $propertyName) {
$this->stateHolder->setAfterTraverserIsCalled();
$this->tokenSwitcher->enable();
$this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName);
$this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName);
}

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\TraitUse;
use Rector\Builder\StatementGlue;
use Rector\Deprecation\SetNames;
use Rector\NodeTraverser\TokenSwitcher;
use Rector\Rector\AbstractRector;
/**
@ -20,9 +21,15 @@ final class NetteObjectToSmartTraitRector extends AbstractRector
*/
private $statementGlue;
public function __construct(StatementGlue $statementGlue)
/**
* @var TokenSwitcher
*/
private $tokenSwitcher;
public function __construct(StatementGlue $statementGlue, TokenSwitcher $tokenSwitcher)
{
$this->statementGlue = $statementGlue;
$this->tokenSwitcher = $tokenSwitcher;
}
public function getSetName(): string
@ -47,6 +54,7 @@ final class NetteObjectToSmartTraitRector extends AbstractRector
return false;
}
$this->tokenSwitcher->enable();
return true;
}
@ -58,12 +66,12 @@ final class NetteObjectToSmartTraitRector extends AbstractRector
*/
public function refactor($classNode): ?Node
{
// remove parent class
$classNode->extends = null;
$traitUseNode = $this->createTraitUse('Nette\SmartObject');
$this->statementGlue->addAsFirstTrait($classNode, $traitUseNode);
// remove parent class
$classNode->extends = null;
return $classNode;
}

View File

@ -5,6 +5,7 @@ namespace Rector\Testing\Application;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\Parser;
use Rector\NodeTraverser\TokenSwitcher;
use Rector\Printer\FormatPerservingPrinter;
use SplFileInfo;
@ -30,16 +31,23 @@ final class FileReconstructor
*/
private $nodeTraverser;
/**
* @var TokenSwitcher
*/
private $tokenSwitcher;
public function __construct(
Parser $parser,
FormatPerservingPrinter $codeStyledPrinter,
Lexer $lexer,
NodeTraverser $nodeTraverser
NodeTraverser $nodeTraverser,
TokenSwitcher $tokenSwitcher
) {
$this->parser = $parser;
$this->codeStyledPrinter = $codeStyledPrinter;
$this->lexer = $lexer;
$this->nodeTraverser = $nodeTraverser;
$this->tokenSwitcher = $tokenSwitcher;
}
// ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516
@ -51,6 +59,10 @@ final class FileReconstructor
$oldTokens = $this->lexer->getTokens();
$newStmts = $this->nodeTraverser->traverse($oldStmts);
if ($this->tokenSwitcher->isEnabled()) {
[$oldStmts, $newStmts] = [$newStmts, $oldStmts];
}
return $this->codeStyledPrinter->printToString($newStmts, $oldStmts, $oldTokens);
}
}

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Tests\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
namespace Rector\Tests\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorRector;
use Rector\Testing\PHPUnit\AbstractReconstructorTestCase;

View File

@ -6,10 +6,12 @@ class ClassWithInjects
* @var stdClass
*/
private $property;
/**
* @var DateTimeInterface
*/
private $otherProperty;
public function __construct(stdClass $property, DateTimeInterface $otherProperty)
{
$this->property = $property;