From a6f59e323385e6aa62cc1678f6fbc2e06ab4cab7 Mon Sep 17 00:00:00 2001
From: Nathan Phillip Brink <binki@gentoo.org>
Date: Tue, 26 Jun 2012 13:16:26 +0000
Subject: [PATCH] Issue #1356170 by tim.plunkett: Remove uses of array_merge_recursive() and add some tests for places where drupal_array_merge_deep() needs to be used instead.

---
 core/includes/ajax.inc                             |    2 +-
 core/includes/module.inc                           |    2 +-
 core/modules/file/file.module                      |    2 +-
 core/modules/node/node.pages.inc                   |    2 +-
 .../lib/Drupal/system/Tests/Ajax/CommandsTest.php  |    8 +++++++
 core/modules/system/system.module                  |    2 +-
 .../modules/ajax_forms_test/ajax_forms_test.module |   23 ++++++++++++++++++++
 core/modules/translation/translation.pages.inc     |    2 +-
 8 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index ede35da..c286d9c 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -292,7 +292,7 @@ function ajax_render($commands = array()) {
   $scripts = drupal_add_js();
   if (!empty($scripts['settings'])) {
     $settings = $scripts['settings'];
-    array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
+    array_unshift($commands, ajax_command_settings(drupal_array_merge_deep_array($settings['data']), TRUE));
   }
 
   // Allow modules to alter any Ajax response.
diff --git a/core/includes/module.inc b/core/includes/module.inc
index a71cb18..6d4e99b 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -782,7 +782,7 @@ function module_hook_info() {
         if (function_exists($function)) {
           $result = $function();
           if (isset($result) && is_array($result)) {
-            $hook_info = array_merge_recursive($hook_info, $result);
+            $hook_info = drupal_array_merge_deep($hook_info, $result);
           }
         }
       }
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 6541e8d..f4403c5 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -283,7 +283,7 @@ function file_ajax_upload() {
 
   $output = theme('status_messages') . drupal_render($form);
   $js = drupal_add_js();
-  $settings = call_user_func_array('array_merge_recursive', $js['settings']['data']);
+  $settings = drupal_array_merge_deep_array($js['settings']['data']);
 
   $commands = array();
   $commands[] = ajax_command_replace(NULL, $output, $settings);
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index faa3dea..725df98 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -176,7 +176,7 @@ function node_form($form, &$form_state, Node $node) {
   //   handlers to the form buttons below. Remove hook_form() entirely.
   $function = node_type_get_base($node) . '_form';
   if (function_exists($function) && ($extra = $function($node, $form_state))) {
-    $form = array_merge_recursive($form, $extra);
+    $form = drupal_array_merge_deep($form, $extra);
   }
   // If the node type has a title, and the node type form defined no special
   // weight for it, we default to a weight of -5 for consistency.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Ajax/CommandsTest.php b/core/modules/system/lib/Drupal/system/Tests/Ajax/CommandsTest.php
index 299b674..d8e71a9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Ajax/CommandsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Ajax/CommandsTest.php
@@ -157,5 +157,13 @@ class CommandsTest extends AjaxTestBase {
       'settings' => array('ajax_forms_test' => array('foo' => 42)),
     );
     $this->assertCommand($commands, $expected, "'settings' AJAX command issued with correct data");
+
+    // Test that the settings command merges settings properly
+    $commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'settings' command with setting merging")));
+    $expected = array(
+      'command' => 'settings',
+      'settings' => array('ajax_forms_test' => array('foo' => 9001)),
+    );
+    $this->assertCommand($commands, $expected, "'settings' AJAX command with setting merging");
   }
 }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index b32187a..76a74fe 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -4002,7 +4002,7 @@ function _system_date_formats_build() {
 
     // If another module already set this format, merge in the new settings.
     if (isset($date_formats[$module_format['type']][$module_format['format']])) {
-      $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $module_format);
+      $date_formats[$module_format['type']][$module_format['format']] = drupal_array_merge_deep($date_formats[$module_format['type']][$module_format['format']], $module_format);
     }
     else {
       // This setting will be overridden later if it already exists in the db.
diff --git a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
index 6a95710..4d74c4c 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
+++ b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
@@ -258,6 +258,18 @@ function ajax_forms_test_ajax_commands_form($form, &$form_state) {
     ),
   );
 
+  // Tests the 'settings' command with a callback which sets the same
+  // setting multiple times. This is used to check that settings are
+  // merged properly (e.g., array_merge_recursive() merges settings
+  // incorrectly, #1356170).
+  $form['settings_command_with_merging_example'] = array(
+    '#type' => 'submit',
+    '#value' => t("AJAX 'settings' command with setting merging"),
+    '#ajax' => array(
+      'callback' => 'ajax_forms_test_advanced_commands_settings_with_merging_callback',
+    ),
+  );
+
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Submit'),
@@ -410,6 +422,17 @@ function ajax_forms_test_advanced_commands_settings_callback($form, $form_state)
   return array('#type' => 'ajax', '#commands' => $commands);
 }
 
+
+/**
+ * Ajax callback for 'settings' but with setting overrides.
+ */
+function ajax_forms_test_advanced_commands_settings_with_merging_callback($form, $form_state) {
+  drupal_add_js(array('ajax_forms_test' => array('foo' => 42)), 'setting');
+  drupal_add_js(array('ajax_forms_test' => array('foo' => 9001)), 'setting');
+
+  return array('#type' => 'ajax', '#commands' => array());
+}
+
 /**
  * This form and its related submit and callback functions demonstrate
  * not validating another form element when a single Ajax element is triggered.
diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc
index a6e8b3c..bd150ef 100644
--- a/core/modules/translation/translation.pages.inc
+++ b/core/modules/translation/translation.pages.inc
@@ -65,7 +65,7 @@ function translation_node_overview(Node $node) {
         $path = 'node/add/' . $node->type;
         $links = language_negotiation_get_switch_links($type, $path);
         $query = array('query' => array('translation' => $node->nid, 'target' => $langcode));
-        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
+        $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], drupal_array_merge_deep($links->links[$langcode], $query));
       }
       $status = t('Not translated');
     }
-- 
1.7.3.4

