Merge pull request #3781 from rectorphp/nested-factory

[Nette] add support for connection with method call
This commit is contained in:
Tomas Votruba 2020-07-25 01:02:41 +02:00 committed by GitHub
commit c91d5b603e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 226 additions and 22 deletions

View File

@ -380,3 +380,5 @@ parameters:
-
message: '#Separate function "Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ref\(\)" in method call to standalone row to improve readability#'
path: 'packages/rector-generator/config/config.php'
- '#Method Rector\\Nette\\NodeResolver\\FormVariableInputNameTypeResolver\:\:findPreviousAssignToVariable\(\) should return PhpParser\\Node\\Expr\\Assign\|null but returns PhpParser\\Node\|null#'

View File

@ -166,27 +166,18 @@ final class FormVariableInputNameTypeResolver
*/
private function resolveExternalMethodNamesByInputNames(Variable $formVariable): array
{
/** @var Assign|null $formVariableAssignNode */
$formVariableAssignNode = $this->betterNodeFinder->findFirstPrevious($formVariable, function (Node $node) use (
$formVariable
) {
if (! $node instanceof Assign) {
return false;
}
return $this->betterStandardPrinter->areNodesEqual($node->var, $formVariable);
});
if ($formVariableAssignNode === null) {
/** @var Assign|null $formVariableAssign */
$formVariableAssign = $this->findPreviousAssignToVariable($formVariable);
if ($formVariableAssign === null) {
return [];
}
if ($formVariableAssignNode->expr instanceof New_) {
return $this->resolveFromNew($formVariableAssignNode->expr);
if ($formVariableAssign->expr instanceof New_) {
return $this->resolveFromNew($formVariableAssign->expr);
}
if ($formVariableAssignNode->expr instanceof MethodCall) {
return $this->resolveFromMethodCall($formVariableAssignNode->expr);
if ($formVariableAssign->expr instanceof MethodCall) {
return $this->resolveFromMethodCall($formVariableAssign->expr);
}
return [];
@ -255,7 +246,10 @@ final class FormVariableInputNameTypeResolver
return [];
}
return $this->resolveMethodNamesByInputNames($lastReturn->expr);
$initialAssignMethodNamesByInputNames = $this->resolveInitialVariableAssignMethodNamesByInputNames($lastReturn);
$previousMethodCallMethodNamesByInputNames = $this->resolveMethodNamesByInputNames($lastReturn->expr);
return array_merge($initialAssignMethodNamesByInputNames, $previousMethodCallMethodNamesByInputNames);
}
/**
@ -271,4 +265,40 @@ final class FormVariableInputNameTypeResolver
return $this->resolveMethodNamesByInputNames($thisVariable);
}
private function findPreviousAssignToVariable(Variable $variable): ?Assign
{
return $this->betterNodeFinder->findFirstPrevious($variable, function (Node $node) use ($variable) {
if (! $node instanceof Assign) {
return false;
}
return $this->betterStandardPrinter->areNodesEqual($node->var, $variable);
});
}
/**
* @return array<string, string>
*/
private function resolveInitialVariableAssignMethodNamesByInputNames(Return_ $return): array
{
if (! $return->expr instanceof Variable) {
return [];
}
$initialAssign = $this->findPreviousAssignToVariable($return->expr);
if (! $initialAssign instanceof Assign) {
return [];
}
if ($initialAssign->expr instanceof MethodCall) {
return $this->resolveFromMethodCall($initialAssign->expr);
}
if ($initialAssign->expr instanceof New_) {
return $this->resolveFromNew($initialAssign->expr);
}
return [];
}
}

View File

@ -0,0 +1,103 @@
<?php
namespace Rector\Nette\Tests\Rector\ArrayDimFetch\ChangeFormArrayAccessToAnnotatedControlVariableRector\Fixture;
use Nette\Application\UI\Form;
class NestedFactory
{
/**
* @var FormWithTitleFactory
*/
private $formWithTitleFactory;
public function __construct(FormWithTitleFactory $formWithTitleFactory)
{
$this->formWithTitleFactory = $formWithTitleFactory;
}
public function run()
{
$form = $this->makeForm();
$form['title']->value = 'foo';
$form['another_title']->value = 'bar';
}
public function makeForm(): Form
{
$form = $this->formWithTitleFactory->create();
$form->addText('another_title');
return $form;
}
}
interface FormWithTitleFactory
{
public function create(): FormWithTitle;
}
class FormWithTitle extends Form
{
public function __construct()
{
$this->addText('title');
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\ArrayDimFetch\ChangeFormArrayAccessToAnnotatedControlVariableRector\Fixture;
use Nette\Application\UI\Form;
class NestedFactory
{
/**
* @var FormWithTitleFactory
*/
private $formWithTitleFactory;
public function __construct(FormWithTitleFactory $formWithTitleFactory)
{
$this->formWithTitleFactory = $formWithTitleFactory;
}
public function run()
{
$form = $this->makeForm();
/** @var \Nette\Forms\Controls\TextInput $titleControl */
$titleControl = $form['title'];
$titleControl->value = 'foo';
/** @var \Nette\Forms\Controls\TextInput $anotherTitleControl */
$anotherTitleControl = $form['another_title'];
$anotherTitleControl->value = 'bar';
}
public function makeForm(): Form
{
$form = $this->formWithTitleFactory->create();
$form->addText('another_title');
return $form;
}
}
interface FormWithTitleFactory
{
public function create(): FormWithTitle;
}
class FormWithTitle extends Form
{
public function __construct()
{
$this->addText('title');
}
}
?>

View File

@ -0,0 +1,73 @@
<?php
namespace Rector\Nette\Tests\Rector\ArrayDimFetch\ChangeFormArrayAccessToAnnotatedControlVariableRector\Fixture;
use Nette\Application\UI\Form;
class NestedFactoryAndNew
{
public function run()
{
$form = $this->makeForm();
$form['title']->value = 'foo';
$form['another_title']->value = 'bar';
}
public function makeForm(): Form
{
$form = new FormWithTitleLocal();
$form->addText('another_title');
return $form;
}
}
class FormWithTitleLocal extends Form
{
public function __construct()
{
$this->addText('title');
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\ArrayDimFetch\ChangeFormArrayAccessToAnnotatedControlVariableRector\Fixture;
use Nette\Application\UI\Form;
class NestedFactoryAndNew
{
public function run()
{
$form = $this->makeForm();
/** @var \Nette\Forms\Controls\TextInput $titleControl */
$titleControl = $form['title'];
$titleControl->value = 'foo';
/** @var \Nette\Forms\Controls\TextInput $anotherTitleControl */
$anotherTitleControl = $form['another_title'];
$anotherTitleControl->value = 'bar';
}
public function makeForm(): Form
{
$form = new FormWithTitleLocal();
$form->addText('another_title');
return $form;
}
}
class FormWithTitleLocal extends Form
{
public function __construct()
{
$this->addText('title');
}
}
?>

View File

@ -187,11 +187,7 @@ final class MethodCallManipulator
{
$callerNode = $methodCall->var;
while ($callerNode instanceof MethodCall || $callerNode instanceof StaticCall) {
if ($callerNode instanceof StaticCall) {
$callerNode = $callerNode->class;
} else {
$callerNode = $callerNode->var;
}
$callerNode = $callerNode instanceof StaticCall ? $callerNode->class : $callerNode->var;
}
return $callerNode;