Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions easy-coding-standard.neon
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ parameters:
Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer:
# classes might not exist
- */src/Rector/Contrib/*/*Rector.php
- */src/Rector/Contrib/**/Helper/**.php
- packages/NodeTypeResolver/src/NodeVisitor/TypeResolver.php
- src/Builder/Contrib/Nette/RouterFactoryClassBuilder.php
Symplify\CodingStandard\Sniffs\Debug\CommentedOutCodeSniff:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php declare(strict_types=1);

namespace Rector\NodeAnalyzer\Contrib;
namespace Rector\NodeAnalyzer\Contrib\Symfony;

use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\String_;

final class SymfonyContainerCallsAnalyzer
final class ContainerCallAnalyzer
{
/**
* Finds $this->get(...);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php declare(strict_types=1);

namespace Rector\NodeAnalyzer\Contrib;
namespace Rector\NodeAnalyzer\Contrib\Symfony;

use Nette\Utils\Strings;
use PhpParser\Node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Rector\Naming\PropertyNaming;
use Rector\Node\Attribute;
use Rector\Node\NodeFactory;
use Rector\NodeAnalyzer\Contrib\SymfonyContainerCallsAnalyzer;
use Rector\NodeAnalyzer\Contrib\Symfony\ContainerCallAnalyzer;
use Rector\Rector\AbstractRector;

/**
Expand Down Expand Up @@ -57,9 +57,9 @@ final class CommandToConstructorInjectionRector extends AbstractRector
private $nodeFactory;

/**
* @var SymfonyContainerCallsAnalyzer
* @var ContainerCallAnalyzer
*/
private $symfonyContainerCallsAnalyzer;
private $containerCallAnalyzer;

/**
* @var ServiceTypeForNameProviderInterface
Expand All @@ -70,13 +70,13 @@ public function __construct(
ClassPropertyCollector $classPropertyCollector,
PropertyNaming $propertyNaming,
NodeFactory $nodeFactory,
SymfonyContainerCallsAnalyzer $symfonyContainerCallsAnalyzer,
ContainerCallAnalyzer $containerCallAnalyzer,
ServiceTypeForNameProviderInterface $serviceTypeForNameProvider
) {
$this->classPropertyCollector = $classPropertyCollector;
$this->propertyNaming = $propertyNaming;
$this->nodeFactory = $nodeFactory;
$this->symfonyContainerCallsAnalyzer = $symfonyContainerCallsAnalyzer;
$this->containerCallAnalyzer = $containerCallAnalyzer;
$this->serviceTypeForNameProvider = $serviceTypeForNameProvider;
}

Expand All @@ -92,7 +92,7 @@ public function isCandidate(Node $node): bool
return false;
}

return $this->symfonyContainerCallsAnalyzer->isGetContainerCall($node);
return $this->containerCallAnalyzer->isGetContainerCall($node);
}

/**
Expand Down
80 changes: 36 additions & 44 deletions src/Rector/Contrib/Symfony/Form/FormTypeGetParentRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,91 +7,83 @@
use Rector\Node\Attribute;
use Rector\Node\NodeFactory;
use Rector\Rector\AbstractRector;
use Rector\Rector\Contrib\Symfony\Form\Helper\FormTypeStringToTypeProvider;

/**
* Converts all:
* - getParent() {
* return 'some_string';
* return 'collection';
* }
* - getExtendedType() {
* return 'collection';
* }
*
* into:
* - getParent() {
* return CollectionType::class;
* }
* - getExtendedType() {
* return CollectionType::class;
* }
*/
final class FormTypeGetParentRector extends AbstractRector
{
/**
* @var string[]
* @var NodeFactory
*/
private $nameToClassMap = [
'birthday' => 'Symfony\Component\Form\Extension\Core\Type\BirthdayType',
'checkbox' => 'Symfony\Component\Form\Extension\Core\Type\CheckboxType',
'collection' => 'Symfony\Component\Form\Extension\Core\Type\CollectionType',
'country' => 'Symfony\Component\Form\Extension\Core\Type\CountryType',
'currency' => 'Symfony\Component\Form\Extension\Core\Type\CurrencyType',
'date' => 'Symfony\Component\Form\Extension\Core\Type\DateType',
'datetime' => 'Symfony\Component\Form\Extension\Core\Type\DatetimeType',
'email' => 'Symfony\Component\Form\Extension\Core\Type\EmailType',
'file' => 'Symfony\Component\Form\Extension\Core\Type\FileType',
'hidden' => 'Symfony\Component\Form\Extension\Core\Type\HiddenType',
'integer' => 'Symfony\Component\Form\Extension\Core\Type\IntegerType',
'language' => 'Symfony\Component\Form\Extension\Core\Type\LanguageType',
'locale' => 'Symfony\Component\Form\Extension\Core\Type\LocaleType',
'money' => 'Symfony\Component\Form\Extension\Core\Type\MoneyType',
'number' => 'Symfony\Component\Form\Extension\Core\Type\NumberType',
'password' => 'Symfony\Component\Form\Extension\Core\Type\PasswordType',
'percent' => 'Symfony\Component\Form\Extension\Core\Type\PercentType',
'radio' => 'Symfony\Component\Form\Extension\Core\Type\RadioType',
'range' => 'Symfony\Component\Form\Extension\Core\Type\RangeType',
'repeated' => 'Symfony\Component\Form\Extension\Core\Type\RepeatedType',
'search' => 'Symfony\Component\Form\Extension\Core\Type\SearchType',
'textarea' => 'Symfony\Component\Form\Extension\Core\Type\TextareaType',
'text' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
'time' => 'Symfony\Component\Form\Extension\Core\Type\TimeType',
'timezone' => 'Symfony\Component\Form\Extension\Core\Type\TimezoneType',
'url' => 'Symfony\Component\Form\Extension\Core\Type\UrlType',
'button' => 'Symfony\Component\Form\Extension\Core\Type\ButtonType',
'submit' => 'Symfony\Component\Form\Extension\Core\Type\SubmitType',
'reset' => 'Symfony\Component\Form\Extension\Core\Type\ResetType',
];
private $nodeFactory;

/**
* @var NodeFactory
* @var FormTypeStringToTypeProvider
*/
private $nodeFactory;
private $formTypeStringToTypeProvider;

public function __construct(NodeFactory $nodeFactory)
public function __construct(NodeFactory $nodeFactory, FormTypeStringToTypeProvider $formTypeStringToTypeProvider)
{
$this->nodeFactory = $nodeFactory;
$this->formTypeStringToTypeProvider = $formTypeStringToTypeProvider;
}

public function isCandidate(Node $node): bool
{
if (! $node instanceof String_ || ! isset($this->nameToClassMap[$node->value])) {
if (! $node instanceof String_) {
return false;
}

$parentClassName = $node->getAttribute(Attribute::PARENT_CLASS_NAME);
if ($parentClassName !== 'Symfony\Component\Form\AbstractType') {
if (! $this->formTypeStringToTypeProvider->hasClassForName($node->value)) {
return false;
}

$methodName = $node->getAttribute(Attribute::METHOD_NAME);
if ($methodName !== 'getParent') {
return false;
if ($this->isParentTypeAndMethod($node, 'Symfony\Component\Form\AbstractType', 'getParent')) {
return true;
}

return true;
if ($this->isParentTypeAndMethod($node, 'Symfony\Component\Form\AbstractTypeExtension', 'getExtendedType')) {
return true;
}

return false;
}

/**
* @param String_ $stringNode
*/
public function refactor(Node $stringNode): ?Node
{
$class = $this->nameToClassMap[$stringNode->value];
$class = $this->formTypeStringToTypeProvider->getClassForName($stringNode->value);

return $this->nodeFactory->createClassConstantReference($class);
}

private function isParentTypeAndMethod(Node $node, string $type, string $method): bool
{
$parentClassName = $node->getAttribute(Attribute::PARENT_CLASS_NAME);
if ($parentClassName !== $type) {
return false;
}

$methodName = $node->getAttribute(Attribute::METHOD_NAME);

return $methodName === $method;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php declare(strict_types=1);

namespace Rector\Rector\Contrib\Symfony\Form\Helper;

use Nette\Utils\Strings;

final class FormTypeStringToTypeProvider
{
/**
* @var string[]
*/
private static $nameToTypeMap = [
'form' => 'Symfony\Component\Form\Extension\Core\Type\FormType',
'birthday' => 'Symfony\Component\Form\Extension\Core\Type\BirthdayType',
'checkbox' => 'Symfony\Component\Form\Extension\Core\Type\CheckboxType',
'collection' => 'Symfony\Component\Form\Extension\Core\Type\CollectionType',
'country' => 'Symfony\Component\Form\Extension\Core\Type\CountryType',
'currency' => 'Symfony\Component\Form\Extension\Core\Type\CurrencyType',
'date' => 'Symfony\Component\Form\Extension\Core\Type\DateType',
'datetime' => 'Symfony\Component\Form\Extension\Core\Type\DatetimeType',
'email' => 'Symfony\Component\Form\Extension\Core\Type\EmailType',
'file' => 'Symfony\Component\Form\Extension\Core\Type\FileType',
'hidden' => 'Symfony\Component\Form\Extension\Core\Type\HiddenType',
'integer' => 'Symfony\Component\Form\Extension\Core\Type\IntegerType',
'language' => 'Symfony\Component\Form\Extension\Core\Type\LanguageType',
'locale' => 'Symfony\Component\Form\Extension\Core\Type\LocaleType',
'money' => 'Symfony\Component\Form\Extension\Core\Type\MoneyType',
'number' => 'Symfony\Component\Form\Extension\Core\Type\NumberType',
'password' => 'Symfony\Component\Form\Extension\Core\Type\PasswordType',
'percent' => 'Symfony\Component\Form\Extension\Core\Type\PercentType',
'radio' => 'Symfony\Component\Form\Extension\Core\Type\RadioType',
'range' => 'Symfony\Component\Form\Extension\Core\Type\RangeType',
'repeated' => 'Symfony\Component\Form\Extension\Core\Type\RepeatedType',
'search' => 'Symfony\Component\Form\Extension\Core\Type\SearchType',
'textarea' => 'Symfony\Component\Form\Extension\Core\Type\TextareaType',
'text' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
'time' => 'Symfony\Component\Form\Extension\Core\Type\TimeType',
'timezone' => 'Symfony\Component\Form\Extension\Core\Type\TimezoneType',
'url' => 'Symfony\Component\Form\Extension\Core\Type\UrlType',
'button' => 'Symfony\Component\Form\Extension\Core\Type\ButtonType',
'submit' => 'Symfony\Component\Form\Extension\Core\Type\SubmitType',
'reset' => 'Symfony\Component\Form\Extension\Core\Type\ResetType',
'entity' => 'Symfony\Bridge\Doctrine\Form\Type\EntityType',
];

public function hasClassForNameWithPrefix(string $name): bool
{
$name = $this->removeFormTypePrefix($name);

return $this->hasClassForName($name);
}

public function getClassForNameWithPrefix(string $name): string
{
$name = $this->removeFormTypePrefix($name);

return $this->getClassForName($name);
}

public function hasClassForName(string $name): bool
{
return array_key_exists($name, self::$nameToTypeMap);
}

public function getClassForName(string $name): string
{
return self::$nameToTypeMap[$name];
}

private function removeFormTypePrefix(string $name): string
{
return Strings::substring($name, strlen('form.type.'));
}
}
67 changes: 30 additions & 37 deletions src/Rector/Contrib/Symfony/Form/StringFormTypeToClassRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
namespace Rector\Rector\Contrib\Symfony\Form;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use Rector\Node\Attribute;
use Rector\Node\NodeFactory;
use Rector\Rector\AbstractRector;
use Rector\Rector\Contrib\Symfony\Form\Helper\FormTypeStringToTypeProvider;

/**
* Converts all:
Expand All @@ -19,61 +23,50 @@
final class StringFormTypeToClassRector extends AbstractRector
{
/**
* @var string[]
* @var NodeFactory
*/
private $nameToClassMap = [
'form.type.birthday' => 'Symfony\Component\Form\Extension\Core\Type\BirthdayType',
'form.type.checkbox' => 'Symfony\Component\Form\Extension\Core\Type\CheckboxType',
'form.type.collection' => 'Symfony\Component\Form\Extension\Core\Type\CollectionType',
'form.type.country' => 'Symfony\Component\Form\Extension\Core\Type\CountryType',
'form.type.currency' => 'Symfony\Component\Form\Extension\Core\Type\CurrencyType',
'form.type.date' => 'Symfony\Component\Form\Extension\Core\Type\DateType',
'form.type.datetime' => 'Symfony\Component\Form\Extension\Core\Type\DatetimeType',
'form.type.email' => 'Symfony\Component\Form\Extension\Core\Type\EmailType',
'form.type.file' => 'Symfony\Component\Form\Extension\Core\Type\FileType',
'form.type.hidden' => 'Symfony\Component\Form\Extension\Core\Type\HiddenType',
'form.type.integer' => 'Symfony\Component\Form\Extension\Core\Type\IntegerType',
'form.type.language' => 'Symfony\Component\Form\Extension\Core\Type\LanguageType',
'form.type.locale' => 'Symfony\Component\Form\Extension\Core\Type\LocaleType',
'form.type.money' => 'Symfony\Component\Form\Extension\Core\Type\MoneyType',
'form.type.number' => 'Symfony\Component\Form\Extension\Core\Type\NumberType',
'form.type.password' => 'Symfony\Component\Form\Extension\Core\Type\PasswordType',
'form.type.percent' => 'Symfony\Component\Form\Extension\Core\Type\PercentType',
'form.type.radio' => 'Symfony\Component\Form\Extension\Core\Type\RadioType',
'form.type.range' => 'Symfony\Component\Form\Extension\Core\Type\RangeType',
'form.type.repeated' => 'Symfony\Component\Form\Extension\Core\Type\RepeatedType',
'form.type.search' => 'Symfony\Component\Form\Extension\Core\Type\SearchType',
'form.type.textarea' => 'Symfony\Component\Form\Extension\Core\Type\TextareaType',
'form.type.text' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
'form.type.time' => 'Symfony\Component\Form\Extension\Core\Type\TimeType',
'form.type.timezone' => 'Symfony\Component\Form\Extension\Core\Type\TimezoneType',
'form.type.url' => 'Symfony\Component\Form\Extension\Core\Type\UrlType',
'form.type.button' => 'Symfony\Component\Form\Extension\Core\Type\ButtonType',
'form.type.submit' => 'Symfony\Component\Form\Extension\Core\Type\SubmitType',
'form.type.reset' => 'Symfony\Component\Form\Extension\Core\Type\ResetType',
];
private $nodeFactory;

/**
* @var NodeFactory
* @var FormTypeStringToTypeProvider
*/
private $nodeFactory;
private $formTypeStringToTypeProvider;

public function __construct(NodeFactory $nodeFactory)
public function __construct(NodeFactory $nodeFactory, FormTypeStringToTypeProvider $formTypeStringToTypeProvider)
{
$this->nodeFactory = $nodeFactory;
$this->formTypeStringToTypeProvider = $formTypeStringToTypeProvider;
}

public function isCandidate(Node $node): bool
{
return $node instanceof String_ && isset($this->nameToClassMap[$node->value]);
if (! $node instanceof String_) {
return false;
}

if (! $this->formTypeStringToTypeProvider->hasClassForNameWithPrefix($node->value)) {
return false;
}

$argNode = $node->getAttribute(Attribute::PARENT_NODE);
if (! $argNode instanceof Arg) {
return false;
}

$methodCallNode = $argNode->getAttribute(Attribute::PARENT_NODE);
if (! $methodCallNode instanceof MethodCall) {
return false;
}

return $methodCallNode->name->toString() === 'add';
}

/**
* @param String_ $stringNode
*/
public function refactor(Node $stringNode): ?Node
{
$class = $this->nameToClassMap[$stringNode->value];
$class = $this->formTypeStringToTypeProvider->getClassForNameWithPrefix($stringNode->value);

return $this->nodeFactory->createClassConstantReference($class);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Rector/Contrib/Symfony/HttpKernel/GetRequestRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Node\Attribute;
use Rector\Node\NodeFactory;
use Rector\NodeAnalyzer\Contrib\ControllerMethodAnalyzer;
use Rector\NodeAnalyzer\Contrib\Symfony\ControllerMethodAnalyzer;
use Rector\NodeAnalyzer\MethodCallAnalyzer;
use Rector\Rector\AbstractRector;

Expand Down
Loading