From 2c3950017d4319fbc516b9843e862b7aa69921da Mon Sep 17 00:00:00 2001
From: Matthieu Aubry <mattab@users.noreply.github.com>
Date: Thu, 1 Dec 2016 20:56:42 +1300
Subject: [PATCH] Make JSON2 the now JSON formatting to fix an issue in
 formatting associative array (#10928)

* Make JSON2 the now JSON formatting to fix an issue in formatting associative arrays

* fix unit test

* Minor changes

* call API with json format in the Angular JS frontend

* Log Analytics
---
 CHANGELOG.md                                    |  1 +
 misc/log-analytics                              |  2 +-
 plugins/API/Renderer/Json.php                   | 15 +++++++++++----
 plugins/API/Renderer/Json2.php                  | 17 +----------------
 plugins/API/tests/Unit/JsonRendererTest.php     |  9 +++------
 plugins/CoreAdminHome/Controller.php            |  2 +-
 .../angularjs/common/services/piwik-api.js      |  2 +-
 .../angularjs/common/services/piwik-api.spec.js | 10 +++++-----
 8 files changed, 24 insertions(+), 34 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b515fab5ec..8d4b22af65 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ The Product Changelog at **[piwik.org/changelog](http://piwik.org/changelog)** l
 Read more about migrating a plugin from Piwik 2.X to Piwik 3 in [our Migration guide](http://developer.piwik.org/guides/migrate-piwik-2-to-3).
 
 ### Breaking Changes
+* Reporting API: if you call the Reporting API requesting data in `json` format then you may be affected. The `json` formatting has changed, a bug was fixed so that API methods that return simple associative arrays like `array('name' => 'value', 'name2' => 'value2')` will now appear correctly as `{"name":"value","name2":"value2"}` in JSON API output instead of `[{"name":"value","name2":"value2"}]` (as it used to be in Piwik 2). API methods like **SitesManager.getSiteFromId** & **UsersManager.getUser** and others are affected.
 * The menu classes `Piwik\Menu\MenuReporting` and `Piwik\Menu\MenuMain` have been removed
 * The class `Piwik\Plugin\Widgets` has been removed and replaced by `Piwik\Widget\Widget`. For each widget one class is needed from now on. You can generate a widget via `./console generate:widget`.
 * The class `Piwik\WidgetList` class has been moved to `Piwik\Widget\WidgetsList`.
diff --git a/misc/log-analytics b/misc/log-analytics
index eb0132eec6..26049b008b 160000
--- a/misc/log-analytics
+++ b/misc/log-analytics
@@ -1 +1 @@
-Subproject commit eb0132eec6a05e2c15154cf8b1378787183ae8d7
+Subproject commit 26049b008b2ce3cbb9e7179a94033db5475ad698
diff --git a/plugins/API/Renderer/Json.php b/plugins/API/Renderer/Json.php
index 8adfdaebe1..1f7591370b 100644
--- a/plugins/API/Renderer/Json.php
+++ b/plugins/API/Renderer/Json.php
@@ -17,9 +17,6 @@ use Piwik\ProxyHttp;
 /**
  * API output renderer for JSON.
  *
- * **NOTE: This is the old JSON format. It includes bugs that are fixed in the JSON2 API output
- * format. Please use that format instead of this.**
- *
  * @deprecated
  */
 class Json extends ApiRenderer
@@ -61,7 +58,17 @@ class Json extends ApiRenderer
             return $this->applyJsonpIfNeeded($result);
         }
 
-        return $this->renderDataTable($array);
+        $result = $this->renderDataTable($array);
+
+        // if $array is a simple associative array, remove the JSON root array that is added by renderDataTable
+        if (!empty($array)
+            && Piwik::isAssociativeArray($array)
+            && !Piwik::isMultiDimensionalArray($array)
+        ) {
+            $result = substr($result, 1, strlen($result) - 2);
+        }
+
+        return $result;
     }
 
     public function sendHeader()
diff --git a/plugins/API/Renderer/Json2.php b/plugins/API/Renderer/Json2.php
index 898fe6a9ce..bd27810fb8 100644
--- a/plugins/API/Renderer/Json2.php
+++ b/plugins/API/Renderer/Json2.php
@@ -11,23 +11,8 @@ namespace Piwik\Plugins\API\Renderer;
 use Piwik\Piwik;
 
 /**
- * Correct API output renderer for JSON. Includes bug fixes for bugs in the old JSON API
- * format.
+ * Left here for Backward compatibility in Piwik 3.X+ for all users who correctly used format=json2 during Piwik 2.X
  */
 class Json2 extends Json
 {
-    public function renderArray($array)
-    {
-        $result = parent::renderArray($array);
-
-        // if $array is a simple associative array, remove the JSON root array that is added by renderDataTable
-        if (!empty($array)
-            && Piwik::isAssociativeArray($array)
-            && !Piwik::isMultiDimensionalArray($array)
-        ) {
-            $result = substr($result, 1, strlen($result) - 2);
-        }
-
-        return $result;
-    }
 }
\ No newline at end of file
diff --git a/plugins/API/tests/Unit/JsonRendererTest.php b/plugins/API/tests/Unit/JsonRendererTest.php
index 68ed45b9f3..ea7f5d69d4 100644
--- a/plugins/API/tests/Unit/JsonRendererTest.php
+++ b/plugins/API/tests/Unit/JsonRendererTest.php
@@ -356,17 +356,14 @@ class JsonRendererTest extends \PHPUnit_Framework_TestCase
         $this->assertNoJsonError($actual);
     }
 
-    /**
-     * backwards compatibility test
-     */
-    public function test_oldJson_renderArray_ShouldConvertSingleDimensionalAssociativeArray()
+    public function test_json_renderArray_ShouldConvertSingleDimensionalAssociativeArray()
     {
         $input = array(
             "firstElement" => "isFirst",
             "secondElement" => "isSecond"
         );
 
-        $expected = '[{"firstElement":"isFirst","secondElement":"isSecond"}]';
+        $expected = '{"firstElement":"isFirst","secondElement":"isSecond"}';
 
         $oldJsonBuilder = new Json($input);
         $actual = $oldJsonBuilder->renderArray($input);
@@ -376,7 +373,7 @@ class JsonRendererTest extends \PHPUnit_Framework_TestCase
 
     private function makeBuilder($request)
     {
-        return new Json2($request);
+        return new Json($request);
     }
 
     private function assertNoJsonError($response)
diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php
index 7621aa1f78..3531623eef 100644
--- a/plugins/CoreAdminHome/Controller.php
+++ b/plugins/CoreAdminHome/Controller.php
@@ -114,7 +114,7 @@ class Controller extends ControllerAdmin
             return '';
         }
 
-        $response = new ResponseBuilder('json2');
+        $response = new ResponseBuilder('json');
         try {
             $this->checkTokenInUrl();
 
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-api.js b/plugins/CoreHome/angularjs/common/services/piwik-api.js
index ab546a7693..ab6ee9c30d 100644
--- a/plugins/CoreHome/angularjs/common/services/piwik-api.js
+++ b/plugins/CoreHome/angularjs/common/services/piwik-api.js
@@ -249,7 +249,7 @@ var hasBlockedContent = false;
             getParams.module = getParams.module || 'API';
 
             if (!getParams.format) {
-                getParams.format = 'JSON2';
+                getParams.format = 'JSON';
             }
 
             addParams(getParams);
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-api.spec.js b/plugins/CoreHome/angularjs/common/services/piwik-api.spec.js
index 1faf387ea3..a51067ea46 100644
--- a/plugins/CoreHome/angularjs/common/services/piwik-api.spec.js
+++ b/plugins/CoreHome/angularjs/common/services/piwik-api.spec.js
@@ -55,7 +55,7 @@
             piwikApi.fetch({
                 method: "SomePlugin.action"
             }).then(function (response) {
-                expect(response).to.equal("Request url: index.php?date=&format=JSON2&idSite=1&method=SomePlugin.action&module=API&period=day");
+                expect(response).to.equal("Request url: index.php?date=&format=JSON&idSite=1&method=SomePlugin.action&module=API&period=day");
 
                 done();
             }).catch(function (ex) {
@@ -115,7 +115,7 @@
             piwikApi.fetch({
                 method: "SomePlugin.action"
             }).then(function (response) {
-                expect(response).to.equal("Request url: index.php?date=&format=JSON2&idSite=1&method=SomePlugin.action&module=API&period=day");
+                expect(response).to.equal("Request url: index.php?date=&format=JSON&idSite=1&method=SomePlugin.action&module=API&period=day");
 
                 request1Done = true;
 
@@ -127,7 +127,7 @@
             piwikApi.fetch({
                 method: "SomeOtherPlugin.action"
             }).then(function (response) {
-                expect(response).to.equal("Request url: index.php?date=&format=JSON2&idSite=1&method=SomeOtherPlugin.action&module=API&period=day");
+                expect(response).to.equal("Request url: index.php?date=&format=JSON&idSite=1&method=SomeOtherPlugin.action&module=API&period=day");
 
                 request2Done = true;
 
@@ -160,7 +160,7 @@
             piwikApi.fetch({
                 method: "SomeOtherPlugin.action"
             }).then(function (response) {
-                expect(response).to.equal("Request url: index.php?date=&format=JSON2&idSite=1&method=SomeOtherPlugin.action&module=API&period=day");
+                expect(response).to.equal("Request url: index.php?date=&format=JSON&idSite=1&method=SomeOtherPlugin.action&module=API&period=day");
 
                 request2Done = true;
 
@@ -216,7 +216,7 @@
                     method: "SomeOtherPlugin.action"
                 }
             ]).then(function (response) {
-                var restOfExpected = "index.php?date=&format=JSON2&idSite=1&method=API.getBulkRequest&" +
+                var restOfExpected = "index.php?date=&format=JSON&idSite=1&method=API.getBulkRequest&" +
                     "module=API&period=day - urls%5B%5D=%3Fmethod%3DSomePlugin.action%26param%3D" +
                     "value&urls%5B%5D=%3Fmethod%3DSomeOtherPlugin.action&token_auth=100bf5eeeed1468f3f9d93750044d3dd";
 
-- 
GitLab