Open
Description
+use Symfony\Component\HttpFoundation\Response;
class SomeController extends AbstractController
{
-public function createTemplate(): JsonResponse
+public function createTemplate(): Response
{
- return new JsonResponse(['data' => $response], JsonResponse::HTTP_OK);
+ return $this->json(['data' => $response], Response::HTTP_OK);
}
}
I would like know if it is possible include a symfony rule that renames all constants JsonResponse::HTTP_OK or JsonResponse::*
to Response::HTTP_OK or Response::*
This solves warnings in IDE like:
"Constant from class 'Symfony\Component\HttpFoundation\Response' referenced through child."
And put the good practice of use $this->json() method instead return the object new JsonResponse()
Also the return typing changing
:JsonResponse
to
:Response
src/Rector/Response/JsonResponseToControllerJsonRector.php
<?php
declare(strict_types=1);
namespace Utils\Rector\Rector;
use PhpParser\Node;
use Rector\Rector\AbstractRector;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Name;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Name\FullyQualified;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\TypeDeclaration\Rector\JsonResponseToControllerJsonRector\JsonResponseToControllerJsonRectorTest
*/
final class JsonResponseToControllerJsonRector extends AbstractRector
{
/**
* Adds a 'use' import for the given class if it does not already exist.
*/
private function addUseImportToFile(Node $node, string $className): void
{
$file = $node->getAttribute('file');
if ($file && method_exists($this, 'addUseType')) {
// For compatibility with Rector's addUseType if available
$this->addUseType($node, $className);
return;
}
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, ClassConstFetch::class, New_::class];
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Replace JsonResponse with Response and use $this->json()', [
new CodeSample(
badCode: <<<'CODE'
use Symfony\Component\HttpFoundation\JsonResponse;
class SomeController extends AbstractController
{
public function createTemplate(): JsonResponse
{
return new JsonResponse(['data' => $response], JsonResponse::HTTP_OK);
}
}
CODE
,
goodCode: <<<'CODE'
use Symfony\Component\HttpFoundation\Response;
class SomeController extends AbstractController
{
public function createTemplate(): Response
{
return $this->json(['data' => $response], Response::HTTP_OK);
}
}
CODE
)
]);
}
public function refactor(Node $node): ?Node
{
// Replace return new JsonResponse(...) with $this->json(...)
if ($node instanceof New_ && $this->getName($node->class) === JsonResponse::class) {
// Corner case: new JsonResponse() with no arguments
if (count($node->args) === 0) {
// Ensure 'use Symfony\Component\HttpFoundation\Response;' is present
$this->addUseImportToFile($node, Response::class);
return new MethodCall(
new Node\Expr\Variable('this'),
'json',
[
new Node\Arg(new Node\Expr\Array_([])),
new Node\Arg(new ClassConstFetch(new Name('Response'), 'HTTP_OK'))
]
);
}
return new MethodCall(new Node\Expr\Variable('this'), 'json', $node->args);
}
// Replace JsonResponse::HTTP_* with Response::HTTP_*
if ($node instanceof ClassConstFetch && $this->getName($node->class) === JsonResponse::class) {
// Ensure 'use Symfony\Component\HttpFoundation\Response;' is present
$this->addUseImportToFile($node, Response::class);
$node->class = new Name('Response');
return $node;
}
// Change return type from JsonResponse to Response
if ($node instanceof ClassMethod) {
if ($node->returnType instanceof Name && $this->getName($node->returnType) === JsonResponse::class) {
$node->returnType = new FullyQualified(Response::class);
return $node;
}
}
return null;
}
}
Using in rector.php
use App\Rector\Response\JsonResponseToControllerJsonRector;
return static function (Rector\Config\RectorConfig $rectorConfig): void {
$rectorConfig->paths([__DIR__ . '/src']);
$rectorConfig->rule(JsonResponseToControllerJsonRector::class);
$rectorConfig->importNames();
};
Test before:
use Symfony\Component\HttpFoundation\JsonResponse;
public function index(): JsonResponse
{
return new JsonResponse(['message' => 'ok'], JsonResponse::HTTP_OK);
}
Test after:
use Symfony\Component\HttpFoundation\Response;
public function index(): Response
{
return $this->json(['message' => 'ok'], Response::HTTP_OK);
}
Metadata
Metadata
Assignees
Labels
No labels