1

How is it best to efficently rebuild your form on multiple AJAX requests?

That is how can I cleanly cache individual elements so I don't need to rebuild them?

Using static variables is not an option as they will not persist across form rebuilds. Using $_SESSION is probably the best, but this needs care as potentially a single session my have to windows open with diffent copies of the form in each one - and $_SESSION seems generally unclean.

Anyone got any best practices or boiler plates?

Background:
In order to AJAX in "proper" drupal style you need to rebuild the entire form on each AJAX call back. Your AJAx call back then just returns individual elements to replace. This is efficent for http bandwidth, but if the form elements are expensive to build this is potential an unneccessary performance hit.

The answer probably involves using $form_state somehow...

3

You need to rebuild whole form, no way around it, but you can store expensive things in Drupal cache. I advise against storing parts of $form array if it can be avoided, but using cache_set() and cache_get() to keep things like options available for select B when there is X in select A, it should work like a charm. And it will work with APC and Memcache modules out of the box.

The key is, of course, careful selection of $cid building algorithm.

$form_state as cache

$form_state is kept in form cache bin, but it is not a "real" cache. Let's look at the definition from Wikipedia:

In computer science, a cache (/ˈkæʃ/ KASH)1 is a component that transparently stores data so that future requests for that data can be served faster.

Now, that's pretty much what $form_state is not - it is kept to save temporary data that needs to be consistent, and that are never stored anywhere else during form processing. It means that when someone is using APC or Memcache, he needs to take extra care to prevent their "it can be deleted without any reason, for performance purposes" approach from corrupting forms. Most Drupal admins I know simply exclude form cache bin from them. And that is not what you want for your pre-built form parts.

Your pre-built form parts are real cache. So you want to keep them in bins that will be treated accordingly, you want to have speed over stability - you can afford additional rebuild once and then more than you can afford slowing down each request by pulling this data from database - slowest cache possible for Drupal.

Second reason not to use it is scope. $form_state exists only per one form session. So if user ends filling the form and access it again, $form_state is build anew. If hundred of users access he same form at one time, you have a hundred instances of $form_state. That's not what you want when your form elements does not depend on the user of your system. By keeping them in separate cache bin, keyed only by the things they depends on, you can have one copy, and use it for all hundred of users, every time they need it. It is impossible to loose anything, and you can decrease load (both CPU for generation and space for storage) to minuscule fraction of what it would be, if you would keep it in $form_state.


Algorithm for using cache (if someone happens to forget, of for newbies reading in future):

  1. Check if data is in cache
  2. If not, build it and save to the cache
  3. Use either data obtained from cache in 1., or built in 2.
  • thanks Molot - since formstate is cached somehow/somewhere, i'm wondering if there isn't a tidy pattern for caching within formstate? given this will be an increasing issues for complex AJAX-heavy forms a nice pattern would be great! – ErichBSchulz Oct 18 '13 at 1:44
  • @ErichBSchulz expanded my answer to explain why form state is not a cache. – Mołot Oct 18 '13 at 7:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.