Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
base system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
29 Nov 2011 at 19:26 UTC
Updated:
1 May 2017 at 08:10 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
tim.plunkettThis is merely to see what the testbot says. I've not yet sat down to think about whether the replacement is appropriate :)
Comment #2
tim.plunkettI can't think of a single place in core where we'd want the value of a string key to become an array, or the value of a numeric key to become appended to a new value.
So I think each of these hunks is valid, and we just need tests to demonstrate why.
Comment #3
xjmSo what we should do here is check these arrays for scalar elements that might be affected.
Comment #4
xjmxpostses, precious.
Comment #5
tim.plunkettI restored #208611: Add drupal_array_merge_deep() and drupal_array_merge_deep_array() to stop drupal_add_js() from adding settings twice to its fixed state, and I'm adding that patch's hunk here.
Still needs tests.
Comment #6
tstoecklerExcept, you're not. There's no ajax_render hunk in there.
Comment #7
sunBecause drupal_array_merge_deep() is slower...?
Comment #8
tim.plunkettWhoops, the patch in #5 was for another issue. I mixed up git diff and git diff --staged. Sorry @tstoeckler.
@sun, of those changes, you could make the case that we're babysitting broken code. If a module tries to implement the same hook_hook_info for tokens and it blows up, that's their fault.
But there are times, like ajax_render, where it should be core's responsibility to take the input and return something useful, not an improperly merged array.
If some of these functions should continue to use array_merge_recursive because we don't care if someone breaks something, that's fine, but let's point that out or add a helpful error message or something.
Comment #10
tim.plunkettMissing parentheses.
Comment #11
tim.plunkettJust some analysis about how these are called, or why they are needed.
Needed for the same reasons as drupal_add_js().
Wrapped in drupal_static().
Wrapped by drupal_static().
Needed for the same reasons as drupal_add_js().
There is a nice @todo here to remove hook_form entirely :)
This is a helper function that is wrapped by drupal_static().
This is a crazy ternary. Wow.
Not sure about this one.
0 days to next Drupal core point release.
Comment #12
tim.plunkettThe other idea I had was to switch the order of the arguments passed to drupal_array_merge_deep() when appropriate. I believe I did this in Views when fixing a similar bug.
If a contrib or custom module caused a key collision with array_merge_recursive, the array would be broken. But with this patch, the offending module would overwrite core, effectively acting like an alter.
In the case of
$info = drupal_array_merge_deep($info, $result);, I suggest that this be switched to$info = drupal_array_merge_deep($result, $info);. I can reroll like that if anyone else agrees.Comment #13
jelle_sFYI:
Blocking #1462410: Clientside validation is not working properly with file component upload button
Comment #14
ohnobinki commentedI can verify that the changes to
core/modules/file/file.moduleandcore/includes/ajax.incfix #1525784: Drupal.settings.content_lock.internal_urls is array instead of string, breaks file.module's JavaScript.Comment #15
ohnobinki commentedThe change to common.inc is obsolete because the use of array_merge_recursive() in drupal_get_filetransfer_info() has been replaced with use of module_invoke_all().
I disagree with the change to user.module. The use of array_merge_recursive() when collecting a set of attributes together will properly gather, for example, multiple settings of the
classattribute into an array which drupal_attributes() will automatically join together with spaces. Changing this behavior, so a new setting of an attribute overwrites a previous one, might not make sense. Now, I understand that if people set$user['attributes_array']['class'] = array('myclass');, drupal_array_merge_deep() will merge those nicely because the arrays use numeric indexes. But if a single module author puts$user['attributes_array']['class'] = 'myclass';(a flat string), then drupal_array_merge_deep() will let the flat string completely override the previous settings for that attribute instead of accumulating them. Perhaps setting theclassattribute using an array is best practice, but I think that a lot of modules still set classes using flat strings... and drupal6 still doesn't support arrays in its drupal_attributes(), so there is a lot of code migrated from drupal6 which would use attributes with flat strings still.Here is a re-roll which fixes the patch not applying in core/includes/common.inc. This re-roll also drops the change regarding attributes, with the above reasoning.
Comment #16
tstoecklerRe #15. Setting a string for
$element['#attributes']['class']is not supported by design.We need to ensure that you can do
$element['#attributes']['class][] = 'my-new-class';from a hook_form_alter() or other alter hooks. It is just one of many things you need to port from your Drupal 6 modules.Comment #17
sun@ohnobinki: Thanks. An interdiff would have been helpful to see the changes since the last patch.
While @ohnobinki's reasoning for skipping damp() in template_process_username() is invalid (as @tstoeckler pointed out), attributes arrays are not deeply nested by design in the first place, so damp() is not really required there.
Second, template_process_username() is potentially called very often and thus in the critical theme/render path, so not using the slower user-space code when it's not strictly required is a good thing for performance.
Tentatively marking this RTBC.
...although I'm not really sure whether the damp() replacements that are fixing actual bugs being reported in other issues shouldn't be split out into those issues (e.g., #1525784: Drupal.settings.content_lock.internal_urls is array instead of string, breaks file.module's JavaScript [which seems to be a duplicate of another Ajax settings issue]). For known functional bugs, we should actually have tests to prevent them in the future. For the other plain damp() replacements without known bugs, we're just applying a code pattern throughout core that is known to merge associative arrays collated by modules in a compatible way.
Comment #18
ohnobinki commentedThis patch adds tests for the use of drupal_array_merge_deep() in the AJAX system.
This still excludes the changes to user.module with regard to @sun's reasoning. If user.module should still be switched to drupal_array_merge_deep(), I can add that to the patch again.
Comment #19
tim.plunkettI had to reroll, split the test into its own patch to prove it works.
Also, any reason not to backport this?
Comment #20
tstoecklerI'm not changing the issue property to avoid infuriating people watching the "bug report" queue, but at least some of the changes contained here are bugfixes, and they should definitely be backported.
Comment #21
tim.plunkettRerolled.
Comment #23
tstoecklerAssuming this comes back green, let's get this in.
Before anyone complains on the usage of the deprecated procedural wrappers for NestedArray, please note that this fixes really, really (!) hard to dissect bugs (I personally was bitten by ajax.inc) that are *impossible* to fix in contrib. We also have lots of other usage of the drupal_array_ functions lying around in core, so this does not make the situation any worse.
Comment #24
tim.plunkettThis is blocked by #1778410: Throw exception when RDF namespaces collide, and the assumptions rdf_get_namespaces() makes about module_invoke_all().
Comment #25
tim.plunkettActually, I discussed that with linclark, and she said it would be appropriate to resolve duplicate namespaces by taking the first defined one.
In addition, to mirror #1705920: Convert all calls to procedural drupal_array_*() functions to Drupal\Component\Utility\NestedArray I've switched everything to using the method.
Comment #27
tim.plunkettIncluding the patch from the other issue.
Comment #28
tim.plunkettYay, that other issue went in.
Comment #29
tstoecklerLooked over everything, including the non-trivial parts (especially rdf.module) and it looks good to go.
Comment #31
tim.plunkett#28: drupal-1356170-28.patch queued for re-testing.
Comment #33
tim.plunkett#28: drupal-1356170-28.patch queued for re-testing.
Comment #34
tim.plunkettUpdating for a recent commit, and marking back to RTBC per #29, that was a random failure.
Comment #36
tim.plunkettRerolled.
Comment #37
tstoecklerStill looks good.
Comment #38
yched commentedThis seems to include all the fixes that were in #791860: array_merge_recursive() is never what we want in Drupal: add a drupal_array_merge_recursive() function instead., so I marked that other one as duplicate.
Comment #39
tim.plunkett#36: array_merge_recursive-1356170-36.patch queued for re-testing.
Comment #40
webchickThis looks like good clean-up. I had two questions while looking through this:
1) How would a normal person not deeply embroiled in the day-to-day commits of D8 ever make the mental leap of array_merge_recursive() => NestedArray::mergeDeepArray()? One would think that there would be the word "Recursive" in the method name to help, and it's confusing that it isn't. When I asked Alex that question, he referred me to the discussion at #208611: Add drupal_array_merge_deep() and drupal_array_merge_deep_array() to stop drupal_add_js() from adding settings twice but that was back when this was a global function, not a method off a class called "NestedArray" which clearly insinuates we're doing something "specialer" than raw PHP. Obviously, not the fault of this issue, but is probably worth a follow-up discussion.
2) Catch had a concern about tests for module_invoke_all() at #791860-33: array_merge_recursive() is never what we want in Drupal: add a drupal_array_merge_recursive() function instead.. However, the patch over there didn't have any test hunk changes and this one does, so I think that addresses it? When I asked tim about it, he said he couldn't think of what other tests he would add, at any rate.
Therefore, I don't see anything else to complain about so!
Committed and pushed to 8.x. Thanks!
Comment #41
webchickOops. Needs a change notice. And then a backport.
Comment #42
effulgentsia commentedI would caution to backport only on a case by case basis, not in its entirety. NestedArray::mergeDeep() intentionally has different semantics (with respect to handling scalar values) than array_merge_recursive(), as documented by that function. Backporting such an API change to module_invoke_all() seems unwise. However, backporting the ajax_render() fix per #208611-43: Add drupal_array_merge_deep() and drupal_array_merge_deep_array() to stop drupal_add_js() from adding settings twice would be a clear bug fix IMO, and therefore, worth doing. I don't know about the other specific cases.
Comment #43
tim.plunkett100% agreed on case-by-case. That's the reason for the cautious title of this issue, because I was in a D7 mindset at the time.
Comment #44
amonteroLinking to related issue, FWIW.
#66183: Add helper methods to inject items into a particular position in associative arrays
Comment #45
tim.plunkettAdded a change notice here: http://drupal.org/node/1887290
Comment #46
tim.plunkettComment #46.0
tim.plunkettlink to functions
Comment #47
deanflory commentedFYI, #36 doesn't apply to D7.43.
Comment #52
donquixote commentedYes it can be risky to change the behavior of module_invoke_all() in Drupal 7.
I ran into one bug caused by this behavior, see #2852809: Facetapi module now implement hook_i18n_string_info.
I did an experiment on a local D7 test site, where I have two versions of module_invoke_all() and compare the difference each time it is called. So far the only case where it was different was this bug.
This does not mean changing this is safe, of course.
I'd say we should open distinct issues for specific cases in D7, and link to them here.
Some of them might be closed as wontfix, but still this is better than having all the discussion here.
Comment #53
donquixote commentedSee #2865599: module_invoke_all() can have surprising results thanks to array_merge_recursive()
Comment #54
markhalliwellJust ran into this with #2870289: file_ajax_upload() causes malformed Drupal.settings too.
I agree that this should be handled in separate issues (as needed) considering that there are only a few places in 7.x that still use this.
So, moving this issue back to 8.x since this was primarily about
NestedArray::mergeDeep()which isn't in 7.x.Really wish I could mark as "Closed (fixed)", but I guess I'll just mark as "Fixed".