Growing Venture Solutions - GVS - Drupal 7 http://growingventuresolutions.com/taxonomy/term/121/0 en Drupal 7 release parties and December sprints http://growingventuresolutions.com/blog/drupal-7-release-parties-and-december-sprints <p>GVS has had a busy December and great start to 2011!</p> <h2>NYC and Denver Drupal 7 release parties</h2> <p>The NYC Drupal 7 Launch Party, hosted by Growing Venture Solutions, Treehouse Agency, and ThinkDrop took place on January 7, 2011.</p> <p>We were delighted at the turnout and enthusiasm for Drupal 7!</p> <p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-crowd.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-crowd.jpg" alt="Crowd of attendees" /></a><br /> Happy crowd!<br /> </p> <p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-group.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-group.jpg" alt="Group photo of organizers and speakers" /></a><br /> The speakers were Rob Purdie (Economist), Todd Ricker (New York Stock Exchange) and Thomas Turnbull (Zagat). The organizers were Lisa Rex, Claudina Sarahe, Ezra Gildesgame, Amy Cham and Ben Jeavons.</p> <!--break--><!--break--><p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-dries-skype.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-dries-skype.jpg" alt="Photo of Dries on Skype" /></a><br /> We did a video link up with the Boston party. Oh look, it's Dries Buytaert!<br /> </p> <p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-denver-skype.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-denver-skype.jpg" alt="Photo of Greg Knaddison and Kevin Bridges on Skype" /></a><br /> And then we did a video link up with the Denver and Austin parties. Everyone say hi to Greggles and Kevin Bridges!<br /> </p> <p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-jacob.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-jacob.jpg" alt="Photo of Jacob" /></a><br /> And Jacob Redding wore his Drupal suit and tie!<br /> </p> <p><a href="http://growingventuresolutions.com/gvsfiles/d7rp-raffles.jpg"><img src="http://growingventuresolutions.com/gvsfiles/d7rp-raffles.jpg" alt="Photo of giving prizes away" /></a><br /> We gave away raffle prizes from Lullabot, Packt Publishing and Mastering Drupal, and there was some additional sponsorship support from CivicActions and Bluestocking Collective.</p> <p>The official photographer for the NYC Drupal 7 party was <a href="http://www.mattcham.com">Matt Cham</a>. Additional <a href="http://www.flickr.com/photos/treehouseagency/tags/d7rpnyc">d7rp_nyc party photos</a> are on Flickr.</p> <p>GVS also co-hosted the Denver party, with Greg Knaddison in attendance. The next three photos are by Keith Stansell.</p> <p><a href="http://www.flickr.com/photos/sole_i/5335033688/in/set-72157625647129263/"><img src="http://farm6.static.flickr.com/5125/5335033688_f2a3162117.jpg" alt="Danomanion, Andrea, Aaronnott, Greggles, Justin Christoffersen and friend" /></a><br /> Dano Manion, Andrea, Aaron Nott, Greg Knaddison and Justin Christoffersen. I'm holding up a nice <a href="http://certifiedtorock.com/">Certified to Rock</a> sticker ;)</p> <p><a href="http://www.flickr.com/photos/sole_i/5334889102/in/set-72157625647129263/"><img src="http://farm6.static.flickr.com/5043/5334889102_e4b4f7d1fa.jpg" alt="Matthew Saunders and Andy of Examiner.com" /></a><br /> Andy Packard and Matthew Saunders from the team at <a href="http://www.examiner.com/">Examiner.com</a>.</p> <p><a href="http://www.flickr.com/photos/sole_i/5334269451/in/set-72157625647129263/"><img src="http://farm6.static.flickr.com/5048/5334269451_93b25fd081.jpg" alt="Jyee making Drupal 7 and 7" /></a><br /> Jason Yee making <a href="http://atendesigngroup.com/blog/drupal-7-and-seven">Drupal 7 and Seven</a>.</p> <h2>GVS &lt;3 sprints</h2> <p>GVS and Treehouse sponsored a D7CX code sprint at the offices of GVS neighbor HUGE in Brooklyn, NY.<br /> Progress made at the sprint included working automated tests for the Nodequeue module, a stable Drupal 7 release of the Security review module, <a href="http://groups.drupal.org/node/115009">amongst other work.</a></p> <p><a href="http://www.flickr.com/photos/35549722@N00/5260602391/"><img src="http://farm6.static.flickr.com/5123/5260602391_404b046bce.jpg" /></a><br /> <br /> Ezra, Vikram Yelanadu, Thomas Turnbull, Andrew Morton, Steven Merrill</p> <p>Meanwhile, Lisa participated in the <a href="http://groups.drupal.org/node/105309">Drupal Docs sprint weekend</a> in Vancouver where the core documentation team hashed out directions and problems the Docs team face (see <a href="http://drupal.org/project/issues/search/infrastructure?issue_tags=docsyvr2010">issues tagged docsyvr2010</a> for things that were raised during the meeting). On Saturday, there was a Docs team sprint with special guests chx, dmitrig01, and webchick!</p> <p><img src="http://farm6.static.flickr.com/5208/5253327904_3249d63ef5.jpg" alt="Docs team" /><br /> <a href="http://www.flickr.com/photos/arianek/5253327904/sizes/m/in/set-72157625579478132/" title="http://www.flickr.com/photos/arianek/5253327904/sizes/m/in/set-72157625579478132/">http://www.flickr.com/photos/arianek/5253327904/sizes/m/in/set-721576255...</a></p> http://growingventuresolutions.com/blog/drupal-7-release-parties-and-december-sprints#comments Planet Drupal code sprints d7rp doc sprints documentation Drupal 7 release party Tue, 18 Jan 2011 23:03:53 +0000 Team GVS 1192 at http://growingventuresolutions.com Drupal 7 multistep forms using variable functions http://growingventuresolutions.com/blog/drupal-7-multistep-forms-using-variable-functions <p>I like building forms. So much so that I've even been teased about it. Despite that I want to share how multistep forms have changed for Drupal 7 and to expand on how you can use variable functions to achieve cleaner and easier form step logic, including easily moving backwards in forms. Understanding multistep in Drupal 7 was prompted by my need to create easy forms for an internal GVS project that will hopefully launch soon.</p> <h3>Multistep in Drupal 7</h3> <p>In Drupal 6 to carry data back to your form builder you set the <code>storage</code> key of <code>$form_state</code> in your submit handler. <strike>In Drupal 7</strike>, upon return to your builder after submission, you carry data over by keeping the Form API from pulling the form array out of cache*. You do so by setting <code>$form_state[&#039;rebuild&#039;]</code> to <code>TRUE</code> in your validate or submit handlers. Another change is the first argument of your builder must be <code>$form</code> because of <a href="http://drupal.org/update/modules/6/7#hook_forms_signature">changes to drupal_get_form()</a>. <code>&amp;$form_state</code> is now your second argument to your form builder.</p> <p>Update: 'rebuild' existed in Drupal 6 (thanks Wim) but now seems to be required for multistep to work in Drupal 7.</p> <p>Drupal 7:<br /> <div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">// Form builder definition.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">my_form</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {...}<br /><br /></span><span style="color: #FF8000">// Form submit handler.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">my_form_builder_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #FF8000">// Trigger multistep.<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'rebuild'</span><span style="color: #007700">] = </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br />&nbsp; </span><span style="color: #FF8000">// Store values that will be available when we return to the definition.<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'values'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$values</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div></p> <p>Let's look at a example:<br /> <div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">// multistep_simple, our form builder function.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_simple</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #FF8000">// Check if storage contains a value. A value is set only after the form is submitted and 'rebuild' is set to TRUE.<br />&nbsp; </span><span style="color: #007700">if (!empty(</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'myvalue'</span><span style="color: #007700">])) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Display a message with the submitted value.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">drupal_set_message</span><span style="color: #007700">(</span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">"You submitted: @name"</span><span style="color: #007700">, array(</span><span style="color: #DD0000">'@name' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'myvalue'</span><span style="color: #007700">])));<br />&nbsp; }<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'name'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'textfield'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Name'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#description' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Enter your name'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#required' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">,<br />&nbsp; );<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'submit'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'submit'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#value' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Submit'</span><span style="color: #007700">),<br />&nbsp; );<br />&nbsp; return </span><span style="color: #0000BB">$form</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #FF8000">// Our submit handler for multistep_simple.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_simple_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #FF8000">// Tell FAPI to rebuild.<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'rebuild'</span><span style="color: #007700">] = </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br />&nbsp; </span><span style="color: #FF8000">// Store submitted value.<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'myvalue'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">][</span><span style="color: #DD0000">'name'</span><span style="color: #007700">];<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div></p> <p>We could of course set the message in the submit handler but I hope the example helps convey the two points of the definition arguments and setting rebuild in the submit handler.</p> <h3>Multistep with variable functions and FAPI handler convention</h3> <p>Using variable functions is a great way to make readable form step logic. And, if you combine this method with Drupal's form handler definition style and you can easily make advanced forms.</p> <p>Update: This is by no means a method that exists only in Drupal 7. This is just <a href="http://pingvision.com/blog/ben-jeavons/2009/multi-step-forms-drupal-6-using-variable-functions">a process I've written about before</a> for making form-step logic easier to code and extend. What I'm writing about here is an expansion on that process.</p> <p>The components:</p> <ol> <li>Store step names (function definitions) in <code>$form_state[&#039;storage&#039;]</code></li> <li>Return the current step's form array in the main FAPI builder</li> <li>Invoke validate and submit handlers for a individual step by appending '_validate' or '_submit' to the step definition</li> </ol> <p>Let me start with the form builder and submit handler for illustration. The form ID known to FAPI will be <code>multistep_form</code> and <code>multistep_form_submit</code> the submit handler. The builder uses functions defined in storage to know which step to return and the submit handler uses FAPI convention to call a individual step's validate or submit.</p> <p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">// Primary form builder.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_form</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #FF8000">// Initialize.<br />&nbsp; </span><span style="color: #007700">if (</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'rebuild'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Don't hang on to submitted data in form state input.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'input'</span><span style="color: #007700">] = array();<br />&nbsp; }<br />&nbsp; if (empty(</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">])) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// No step has been set so start with the first.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'step' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'multistep_form_start'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; );<br />&nbsp; }<br /><br />&nbsp; </span><span style="color: #FF8000">// Return the form for the current step.<br />&nbsp; </span><span style="color: #0000BB">$function </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">];<br />&nbsp; </span><span style="color: #0000BB">$form </span><span style="color: #007700">= </span><span style="color: #0000BB">$function</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">);<br />&nbsp; return </span><span style="color: #0000BB">$form</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #FF8000">// Primary submit handler.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_form_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #0000BB">$values </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">];<br />&nbsp; </span><span style="color: #FF8000">// Check if we're moving back or forward in the form.<br />&nbsp; </span><span style="color: #007700">if (isset(</span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) &amp;&amp; </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'op'</span><span style="color: #007700">] == </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Code for moving in reverse left out for now...<br />&nbsp; </span><span style="color: #007700">}<br />&nbsp; else {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Record the current step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$step </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'steps'</span><span style="color: #007700">][] = </span><span style="color: #0000BB">$step</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Call step submit handler if it exists.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #007700">if (</span><span style="color: #0000BB">function_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">)) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function </span><span style="color: #007700">= </span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Current step's submit handler will set the next step.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp; }<br />&nbsp; return;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div></p> <p>Step submit handlers specify the next step to use and step builders can skip steps.</p> <p>Here's a diagram depicting the flow of standard FAPI and how the builder and handlers call off to a individual step.</p> <p><img src="http://growingventuresolutions.com/gvsfiles/multistep-form-diagram.png" /></p> <p>Here's an example individual step and it's submit handler:</p> <p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_form_start</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'radios'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Choose a musician'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#options' </span><span style="color: #007700">=&gt; array(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'davis' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Miles Davis'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'coltrane' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'John Coltrane'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'corea' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Chick Corea'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'brubeck' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Dave Brubeck'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'other' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Other'</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp; ),<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#default_value' </span><span style="color: #007700">=&gt; isset(</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">]) ? </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">] : </span><span style="color: #0000BB">NULL</span><span style="color: #007700">,<br />&nbsp; );<br />&nbsp; </span><span style="color: #FF8000">// Next button.<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'submit'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'submit'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#value' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Next'</span><span style="color: #007700">),<br />&nbsp; );<br />&nbsp; return </span><span style="color: #0000BB">$form</span><span style="color: #007700">;<br />}<br /><br />function </span><span style="color: #0000BB">multistep_form_start_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #FF8000">// Trigger multistep, there are more steps.<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'rebuild'</span><span style="color: #007700">] = </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br />&nbsp; </span><span style="color: #0000BB">$values </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">];<br />&nbsp; if (isset(</span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) &amp;&amp; </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'op'</span><span style="color: #007700">] == </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// User is moving back from this form, clear our storage.<br />&nbsp;&nbsp;&nbsp; // [...]<br />&nbsp; </span><span style="color: #007700">}<br />&nbsp; else if (</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">] == </span><span style="color: #DD0000">'other'</span><span style="color: #007700">) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// User chose 'other' so inject an intermediary step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">] = </span><span style="color: #0000BB">NULL</span><span style="color: #007700">; </span><span style="color: #FF8000">// Clear out because of our define musician step uses key 'musician' as well.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'multistep_form_define_musician'</span><span style="color: #007700">;<br />&nbsp; }<br />&nbsp; else {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// We could do something with the values here, like saving etc...<br />&nbsp;&nbsp;&nbsp; // Hold on to value.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">][</span><span style="color: #DD0000">'musician'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Set the next step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'multistep_form_songs'</span><span style="color: #007700">;<br />&nbsp; }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div></p> <p>The above example defines a single step and sets us up to move through the chain of several. Let's look at the next step and define how we could move backwards. We'll redefine the primary submit handler now.</p> <p>Update: The form property <code>#limit_validation_errors</code> and a element submit property are required on back buttons should any step have anything that would trigger validation.</p> <p><div class="codeblock"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #FF8000">// Primary submit handler.<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">multistep_form_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #0000BB">$values </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">];<br />&nbsp; if (isset(</span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) &amp;&amp; </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'op'</span><span style="color: #007700">] == </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Moving back in form.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$step </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Call current step submit handler if it exists to unset step form data.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #007700">if (</span><span style="color: #0000BB">function_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">)) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function </span><span style="color: #007700">= </span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Remove the last saved step so we use it next.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$last_step </span><span style="color: #007700">= </span><span style="color: #0000BB">array_pop</span><span style="color: #007700">(</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'steps'</span><span style="color: #007700">]);<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$last_step</span><span style="color: #007700">;<br />&nbsp; }<br />&nbsp; else {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Record step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$step </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'steps'</span><span style="color: #007700">][] = </span><span style="color: #0000BB">$step</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Call step submit handler if it exists.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #007700">if (</span><span style="color: #0000BB">function_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">)) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function </span><span style="color: #007700">= </span><span style="color: #0000BB">$step </span><span style="color: #007700">. </span><span style="color: #DD0000">'_submit'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$function</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp; }<br />&nbsp; return;<br />}<br /><br />function </span><span style="color: #0000BB">multistep_form_songs</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'song'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'textfield'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Favorite recording?'</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#default_value' </span><span style="color: #007700">=&gt; isset(</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'song'</span><span style="color: #007700">]) ? </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'song'</span><span style="color: #007700">] : </span><span style="color: #0000BB">NULL</span><span style="color: #007700">,<br />&nbsp; );<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'unknown'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'checkbox'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#title' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">"I don't know"</span><span style="color: #007700">),<br />&nbsp; );<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'submit'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#value' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Back'</span><span style="color: #007700">),<br />&nbsp; );<br />&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'submit'</span><span style="color: #007700">] = array(<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#type' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'submit'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #DD0000">'#value' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Next'</span><span style="color: #007700">),<br />&nbsp; );<br />&nbsp; <br />&nbsp; return </span><span style="color: #0000BB">$form</span><span style="color: #007700">;<br />}<br /><br />function </span><span style="color: #0000BB">multistep_form_songs_submit</span><span style="color: #007700">(</span><span style="color: #0000BB">$form</span><span style="color: #007700">, &amp;</span><span style="color: #0000BB">$form_state</span><span style="color: #007700">) {<br />&nbsp; </span><span style="color: #0000BB">$values </span><span style="color: #007700">= </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">];<br />&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'rebuild'</span><span style="color: #007700">] = </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br />&nbsp; if (isset(</span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) &amp;&amp; </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'op'</span><span style="color: #007700">] == </span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'back'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// User is moving back from this form, clear our storage.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'song'</span><span style="color: #007700">] = </span><span style="color: #0000BB">NULL</span><span style="color: #007700">;<br />&nbsp; }<br />&nbsp; else if (</span><span style="color: #0000BB">$values</span><span style="color: #007700">[</span><span style="color: #DD0000">'unknown'</span><span style="color: #007700">]) {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Skip to confirm step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'multistep_form_confirm'</span><span style="color: #007700">;<br />&nbsp; }<br />&nbsp; else {<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'song'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'values'</span><span style="color: #007700">][</span><span style="color: #DD0000">'song'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #FF8000">// Set the next step.<br />&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form_state</span><span style="color: #007700">[</span><span style="color: #DD0000">'storage'</span><span style="color: #007700">][</span><span style="color: #DD0000">'step'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'multistep_form_heard'</span><span style="color: #007700">;<br />&nbsp; }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div></p> <p>In our second step form builder (<code>multistep_form_songs</code>) we provide a back button. The primary submit handler allows the current step to remove stored data (to avoid a previously set default value when we return) and then removes the most recent step so when returned to the primary builder the previous step is used.</p> <p>A full multistep example is provided in the attachment. You'll need to rename the files excluding the '.txt' extension to use. Some assumptions are made, of course, so adjustment for your use cases is required.</p> <p>P.S.<br /> If you didn't catch it, in Drupal 7 you are not limited to <code>&#039;storage&#039;</code> for carrying data across requests. It's used in most of the examples, but you'll see that it's not required.<br /> *I'm not clear on some core implementation specifics regarding the form cache so if you know please share!</p> <table id="attachments" class="sticky-enabled"> <thead><tr><th>Attachment</th><th>Size</th> </tr></thead> <tbody> <tr class="odd"><td><a href="http://growingventuresolutions.com/gvsfiles/multistep.module.txt">multistep.module.txt</a></td><td>9.85 KB</td> </tr> <tr class="even"><td><a href="http://growingventuresolutions.com/gvsfiles/multistep.info_.txt">multistep.info_.txt</a></td><td>94 bytes</td> </tr> </tbody> </table> http://growingventuresolutions.com/blog/drupal-7-multistep-forms-using-variable-functions#comments Planet Drupal Drupal 7 forms Tue, 06 Apr 2010 17:41:46 +0000 Ben 841 at http://growingventuresolutions.com