Problem/Motivation
In #1812866: Rebuild the server side AJAX API a new Object-Oriented AJAX API for D8 was introduced. The existing D7 Ajax API was left in place while usage was converted from the old to the new. It's time to remove the D7 Ajax code from Drupal.
Proposed resolution
Remove most of the contents of ajax.inc. Rewrite / remove any remaining usages of ajax_command_*, ajax_render, or any other Ajax functions removed from ajax.inc.
Remaining tasks
- Remove any remaining calls to ajax_render().
- "fix AjaxEnhancer, which was doing things the old backward way" - Crell
- Test XHR2 and iframe uploads across browsers
Related Issues
#1812866: Rebuild the server side AJAX API
#1938980: Fix Ajax system; the last remnants of the old API must be swept away
#1957590: Remove remaining procedural ajax command usages.
#1843220: Convert form AJAX to new AJAX API
Open Questions:
1) Most of what is left in ajax.inc is related to forms. Does it make sense to rip it out and stick it in form.inc so we can get rid of ajax.inc entirely?
Answer: Most (~30%) is solving "#ajax" on forms, but let's keep it for now in there to reduce the patch size.
2) There's a massive block of documentation at the top of ajax.inc that needs updating. If we get rid of ajax.inc, where does this go?
Much of it deals with #ajax as well, but indeed this also covers the old way of dealing with it. The most recent version adapts the documentation
to the already ~ 1 year old new standard.
3) The old ajax.inc had defgroup docs for all of the ajax commands, which was nice...is there something comparable for all of the different ajax command classes?
Well, we do have CommandInterface, which makes it quite easy to find them.
| Comment | File | Size | Author |
|---|---|---|---|
| #86 | ajax-1959574.patch | 6.46 KB | dawehner |
| #67 | 1959574-ajax.patch | 38.01 KB | dawehner |
| #50 | ajax-1959574.patch | 35.32 KB | dawehner |
| #40 | ajax-1959574.patch | 29.18 KB | dawehner |
| #39 | remove-d7-ajax-api-1959574-39.patch | 20.15 KB | wim leers |
Comments
Comment #1
mkadin commentedComment #3
mkadin commentedNeeded the new MIME type on drupalPostAjax
Comment #5
andypostThe same happens in #1957590: Remove remaining procedural ajax command usages.
Comment #6
mkadin commentedThe scope of this work is beyond #1957590: Remove remaining procedural ajax command usages., so I'm posting the patch from work there here again, and postponing it on that issue.
Comment #7
effulgentsia commented#1957590: Remove remaining procedural ajax command usages. landed, so unpostponing this.
Comment #9
mkadin commentedRerolled this patch after #1957590: Remove remaining procedural ajax command usages.. Likely to fail but need to know which tests to work on.
Comment #10
mkadin commentedComment #12
mkadin commentedShould be down to 2 fails now, can't for the life of me figure out what's up with these. They work fine in the browser.
I think I've seen another issue struggling with this same problem but can't find it.
Comment #14
effulgentsia commentedThanks. These are the relevant issues related to those failures: #1967036: WebTestBase::drupalGetAJAX() and WebTestBase::drupalPostAJAX() don't set the Accept header needed for content negotiation and #1941288: Regression: ajaxPageState not being updated with AjaxResponse, assets (js/css) being added twice.
Comment #15
effulgentsia commentedThis could use a reroll for #1967036: WebTestBase::drupalGetAJAX() and WebTestBase::drupalPostAJAX() don't set the Accept header needed for content negotiation and other HEAD changes. Good news is, since that issue landed, once rerolled, it should pass.
Comment #16
mkadin commentedGiving a stripped down version of this patch another shot. Need to see where the tests are at.
Comment #17
Crell commentedPretty. :-)
Comment #18
dawehnerJust noting that in core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php ajax_render still exists.
Comment #19
Crell commentedActually... Shouldn't this also fix AjaxEnhancer, which was doing things the old backward way? (Bad Crell for RTBCing without thinking about that.)
Comment #20
wim leersIndeed, I'm afraid this is not even close to RTBC…
In
ViewSubscriber, the old AJAX system stuff is being called in two methods (not one as you would expect):onAjax(as expected; should be safely deletable)onIframeUpload(rather unexpected, to me at least)The latter could turn out to be kinda tricky. I'd love to remove it, but that might be impossible, it's necessary for #1009382: Several popular browser extensions corrupt AJAX responses, causing errors (for dealing with crappy browser add-ons/extensions, which I think we should not do at all) and http://malsup.com/jquery/form/#file-upload (for dealing with browsers that don't support XHR level 2). The latter is less relevant now, though it still appears to be necessary for IE 9 and Opera Mini: http://caniuse.com/xhr2.
Figuring out how to deal with that seems to be rather tricky and will require manual testing in many browsers. It must be done as part of this issue too — even though it is unrelated at the surface, because it currently depends on the D7 AJAX API, which is precisely what we want to remove in this issue.
Finally: it'd be nice if you'd like to this rather critical follow-up issue from the main issue next time — I did that just now: #1812866-88: Rebuild the server side AJAX API. How else are followers of that issue supposed to find this one?
Comment #21
wim leersThe current issue summary is not linking to the original issue, nor explaining why this was not done in the original issue (i.e. converting existing calling code to the new D8 Ajax API), nor explaining tricky edge cases like the one I laid out. An updated issue summary would be very helpful for other reviewers.
Comment #21.0
wim leersUpdated issue summary.
Comment #22
mkadin commentedApologies for not posting this as a follow up issue to the earlier Ajax issues. I'm really a casual core contributor; I'm not super familiar with the process, so take it easy on me.
I've updated the issue summary. @Crell (or anyone else), can you clarify what necessary fixes you're talking about with respect to #19? I've tried to figure out what you mean from other issues, but have been unsuccessful...
Comment #23
wim leers#22: No problem! :) Hope I didn't sound too harsh.
Thanks for the issue summary update! Are the open questions in the issue summary really still open questions though?
And indeed, the
AjaxEnhancerstuff in #19 needs input/guidance from people familiar with those matters, that's relatively deep stuff that only few people are familiar with.Comment #24
tim.plunkett.
Comment #25
Crell commentedmkadin, are you still interested in this? We really do need to finish it. :-)
Comment #26
mkadin commentedI'd love to, but you might need to find another taker to finish this up, I don't have any time for core stuff right now :(
Comment #27
wim leersAnd I found yet another major bug with the D8 Ajax API: #2063303: A Drupal 8 AjaxResponse that must return a 403, returns a 403 and prints "A fatal error occurred: ".
Comment #28
wim leersSeems appropriate, considering #1812866: Rebuild the server side AJAX API was also tagged WSCCI.
Comment #29
catchComment #30
webchick#29 implies this.
Comment #31
jessebeach commentedThis is just a straight reroll of #16, which bitrotted.
I'm going to see how much farther I can take this.
Comment #32
jessebeach commentedJust setting to needs review to have tests run. I expect them to fail.
I've uncommented this test in the latest patch. It would seem that this test must pass in order for this issue to be considered resolved.
I am not the right person to look into this issue it turns out. This is too far down into kernel for me.
Comment #33.0
(not verified) commentedUpdated issue summary.
Comment #34
Crell commented32: remove-d7-ajax-api-1959574-32.patch queued for re-testing.
Comment #36
dawehnerTo be honest this feels like an issue which should be fixed after the htmlpage issue.
Comment #37
Crell commentedI think you're right. They'd likely conflict and just make rolling harder.
Comment #38
wim leers#2068471: Normalize Controller/View-listener behavior with a Page object is in, unpostponing.
Comment #39
wim leersStraight reroll of #32. Let's see what fails.
Comment #40
dawehnerIn order to use the logic of AjaxController in the view subscriber as well I introduced the ajax response renderer, similar to the HtmlPageRenderer
and in the future the HtmlFragmentRenderer.
@wim
I started independent from your rerole, though most of the code should be identical.
Comment #41
wim leers#40: you know this area of Drupal so much better, so *thank you*! :)
Comment #42
wim leersI double-checked, and #40 indeed is a superset of #39. So ignore #39, #40 is the best one!
Comment #44
mkadin commentedI'm not following core dev close enough to participate in this work anymore, but just wanted to say thanks for carrying this forward folks.
Comment #45
twistor commentedMissing newline.
Unneeded 'so.' What about HtmlFragment, Response, and AjaxResponse?
if/elseif ?
80 char limit.
Inject the translation service?
Comment #46
tstoecklerajax -> Ajax
Also I think the second one would be much clearer if it were identical to the first one. "Render" is not exactly clear and "an" is missing.
The is_array() can be saved in the second one, it will never be FALSE.
Trailing whitespace.
Previously this was added unconditionally. Is there a specific reason for that?
Missing period after "commands".
In case it still fits in the 80 chars (I think it does) add a "that" after "Ensures".
Since we're already changing this, maybe "Tests *the* behavior"
are -> is
Also: Dropping the "through the Ajax framework" would make it < 80 chars.
Comment #47
dawehnerWow, two reviews in a short time, thank you!
Well, this code was moved from AjaxController to AjaxResponseRenderer, which is the more modern code compared to ajax_prepare_...
It fits exactly.
Sure.
In general I wonder whether we should add an interface for the AjaxResponseRenderer?
Additional this replaces all references of ajax_render() in core.
No comment.
Comment #48
tstoecklerAwesome thanks! Looks great to me, but I don't know the Ajax system or the new page rendering system well enough to RTBC.
Comment #49
Crell commentedWe may as well split this to its own subscriber, as we did for Html.
For parallelism with the HTML pipeline, we should not be mixing the array rendering in with the rest of this logic. The renderer should already have a domain object (HtmlFragment, HtmlPage, etc.), and a render array is not a domain object.
Which does suggest that perhaps we need a Drupal Ajax object other than AjaxResponse? Hm. It's not a perfect parallelism, I grant, but I am not comfortable with the Ajax renderer doing all three things when for Html the controller is responsible for normalizing render arrays to a domain object, and then the renderer just has to deal with the domain object.
Also, as written this means we have 2 redundant pipelines again, depending on whether an ajax request can sneak past the AjaxController. (If AJaxController does its job, then we never actually fire a view listener.) That's what we just fixed for HTML. Let's not introduce it here. :-)
Comment #50
dawehnerGiven that the same code is executed for onAjax and the proper ajaxController we should rather use the AjaxController on those cases as well.
Comment #51
Crell commentedHm. It's still not exactly parallel, but under the circumstances that's probably OK. I think that's the best we're going to be able to do, but we still get a delightful diffstat out of it. :-)
Do we still need this class at all?
This logic was intended as a BC shiv; in theory, ContentControllerEnhancer should be able to take care of ajax formats, too.
However, that would mean ajax-only routes (which we have a number of) would need to specify _content, not _controller, if they want to get the auto-wrapping controller. If they specify _controller, they MUST return an AjaxResponse themselves and they're on their own.
However, that is consistent with what is now required for HTML routes; if you specify _controller, you'd better not return a render array (or anything other than Response, HtmlFragment, or HtmlPage) or things WILL break and it's your own fault. And, in practice, I think that's what all of our ajax routes are doing now already, isn't it...?
So let's see what happens if we take AjaxEnhancer away completely and just add more mappings to ContentControllerEnhancer.
Comment #52
webchickSeeing as this changes a major API, this should most likely be a beta blocker.
Comment #53
dawehnerI agree that using _content for everything returning a render array would be nice consistency, though I really wonder whether the word "content" describes that properly. Personally I kind of connect content with HTML.
In addition though we would also add iframeupload and ajax support to the ContentControlleEnhancer if we really want to use it.
Do core maintainer have issues with this kind of small api changes these days?
Comment #54
Crell commentedI think it's fine. This issue is already ripping out the old API; let's rip it all the way.
Comment #55
sunComment #56
dawehnerYeah we can always iterate on top of it.
This is just a normal reroll, #2168113: Add leading underscore and other discouragement to drupal_add_css() and drupal_add_js() conflict with it.
Comment #57
Crell commenteddawehner: Er, I meant it should be fine to go ahead and fold AjaxEnhancer into ContentControllerEnhancer.
Note that this will conflict with the new plan in #2026431: Make ContentNegotiation a "internal" service, used only by the router, so that core or contrib can implement real negotiation. I'm not sure which we want to do first.
Comment #58
dawehnerThis would require ALL ajax callbacks to use _content instead which is kind of fine in, but certainly not in scope of this issue.
We just want to get rid of an old API.
Comment #59
Crell commentedComment #60
dawehner56: ajax-1959574.patch queued for re-testing.
Comment #61
Crell commentedScrew it, let's unblock stuff.
Comment #62
Crell commented56: ajax-1959574.patch queued for re-testing.
Comment #63
dawehnerComment #64
dawehnerFixed the documentation at the top of the ajax.inc file.
I kinda think that we should put that information into a better place but not sure really where.
Let's do that in a follow up, as otherwise the patch is too hard to review.
Comment #65
alexpotthuh?
This logic looks really odd.
Comment #66
pounardThis is probably black magic.
if (!empty($error)) {} // Should have been enough I guess.
Or if you want to keep typing: if (NULL !== $error && FALSE !== $error) {} // And there you go.
Comment #67
dawehnerThis logic is indeed really confusing, what about this really simple concept? I would guess that the entire block could be skipped some as #type ajax is not really recommended anymore but just a AjaxResponse object.
Comment #68
amateescu commentedThat interdiff seems to be from another issue :) And here's a small review of the doc since the functionality is a bit alien to me:
Like Alex pointed out, this needs to be rephrased a bit. How about merging it with the phrase below?
I'm not sure what to say about this one as well, does a controller have a "result"? Because it sounds really weird..
Since I've been nitpicking so far, this needs two extra spaces.
Edit: For the second point above, how about 'Converts the output of a controller ...' or 'Converts the return value of a controller ....'?
Comment #69
dawehnerGood idea, what about the small merge in the interdiff?
Lets use output in the main description and "return value" on the @param to be more precise on the technical level
Comment #70
dawehnerAmateescu found that.
Comment #71
amateescu commented#65 and my doc review was addressed => back to RTBC. @dawehner++
Comment #72
wim leersFixed a bunch of nitpicks. One question.
Shouldn't we at least document why we have both "drupal_ajax" and "ajax" as content types, and why
AjaxEnhanceralso needs to support the "iframeupload" content type?Comment #73
wim leersComment #74
dawehnerDoes this help?
Comment #75
andypostThis hunk changed in #2177637: Replace theme() with drupal_render() in ajax.inc
Comment #76
dawehnerThank you, luckily this was already part of the code before.
Comment #77
drclaw commentedJust unescaped the html in the issue summary
Comment #78
Crell commentedThe last several patches were all just docs tweaks, so I think we're good to go here. Thanks, dawehner et al!
Comment #79
alexpottCommitted e4e74fc and pushed to 8.x. Thanks!
Comment #80
jessebeach commentedMany of these changes seem opaque to anyone using the AJAX system through forms. Am I mistaken?
So it seems the change notice just needs some code examples from ajax_test.module, especially an example of adding a command e.g.
$response->addCommand(new HtmlCommand('body', 'Hello, world!'));. And then it seems the only major change is the removal ofajax_render.Comment #81
mkadin commentedThanks to everyone who pushed this through and got it in.
Comment #82
jessebeach commentedI think the JsonResponse->callback method is now returning the data on an insert command, meaning we can't simply invoke jQuery.ajax on a route that should return jsonp data to be eval'ed. I believe this issue broke the loading of the toolbar submenus.
Ultimately I think we'll need a jsonp command that does the data eval'ing in ajax.js. I started an issue here #2187483: Toolbar subtree is broken | JsonResponse->callback now returns data in an Insert Command without any support in ajax.js to eval the callback in the client.
Comment #83
jessebeach commentedWe can also reenable this test now, too: #2187897: The testControllerResolutionAjax() test was commented out pending resolution of #1959574; reenable it.
Comment #84
dawehnerRight, if you use #ajax nothing changed for you.
https://drupal.org/node/1843212 already has the change notice here ... this issue was just about deprecating the existing code.
Cu on that issue. Sorry for breaking it.
Comment #85
andypostIssue needs follow-up!
There's still
ajax_render()andajax_prepare_response()functions incore/includes/ajax.incthat are totally broken because calls removedajax_command_*Comment #86
dawehnerDamnit I totally failed at the last reroll.
Comment #87
andypostFiled the same to #2187735-3: Add removal information to docblock of all @deprecated functions
Comment #88
xjmThat works too. Thanks!
Comment #90
xjmComment #92
dawehnerOh xjm, I am sorry
#2203239: Remove ajax_render and co.