[Symfony] Add FormTypeInstanceToClassConstRector

This commit is contained in:
Tomas Votruba 2018-10-23 20:06:06 +02:00
parent 271d98e868
commit 075707447a
44 changed files with 643 additions and 69 deletions

View File

@ -80,18 +80,10 @@
"Rector\\FileSystemRector\\Tests\\": "packages/FileSystemRector/tests"
},
"classmap": [
"packages/CakePHP/tests",
"packages/Doctrine/tests",
"packages/FileSystemRector/tests",
"packages/NodeTypeResolver/tests",
"packages/PhpParser/tests",
"packages/PHPUnit/tests",
"packages/Sensio/tests",
"packages/Silverstripe/tests",
"packages/Sylius/tests",
"packages/Symfony/tests",
"packages/Twig/tests",
"packages/Utils/tests",
"packages/Symfony/tests/Rector/FrameworkBundle/AbstractToConstructorInjectionRectorSource",
"packages/Symfony/tests/Rector/FrameworkBundle/ContainerGetToConstructorInjectionRector/Source",
"packages/NodeTypeResolver/tests/PerNodeTypeResolver/ParamTypeResolver/Source",
"packages/NodeTypeResolver/tests/PerNodeTypeResolver/PropertyTypeResolver/Source",
"tests/Source",
"tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Source",
"tests/Rector/Namespace_/PseudoNamespaceToNamespaceRector/Source"

View File

@ -156,4 +156,5 @@ services:
'Symfony\Component\Validator\Mapping\MetadataFactoryInterface': 'Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface'
# swift mailer
'Symfony\Bridge\Swiftmailer\DataCollector\MessageDataCollector': 'Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector'
'Symfony\Bridge\Swiftmailer\DataCollector\MessageDataCollector': 'Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector'
Rector\Symfony\Rector\MethodCall\FormTypeInstanceToClassConstRector: ~

View File

@ -6,13 +6,13 @@ use Nette\Utils\FileSystem;
use Nette\Utils\Strings;
use Rector\CodingStyle\AfterRectorCodingStyle;
use Rector\Console\ConsoleStyle;
use Rector\ContributorTools\Configuration\Configuration;
use Rector\ContributorTools\Configuration\ConfigurationFactory;
use Rector\ContributorTools\TemplateVariablesFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Yaml;
use Symplify\PackageBuilder\Console\Command\CommandNaming;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\PackageBuilder\FileSystem\FinderSanitizer;
@ -28,6 +28,11 @@ final class CreateRectorCommand extends Command
*/
private const TEMPLATES_DIRECTORY = __DIR__ . '/../../templates';
/**
* @var string
*/
private const RECTOR_FQN_NAME_PATTERN = 'Rector\_Package_\Rector\_Category_\_Name_';
/**
* @var ConsoleStyle
*/
@ -101,19 +106,7 @@ final class CreateRectorCommand extends Command
}
}
if ($configuration->getLevel()) {
if (file_exists($configuration->getLevel())) {
$levelConfigContent = FileSystem::read($configuration->getLevel());
$levelConfigContent = trim($levelConfigContent) . sprintf(
'%s%s: ~%s',
PHP_EOL,
Strings::indent($configuration->getName(), 8, ' '),
PHP_EOL
);
FileSystem::write($configuration->getLevel(), $levelConfigContent);
}
}
$this->appendToLevelConfig($configuration, $templateVariables);
$this->applyCodingStyle();
$this->printSuccess($configuration->getName());
@ -180,4 +173,36 @@ final class CreateRectorCommand extends Command
{
return $this->applyVariables($smartFileInfo->getContents(), $templateVariables);
}
/**
* @param string[] $templateVariables
*/
private function appendToLevelConfig(Configuration $configuration, array $templateVariables): void
{
if (! $configuration->getLevelConfig()) {
return;
}
if (! file_exists($configuration->getLevelConfig())) {
return;
}
$rectorFqnName = $this->applyVariables(self::RECTOR_FQN_NAME_PATTERN, $templateVariables);
$levelConfigContent = FileSystem::read($configuration->getLevelConfig());
// already added
if (Strings::contains($levelConfigContent, $rectorFqnName)) {
return;
}
$levelConfigContent = trim($levelConfigContent) . sprintf(
'%s%s: ~%s',
PHP_EOL,
Strings::indent($rectorFqnName, 8, ' '),
PHP_EOL
);
FileSystem::write($configuration->getLevelConfig(), $levelConfigContent);
}
}

View File

@ -49,7 +49,7 @@ final class Configuration
/**
* @var string|null
*/
private $level;
private $levelConfig;
/**
* @param string[] $nodeTypes
@ -63,7 +63,7 @@ final class Configuration
string $codeBefore,
string $codeAfter,
string $source,
?string $level
?string $levelConfig
) {
$this->package = $package;
$this->setName($name);
@ -73,7 +73,7 @@ final class Configuration
$this->codeAfter = $codeAfter;
$this->description = $description;
$this->source = $source;
$this->level = $level;
$this->levelConfig = $levelConfig;
}
public function getDescription(): string
@ -119,6 +119,11 @@ final class Configuration
return $this->source;
}
public function getLevelConfig(): ?string
{
return $this->levelConfig;
}
private function setName(string $name): void
{
if (! Strings::endsWith($name, 'Rector')) {
@ -127,9 +132,4 @@ final class Configuration
$this->name = $name;
}
public function getLevel(): ?string
{
return $this->level;
}
}

View File

@ -133,7 +133,7 @@ final class ConfigurationFactory
return array_keys($robotLoader->getIndexedClasses());
}
private function isNodeClassMatch(String $nodeClass, String $nodeType): bool
private function isNodeClassMatch(string $nodeClass, string $nodeType): bool
{
if (Strings::endsWith($nodeClass, '\\' . $nodeType)) {
return true;
@ -147,15 +147,16 @@ final class ConfigurationFactory
{
$finder = Finder::create()->files()
->in($this->levelsDirectory)
->name('#.(yml|yaml)$#');
->name(sprintf('#%s$#', $level));
/** @var SplFileInfo $fileInfo */
foreach ($finder as $fileInfo) {
if ($fileInfo->getBasename() === $level) {
return $fileInfo->getRealPath();
}
/** @var SplFileInfo[] $fileInfos */
$fileInfos = iterator_to_array($finder->getIterator());
if (! count($fileInfos)) {
return null;
}
return null;
/** @var SplFileInfo $foundLevelConfigFileInfo */
$foundLevelConfigFileInfo = array_pop($fileInfos);
return $foundLevelConfigFileInfo->getRealPath();
}
}

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Silverstripe\Tests\ConstantToStaticCallRector;
namespace Rector\Silverstripe\Tests\Rector\ConstantToStaticCallRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Silverstripe\Tests\DefineConstantToStaticCallRector;
namespace Rector\Silverstripe\Tests\Rector\DefineConstantToStaticCallRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -0,0 +1,333 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Rector\MethodCall;
use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\NodeTypeResolver\Application\ClassNodeCollector;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use ReflectionClass;
/**
* @see https://github.com/symfony/symfony/commit/adf20c86fb0d8dc2859aa0d2821fe339d3551347
* @see http://www.keganv.com/passing-arguments-controller-file-type-symfony-3/
* @see https://stackoverflow.com/questions/34027711/passing-data-to-buildform-in-symfony-2-8-3-0
* @see https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.8.md#form
*/
final class FormTypeInstanceToClassConstRector extends AbstractRector
{
/**
* @var string
*/
private $controllerClass;
/**
* @var string
*/
private $formBuilderType;
/**
* @var string
*/
private $formType;
/**
* @var ClassNodeCollector
*/
private $classNodeCollector;
/**
* @var BuilderFactory
*/
private $builderFactory;
public function __construct(
ClassNodeCollector $classNodeCollector,
BuilderFactory $builderFactory,
string $controllerClass = 'Symfony\Bundle\FrameworkBundle\Controller\Controller',
string $formBuilderType = 'Symfony\Component\Form\FormBuilderInterface',
string $formType = 'Symfony\Component\Form\FormInterface'
) {
$this->classNodeCollector = $classNodeCollector;
$this->controllerClass = $controllerClass;
$this->formBuilderType = $formBuilderType;
$this->formType = $formType;
$this->builderFactory = $builderFactory;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Changes createForm(new FormType), add(new FormType) to ones with "FormType::class"',
[
new CodeSample(
<<<'CODE_SAMPLE'
class SomeController
{
public function action()
{
$form = $this->createForm(new TeamType, $entity, [
'action' => $this->generateUrl('teams_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeController
{
public function action()
{
$form = $this->createForm(TeamType::class, $entity, [
'action' => $this->generateUrl('teams_update', ['id' => $entity->getId()]),
'method' => 'PUT',
));
}
}
CODE_SAMPLE
),
]
);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->isType($node, $this->controllerClass) && $this->isName($node, 'createForm')) {
return $this->processNewInstance($node, 0, 2);
}
if ($this->isTypes($node, [$this->formBuilderType, $this->formType]) && $this->isName($node, 'add')) {
return $this->processNewInstance($node, 1, 2);
}
return null;
}
private function processNewInstance(MethodCall $methodCallNode, int $position, int $optionsPosition): ?Node
{
if (! isset($methodCallNode->args[$position])) {
return null;
}
if (! $methodCallNode->args[$position]->value instanceof New_) {
return null;
}
/** @var New_ $newNode */
$newNode = $methodCallNode->args[$position]->value;
// we can only process direct name
if (! $newNode->class instanceof Name) {
return null;
}
if (count($newNode->args)) {
$methodCallNode = $this->moveArgumentsToOptions(
$methodCallNode,
$position,
$optionsPosition,
$newNode->class->toString(),
$newNode->args
);
if ($methodCallNode === null) {
return null;
}
}
$methodCallNode->args[$position]->value = new ClassConstFetch($newNode->class, 'class');
return $methodCallNode;
}
/**
* @param Arg[] $argNodes
* @return Arg[]
*/
private function resolveNamesToArgs(string $className, array $argNodes): array
{
$reflectionClass = new ReflectionClass($className);
$constructorReflectionMethod = $reflectionClass->getConstructor();
if (! $constructorReflectionMethod) {
return [];
}
$namesToArgs = [];
foreach ($constructorReflectionMethod->getParameters() as $parameterReflection) {
$namesToArgs[$parameterReflection->getName()] = $argNodes[$parameterReflection->getPosition()];
}
return $namesToArgs;
}
/**
* @param Arg[] $argNodes
*/
private function moveArgumentsToOptions(
MethodCall $methodCallNode,
int $position,
int $optionsPosition,
string $className,
array $argNodes
): ?Node {
$namesToArgs = $this->resolveNamesToArgs($className, $argNodes);
// set default data in between
if ($position + 1 !== $optionsPosition) {
if (! isset($methodCallNode->args[$position + 1])) {
$methodCallNode->args[$position + 1] = new Arg(new ConstFetch(new Name('null')));
}
}
// @todo extend current options - array analyzer
if (! isset($methodCallNode->args[$optionsPosition])) {
$optionsArrayNode = new Array_();
foreach ($namesToArgs as $name => $arg) {
$optionsArrayNode->items[] = new ArrayItem($arg->value, new String_($name));
}
$methodCallNode->args[$optionsPosition] = new Arg($optionsArrayNode);
}
$formTypeClassNode = $this->classNodeCollector->findClass($className);
if ($formTypeClassNode === null) {
return null;
}
$formTypeConstructorMethodNode = $formTypeClassNode->getMethod('__construct');
// nothing we can do, out of scope
if ($formTypeConstructorMethodNode === null) {
return null;
}
// add "buildForm" method + "configureOptions" method with defaults
$this->addBuildFormMethod($formTypeClassNode, $formTypeConstructorMethodNode);
$this->addConfigureOptionsMethod($formTypeClassNode, $namesToArgs);
// remove ctor
$this->removeNode($formTypeConstructorMethodNode);
return $methodCallNode;
}
/**
* @param Node[] $nodes
* @return Node[]
*
* $this->value = $value
*
* $this->value = $options['value']
*/
private function replaceParameterAssignWithOptionAssign(array $nodes, Param $param): array
{
foreach ($nodes as $expression) {
if (! $expression instanceof Expression) {
continue;
}
$node = $expression->expr;
if ($node instanceof Assign && $node->expr instanceof Variable) {
$node->expr = new ArrayDimFetch($param->var, new String_($this->getName($node->var)));
}
}
return $nodes;
}
private function addBuildFormMethod(Class_ $classNode, ClassMethod $formTypeConstructorMethodNode): void
{
if ($classNode->getMethod('buildForm')) {
// @todo
return;
}
$formBuilderParamNode = $this->builderFactory->param('builder')
->setType(new FullyQualified($this->formBuilderType))
->getNode();
$optionsParamNode = $this->builderFactory->param('options')
->setType('array')
->getNode();
$buildFormClassMethodNode = $this->builderFactory->method('buildForm')
->makePublic()
->addParam($formBuilderParamNode)
->addParam($optionsParamNode)
// raw copy stmts from ctor @todo improve
->addStmts(
$this->replaceParameterAssignWithOptionAssign(
$formTypeConstructorMethodNode->stmts,
$optionsParamNode
)
)
->getNode();
$classNode->stmts[] = $buildFormClassMethodNode;
}
/**
* @param Arg[] $namesToArgs
*/
private function addConfigureOptionsMethod(Class_ $classNode, array $namesToArgs): void
{
if ($classNode->getMethod('configureOptions')) {
// @todo
return;
}
$resolverParamNode = $this->builderFactory->param('resolver')
->setType(new FullyQualified('Symfony\Component\OptionsResolver\OptionsResolver'))
->getNode();
$optionsDefaults = new Array_();
foreach (array_keys($namesToArgs) as $optionName) {
$optionsDefaults->items[] = new ArrayItem(new ConstFetch(new Name('null')), new String_($optionName));
}
$setDefaultsMethodCall = new MethodCall($resolverParamNode->var, new Identifier('setDefaults'));
$setDefaultsMethodCall->args[] = new Arg($optionsDefaults);
$configureOptionsClassMethodNode = $this->builderFactory->method('configureOptions')
->makePublic()
->addParam($resolverParamNode)
->addStmt($setDefaultsMethodCall)
->getNode();
$classNode->stmts[] = $configureOptionsClassMethodNode;
}
}

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Console\ConsoleExceptionToErrorEventConstantRector;
namespace Rector\Symfony\Tests\Rector\Console\ConsoleExceptionToErrorEventConstantRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Controller\ActionSuffixRemoverRector;
namespace Rector\Symfony\Tests\Rector\Controller\ActionSuffixRemoverRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Controller\AddFlashRector;
namespace Rector\Symfony\Tests\Rector\Controller\AddFlashRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Controller\RedirectToRouteRector;
namespace Rector\Symfony\Tests\Rector\Controller\RedirectToRouteRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\DependencyInjection\ContainerBuilderCompileEnvArgumentRector;
namespace Rector\Symfony\Tests\Rector\DependencyInjection\ContainerBuilderCompileEnvArgumentRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Form\FormIsValidRector;
namespace Rector\Symfony\Tests\Rector\Form\FormIsValidRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Form\FormTypeGetParentRector;
namespace Rector\Symfony\Tests\Rector\Form\FormTypeGetParentRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Form\OptionNameRector;
namespace Rector\Symfony\Tests\Rector\Form\OptionNameRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Form\StringFormTypeToClassRector;
namespace Rector\Symfony\Tests\Rector\Form\StringFormTypeToClassRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\ContainerGetToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\ContainerGetToConstructorInjectionRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\GetParameterToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\GetParameterToConstructorInjectionRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\GetToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\GetToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector;
use Rector\Exception\Configuration\InvalidConfigurationException;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\GetToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector;
use Rector\Exception\Configuration\InvalidConfigurationException;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\FrameworkBundle\GetToConstructorInjectionRector;
namespace Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector;
use Rector\Exception\Configuration\InvalidConfigurationException;
use Rector\Symfony\Tests\FrameworkBundle\AbstractToConstructorInjectionRectorSource\SomeNonKernelClass;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\HttpKernel\GetRequestRector;
namespace Rector\Symfony\Tests\Rector\HttpKernel\GetRequestRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -0,0 +1,34 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
class SomeController extends ControllerClass
{
public function action()
{
$form = $this->createForm(AnotherFormType::class, $entity, [
'action' => $this->generateUrl('teams_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form = $this->createForm(AnotherFormType::class, $entity, ['items' => [1]]);
}
}
final class AnotherFormType
{
/**
* @var array
*/
private $items;
public function buildForm(\Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder $builder, array $options)
{
$this->items = $options['items'];
}
public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver)
{
$resolver->setDefaults(['items' => null]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormType;
class SomeAnotherController extends ControllerClass
{
public function action(FormBuilder $builder)
{
$builder->add('someText', SomeClass::class);
$form = new FormType();
$form->add('text', AnotherFormTypeClass::class);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder;
class SomeAnotherControllerWithArgs extends ControllerClass
{
public function action(FormBuilder $builder)
{
$builder->add('someText', SomeTypeWithCtor::class, ['number' => 1]);
}
}
class SomeTypeWithCtor
{
/**
* @var int
*/
private $number;
public function buildForm(\Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder $builder, array $options)
{
$this->number = $options['number'];
}
public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver)
{
$resolver->setDefaults(['number' => null]);
}
}

View File

@ -0,0 +1,32 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
/**
* @covers \Rector\Symfony\Rector\MethodCall\FormTypeInstanceToClassConstRector
*/
final class FormTypeInstanceToClassConstRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideWrongToFixedFiles()
*/
public function test(string $wrong, string $fixed): void
{
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
}
public function provideWrongToFixedFiles(): Iterator
{
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
yield [__DIR__ . '/Wrong/wrong2.php.inc', __DIR__ . '/Correct/correct2.php.inc'];
yield [__DIR__ . '/Wrong/wrong3.php.inc', __DIR__ . '/Correct/correct3.php.inc'];
}
protected function provideConfig(): string
{
return __DIR__ . '/config.yml';
}
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source;
class ControllerClass
{
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source;
final class FormBuilder
{
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source;
final class FormType
{
}

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
class SomeController extends ControllerClass
{
public function action()
{
$form = $this->createForm(new AnotherFormType(), $entity, [
'action' => $this->generateUrl('teams_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form = $this->createForm(new AnotherFormType([1]), $entity);
}
}
final class AnotherFormType
{
/**
* @var array
*/
private $items;
public function __construct(array $items = [])
{
$this->items = $items;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormType;
class SomeAnotherController extends ControllerClass
{
public function action(FormBuilder $builder)
{
$builder->add('someText', new SomeClass);
$form = new FormType();
$form->add('text', new AnotherFormTypeClass);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Wrong;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass;
use Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder;
class SomeAnotherControllerWithArgs extends ControllerClass
{
public function action(FormBuilder $builder)
{
$builder->add('someText', new SomeTypeWithCtor(1));
}
}
class SomeTypeWithCtor
{
/**
* @var int
*/
private $number;
public function __construct(int $number)
{
$this->number = $number;
}
}

View File

@ -0,0 +1,5 @@
services:
Rector\Symfony\Rector\MethodCall\FormTypeInstanceToClassConstRector:
$controllerClass: 'Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\ControllerClass'
$formBuilderType: 'Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormBuilder'
$formType: 'Rector\Symfony\Tests\Rector\MethodCall\FormTypeInstanceToClassConstRector\Source\FormType'

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Process\ProcessBuilderGetProcessRector;
namespace Rector\Symfony\Tests\Rector\Process\ProcessBuilderGetProcessRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Process\ProcessBuilderInstanceRector;
namespace Rector\Symfony\Tests\Rector\Process\ProcessBuilderInstanceRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Validator\ConstraintUrlOptionRector;
namespace Rector\Symfony\Tests\Rector\Validator\ConstraintUrlOptionRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\VarDumper\VarDumperTestTraitMethodArgsRector;
namespace Rector\Symfony\Tests\Rector\VarDumper\VarDumperTestTraitMethodArgsRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Yaml\ParseFileRector;
namespace Rector\Symfony\Tests\Rector\Yaml\ParseFileRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Yaml\SessionStrictTrueByDefaultYamlRector;
namespace Rector\Symfony\Tests\Rector\Yaml\SessionStrictTrueByDefaultYamlRector;
use Iterator;
use Rector\YamlRector\Tests\AbstractYamlRectorTest;

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Symfony\Tests\Yaml\SpaceBetweenKeyAndValueYamlRector;
namespace Rector\Symfony\Tests\Rector\Yaml\SpaceBetweenKeyAndValueYamlRector;
use Iterator;
use Rector\YamlRector\Tests\AbstractYamlRectorTest;

View File

@ -46,6 +46,7 @@ parameters:
- '#Call to function in_array\(\) with arguments string, (.*?) and true will always evaluate to false#'
# known values
# - '#Call to an undefined method PhpParser\\Node\\Expr|PhpParser\\Node\\Name|PhpParser\\Node\\Stmt\\Class_::toString\(\)#'
- '#Method Rector\\ContributorTools\\Configuration\\ConfigurationFactory::resolveCategoryFromFqnNodeTypes\(\) should return string but returns string\|false#'
- '#Array \(array<PhpParser\\Node\\Expr\\MethodCall>\) does not accept PhpParser\\Node\\Expr#'
- '#Cannot access property \$expr on PhpParser\\Node\\Stmt\|null#'

View File

@ -26,6 +26,8 @@ final class AutoloadWrongCasesEventSubscriber
self::$wrongDirectories = array_merge(self::$wrongDirectories, self::getWrongDirectoriesInPath($path));
}
sort(self::$wrongDirectories);
$package = $event->getComposer()->getPackage();
$autoload = $package->getDevAutoload();
$autoload['classmap'] = array_merge($autoload['classmap'] ?? [], self::$wrongDirectories);
@ -40,7 +42,7 @@ final class AutoloadWrongCasesEventSubscriber
$globResult = self::globRecursive($path, GLOB_ONLYDIR);
return array_filter($globResult, function ($name) {
return strpos($name, '/Wrong');
return strpos($name, '/Wrong') && ! strpos($name, 'ContributorTools');
});
}