From 7baf954aef2a3e7e0900cb3e2ff76b4c9103399e Mon Sep 17 00:00:00 2001
From: Tomas Votruba <tomas.vot@gmail.com>
Date: Wed, 7 Aug 2019 19:47:26 +0200
Subject: [PATCH] add implode support to
 ManualJsonStringToJsonEncodeArrayRector

---
 ...anualJsonStringToJsonEncodeArrayRector.php | 57 ++++++++++++++++---
 .../Fixture/with_implode.php.inc              | 31 ++++++++++
 ...lJsonStringToJsonEncodeArrayRectorTest.php |  1 +
 3 files changed, 82 insertions(+), 7 deletions(-)
 create mode 100644 packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/Fixture/with_implode.php.inc

diff --git a/packages/CodingStyle/src/Rector/String_/ManualJsonStringToJsonEncodeArrayRector.php b/packages/CodingStyle/src/Rector/String_/ManualJsonStringToJsonEncodeArrayRector.php
index 48342cfdf8f..4ddcec22323 100644
--- a/packages/CodingStyle/src/Rector/String_/ManualJsonStringToJsonEncodeArrayRector.php
+++ b/packages/CodingStyle/src/Rector/String_/ManualJsonStringToJsonEncodeArrayRector.php
@@ -13,6 +13,7 @@ use PhpParser\Node\Expr\AssignOp\Concat as ConcatAssign;
 use PhpParser\Node\Expr\BinaryOp\Concat;
 use PhpParser\Node\Expr\Variable;
 use PhpParser\Node\Scalar\String_;
+use PhpParser\Node\Stmt\Expression;
 use Rector\CodingStyle\Node\ConcatJoiner;
 use Rector\CodingStyle\Node\ConcatManipulator;
 use Rector\CodingStyle\ValueObject\ConcatExpressionJoinData;
@@ -190,15 +191,18 @@ CODE_SAMPLE
      */
     private function replaceNodeObjectHashPlaceholdersWithNodes(Array_ $array, array $placeholderNodes): void
     {
-        // traverse and replace placeholdes by original nodes
+        // traverse and replace placeholder by original nodes
         $this->traverseNodesWithCallable($array, function (Node $node) use ($placeholderNodes): ?Expr {
-            if (! $node instanceof String_) {
-                return null;
+            if ($node instanceof Array_ && count($node->items) === 1) {
+                $placeholderNode = $this->matchPlaceholderNode($node->items[0]->value, $placeholderNodes);
+
+                if ($placeholderNode && $this->isImplodeToJson($placeholderNode)) {
+                    /** @var Expr\FuncCall $placeholderNode */
+                    return $placeholderNode->args[1]->value;
+                }
             }
 
-            $stringValue = $node->value;
-
-            return $placeholderNodes[$stringValue] ?? null;
+            return $this->matchPlaceholderNode($node, $placeholderNodes);
         });
     }
 
@@ -209,7 +213,7 @@ CODE_SAMPLE
     private function matchNextExpressionAssignConcatToSameVariable(Expr $expr, Node $currentNode): ?array
     {
         $nextExpression = $this->getNextExpression($currentNode);
-        if (! $nextExpression instanceof Node\Stmt\Expression) {
+        if (! $nextExpression instanceof Expression) {
             return null;
         }
 
@@ -298,4 +302,43 @@ CODE_SAMPLE
 
         return $concatExpressionJoinData;
     }
+
+    /**
+     * Matches: "implode('","', $items)"
+     */
+    private function isImplodeToJson(Node $node): bool
+    {
+        if (! $node instanceof Expr\FuncCall) {
+            return false;
+        }
+
+        if (! $this->isName($node, 'implode')) {
+            return false;
+        }
+
+        if (! isset($node->args[1])) {
+            return false;
+        }
+
+        $firstArgumentValue = $node->args[0]->value;
+        if ($firstArgumentValue instanceof String_) {
+            if ($firstArgumentValue->value !== '","') {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @param Expr[] $placeholderNodes
+     */
+    private function matchPlaceholderNode(Node $node, array $placeholderNodes): ?Expr
+    {
+        if (! $node instanceof String_) {
+            return null;
+        }
+
+        return $placeholderNodes[$node->value] ?? null;
+    }
 }
diff --git a/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/Fixture/with_implode.php.inc b/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/Fixture/with_implode.php.inc
new file mode 100644
index 00000000000..51ac467cc1b
--- /dev/null
+++ b/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/Fixture/with_implode.php.inc
@@ -0,0 +1,31 @@
+<?php
+
+namespace Rector\CodingStyle\Tests\Rector\String_\ManualJsonStringToJsonEncodeArrayRector\Fixture;
+
+final class WithImplode
+{
+    public function run()
+    {
+        $jsonRequest = '{"categories":["'.implode(
+                '","',
+                [1, 2, 3]
+            ).'"],"order_by":"random"}';
+    }
+}
+
+?>
+-----
+<?php
+
+namespace Rector\CodingStyle\Tests\Rector\String_\ManualJsonStringToJsonEncodeArrayRector\Fixture;
+
+final class WithImplode
+{
+    public function run()
+    {
+        $jsonData = ['categories' => [1, 2, 3], 'order_by' => 'random'];
+        $jsonRequest = \Nette\Utils\Json::encode($jsonData);
+    }
+}
+
+?>
diff --git a/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/ManualJsonStringToJsonEncodeArrayRectorTest.php b/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/ManualJsonStringToJsonEncodeArrayRectorTest.php
index e005ed75fe3..17070bd9479 100644
--- a/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/ManualJsonStringToJsonEncodeArrayRectorTest.php
+++ b/packages/CodingStyle/tests/Rector/String_/ManualJsonStringToJsonEncodeArrayRector/ManualJsonStringToJsonEncodeArrayRectorTest.php
@@ -15,6 +15,7 @@ final class ManualJsonStringToJsonEncodeArrayRectorTest extends AbstractRectorTe
             __DIR__ . '/Fixture/multiline_concat_json.php.inc',
             __DIR__ . '/Fixture/tripleline_multiline_concat_json.php.inc',
             __DIR__ . '/Fixture/assign_with_concat.php.inc',
+            __DIR__ . '/Fixture/with_implode.php.inc',
         ]);
     }