Skip to content

Commit

Permalink
Fix FactoryDefinitionRector to work with arrow functions (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeniJaho committed May 7, 2024
1 parent 415aa9a commit a2a7f52
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 18 deletions.
25 changes: 13 additions & 12 deletions src/NodeFactory/ModelFactoryNodeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
Expand Down Expand Up @@ -66,13 +67,13 @@ public function createEmptyFactory(string $name, Expr $expr): Class_
return $class;
}

public function createDefinition(Closure $closure): ClassMethod
public function createDefinition(Closure|ArrowFunction $callable): ClassMethod
{
if (isset($closure->params[0])) {
$this->fakerVariableToPropertyFetch($closure->stmts, $closure->params[0]);
if (isset($callable->params[0])) {
$this->fakerVariableToPropertyFetch($callable->getStmts(), $callable->params[0]);
}

return $this->createPublicMethod('definition', $closure->stmts);
return $this->createPublicMethod('definition', $callable->getStmts());
}

public function createStateMethod(MethodCall $methodCall): ?ClassMethod
Expand All @@ -87,8 +88,8 @@ public function createStateMethod(MethodCall $methodCall): ?ClassMethod

$thirdArgValue = $methodCall->args[2]->value;
// the third argument may be closure or array
if ($thirdArgValue instanceof Closure && isset($thirdArgValue->params[0])) {
$this->fakerVariableToPropertyFetch($thirdArgValue->stmts, $thirdArgValue->params[0]);
if (($thirdArgValue instanceof Closure || $thirdArgValue instanceof ArrowFunction) && isset($thirdArgValue->params[0])) {
$this->fakerVariableToPropertyFetch($thirdArgValue->getStmts(), $thirdArgValue->params[0]);
unset($thirdArgValue->params[0]);
}

Expand Down Expand Up @@ -117,11 +118,11 @@ public function createEmptyConfigure(): ClassMethod
return $this->createPublicMethod('configure', [$return]);
}

public function appendConfigure(ClassMethod $classMethod, string $name, Closure $closure): void
public function appendConfigure(ClassMethod $classMethod, string $name, Closure|ArrowFunction $callable): void
{
$this->simpleCallableNodeTraverser->traverseNodesWithCallable(
(array) $classMethod->stmts,
function (Node $node) use ($closure, $name): ?Return_ {
function (Node $node) use ($callable, $name): ?Return_ {
if (! $node instanceof Return_) {
return null;
}
Expand All @@ -130,13 +131,13 @@ function (Node $node) use ($closure, $name): ?Return_ {
return null;
}

if (isset($closure->params[1])) {
$this->fakerVariableToPropertyFetch($closure->stmts, $closure->params[1]);
if (isset($callable->params[1])) {
$this->fakerVariableToPropertyFetch($callable->getStmts(), $callable->params[1]);
// remove argument $faker
unset($closure->params[1]);
unset($callable->params[1]);
}

$node->expr = $this->nodeFactory->createMethodCall($node->expr, $name, [$closure]);
$node->expr = $this->nodeFactory->createMethodCall($node->expr, $name, [$callable]);

return $node;
}
Expand Down
13 changes: 7 additions & 6 deletions src/Rector/Namespace_/FactoryDefinitionRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\Closure;
Expand Down Expand Up @@ -207,12 +208,12 @@ private function addDefinition(Class_ $class, MethodCall $methodCall): void
return;
}

$callback = $methodCall->args[1]->value;
if (! $callback instanceof Closure) {
$callable = $methodCall->args[1]->value;
if (! $callable instanceof Closure && ! $callable instanceof ArrowFunction) {
return;
}

$class->stmts[] = $this->modelFactoryNodeFactory->createDefinition($callback);
$class->stmts[] = $this->modelFactoryNodeFactory->createDefinition($callable);
}

private function addState(Class_ $class, MethodCall $methodCall): void
Expand All @@ -235,8 +236,8 @@ private function appendAfterCalling(Class_ $class, MethodCall $methodCall, strin
return;
}

$closure = $methodCall->args[1]->value;
if (! $closure instanceof Closure) {
$callable = $methodCall->args[1]->value;
if (! $callable instanceof Closure && ! $callable instanceof ArrowFunction) {
return;
}

Expand All @@ -246,6 +247,6 @@ private function appendAfterCalling(Class_ $class, MethodCall $methodCall, strin
$class->stmts[] = $method;
}

$this->modelFactoryNodeFactory->appendConfigure($method, $name, $closure);
$this->modelFactoryNodeFactory->appendConfigure($method, $name, $callable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace RectorLaravel\Tests\Rector\Namespace_\FactoryDefinitionRector\Fixture;

use RectorLaravel\Tests\Rector\Namespace_\FactoryDefinitionRector\Source\Model;

$factory->define(Model::class, fn ($faker) => [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
]);

$factory->state(Model::class, 'address', fn ($faker) => [
'address' => $faker->address,
]);

$factory->afterMaking(Model::class, fn (Model $user, $faker) => $user->name = $faker->name);

$factory->afterCreating(Model::class, fn (Model $user, $faker) => $user->name = $faker->name);

?>
-----
<?php

namespace RectorLaravel\Tests\Rector\Namespace_\FactoryDefinitionRector\Fixture;

use RectorLaravel\Tests\Rector\Namespace_\FactoryDefinitionRector\Source\Model;
class ModelFactory extends \Illuminate\Database\Eloquent\Factories\Factory
{
protected $model = Model::class;
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
];
}
public function address()
{
return $this->state(fn() => [
'address' => $this->faker->address,
]);
}
public function configure()
{
return $this->afterMaking(fn (Model $user) => $user->name = $this->faker->name)->afterCreating(fn (Model $user) => $user->name = $this->faker->name);
}
}

?>

0 comments on commit a2a7f52

Please sign in to comment.