Zend_Form-Advanced.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 14978 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.form.advanced">
  5. <title>Fortgeschrittene Verwendung von <classname>Zend_Form</classname></title>
  6. <para>
  7. <classname>Zend_Form</classname> hat eine Vielzahl an Funktionalitäten, von denen viele auf
  8. fortgeschrittene Entwickler zugeschnitten sind. Dieses Kapitel beschreibt einige dieser
  9. Funktionalitäten mit Beispielen und Usecases.
  10. </para>
  11. <sect2 id="zend.form.advanced.arrayNotation">
  12. <title>Array Schreibweise</title>
  13. <para>
  14. Viele fortgeschrittene Entwickler gruppieren zusammengehörige Formularelemente durch
  15. Verwendung einer Array Schreibweise in den Namen der Elemente. Zum Beispiel, wenn man
  16. zwei Adressen hat die geholt werden sollen, eine Versand- und eine Rechnungsadresse,
  17. hat man identische Elemente; durch deren Gruppierung in einem Array, kann
  18. sichergestellt werden, dass sie separat geholt werden. Nehmen wir die folgende Form
  19. als Beispiel an:
  20. </para>
  21. <programlisting role="html"><![CDATA[
  22. <form>
  23. <fieldset>
  24. <legend>Versandadresse</legend>
  25. <dl>
  26. <dt><label for="recipient">Versand an:</label></dt>
  27. <dd><input name="recipient" type="text" value="" /></dd>
  28. <dt><label for="address">Adresse:</label></dt>
  29. <dd><input name="address" type="text" value="" /></dd>
  30. <dt><label for="municipality">Stadt:</label></dt>
  31. <dd><input name="municipality" type="text" value="" /></dd>
  32. <dt><label for="province">Bundesland:</label></dt>
  33. <dd><input name="province" type="text" value="" /></dd>
  34. <dt><label for="postal">Postleitzahl:</label></dt>
  35. <dd><input name="postal" type="text" value="" /></dd>
  36. </dl>
  37. </fieldset>
  38. <fieldset>
  39. <legend>Rechnungsadresse</legend>
  40. <dl>
  41. <dt><label for="payer">Rechnung an:</label></dt>
  42. <dd><input name="payer" type="text" value="" /></dd>
  43. <dt><label for="address">Adresse:</label></dt>
  44. <dd><input name="address" type="text" value="" /></dd>
  45. <dt><label for="municipality">Stadt:</label></dt>
  46. <dd><input name="municipality" type="text" value="" /></dd>
  47. <dt><label for="province">Bundesland:</label></dt>
  48. <dd><input name="province" type="text" value="" /></dd>
  49. <dt><label for="postal">Postleitzahl:</label></dt>
  50. <dd><input name="postal" type="text" value="" /></dd>
  51. </dl>
  52. </fieldset>
  53. <dl>
  54. <dt><label for="terms">Ich stimme den AGBs zu</label></dt>
  55. <dd><input name="terms" type="checkbox" value="" /></dd>
  56. <dt></dt>
  57. <dd><input name="save" type="submit" value="Speichern" /></dd>
  58. </dl>
  59. </form>
  60. ]]>
  61. </programlisting>
  62. <para>
  63. In diesem Beispiel enthalten die Rechnungs- und Versanadresse einige identische
  64. Felder, was bedeueten würde, dass sie sich gegenseitig überschreiben. Wir können
  65. das durch die Verwendung der Array Schreibweise lösen:
  66. </para>
  67. <programlisting role="html"><![CDATA[
  68. <form>
  69. <fieldset>
  70. <legend>Versandadresse</legend>
  71. <dl>
  72. <dt><label for="shipping-recipient">Versand an:</label></dt>
  73. <dd><input name="shipping[recipient]" id="shipping-recipient"
  74. type="text" value="" /></dd>
  75. <dt><label for="shipping-address">Adresse:</label></dt>
  76. <dd><input name="shipping[address]" id="shipping-address"
  77. type="text" value="" /></dd>
  78. <dt><label for="shipping-municipality">Stadt:</label></dt>
  79. <dd><input name="shipping[municipality]" id="shipping-municipality"
  80. type="text" value="" /></dd>
  81. <dt><label for="shipping-province">Bundesland:</label></dt>
  82. <dd><input name="shipping[province]" id="shipping-province"
  83. type="text" value="" /></dd>
  84. <dt><label for="shipping-postal">Postleitzahl:</label></dt>
  85. <dd><input name="shipping[postal]" id="shipping-postal"
  86. type="text" value="" /></dd>
  87. </dl>
  88. </fieldset>
  89. <fieldset>
  90. <legend>Rechnungsadresse</legend>
  91. <dl>
  92. <dt><label for="billing-payer">Rechnung an:</label></dt>
  93. <dd><input name="billing[payer]" id="billing-payer"
  94. type="text" value="" /></dd>
  95. <dt><label for="billing-address">Adresse:</label></dt>
  96. <dd><input name="billing[address]" id="billing-address"
  97. type="text" value="" /></dd>
  98. <dt><label for="billing-municipality">Stadt:</label></dt>
  99. <dd><input name="billing[municipality]" id="billing-municipality"
  100. type="text" value="" /></dd>
  101. <dt><label for="billing-province">Bundesland:</label></dt>
  102. <dd><input name="billing[province]" id="billing-province"
  103. type="text" value="" /></dd>
  104. <dt><label for="billing-postal">Postleitzahl:</label></dt>
  105. <dd><input name="billing[postal]" id="billing-postal"
  106. type="text" value="" /></dd>
  107. </dl>
  108. </fieldset>
  109. <dl>
  110. <dt><label for="terms">Ich stimme den AGBs zu</label></dt>
  111. <dd><input name="terms" type="checkbox" value="" /></dd>
  112. <dt></dt>
  113. <dd><input name="save" type="submit" value="Speichern" /></dd>
  114. </dl>
  115. </form>
  116. ]]>
  117. </programlisting>
  118. <para>
  119. In dem obigen Beispiel erhalten wir jetzt separate Adressen. In der übermittelten Form
  120. haben wir jetzt zwei Elemente, 'shipping' und 'billing', jedes mit Schlüsseln für
  121. deren verschiedene Elemente.
  122. </para>
  123. <para>
  124. <classname>Zend_Form</classname> versucht diesen Prozess mit seinen
  125. <link linkend="zend.form.forms.subforms">Unterformularen</link> zu automatisieren.
  126. Standardmäßig werden Unterformulare dargestellt, indem die Array Schreibweise, wie im
  127. vorherigen HTML Form Code gezeigt, komplett mit Ids, verwendet wird. Der Arrayname
  128. basiert auf dem Namen des Unterformulars, mit den Schlüsseln basierend auf den
  129. Elementen, die im Unterformualr enthalten sind. Unterformulare können beliebig tief
  130. verschachtelt sein, und das erzeugt verschachtelte Arrays um die Struktur zu
  131. reflektieren. Zusätzlich beachten die verschiedenen Prüfroutinen in <classname>Zend_Form</classname>
  132. die Arraystruktur, und stellen sicher, dass die Form korrekt überprüft wird, egal wie
  133. tief verschachtelt die Unterformulare sind. Es muss nichts getan werden, um davon zu
  134. profitieren; dieses Verhalten ist standardmäßig aktiviert.
  135. </para>
  136. <para>
  137. Zusätzlich gibt es Möglichkeiten, die es erlauben die Array Schreibweise fallweise
  138. zu aktivieren, wie auch die Spezifikation eines speziellen Array zu welchem ein
  139. Element oder eine Sammlung gehört:
  140. </para>
  141. <itemizedlist>
  142. <listitem>
  143. <para>
  144. <classname>Zend_Form::setIsArray($flag)</classname>: Durch das Setzen dieses Flags auf
  145. <code>true</code>, kann angezeigt werden, dass das komplette Formular als Array
  146. behandelt werden soll. Standardmäßig wird der Name des Formulars als Name des
  147. Arrays verwendet, solange <code>setElementsBelongTo()</code> aufgerufen wurde.
  148. Wenn das Formular keinen Namen spezifiziert hat, oder <code>setElementsBelongTo()</code>
  149. nicht gesetzt wurde, wird dieses Flag ignoriert (da es kein Arraynamen gibt zu dem
  150. die Elemente gehören).
  151. </para>
  152. <para>
  153. Man kann auswählen, ob ein Formular als Array behandelt wird, indem die
  154. Zugriffsmethode <code>isArray()</code> verwendet wird.
  155. </para>
  156. </listitem>
  157. <listitem><para>
  158. <classname>Zend_Form::setElementsBelongTo($array)</classname>: Durch Verwendung dieser
  159. Methode kann der Name eines Arrays spezifiziert werden dem alle Elemente des
  160. Formulars angehören. Der Name kann durch Verwendung der Zugriffsmethode
  161. <code>getElementsBelongTo()</code> eruiert werden.
  162. </para></listitem>
  163. </itemizedlist>
  164. <para>
  165. Zusätzlich können auf dem Element Level, individuelle Elemente spezifiziert werden die
  166. bestimmten Arrays angehören indem die <classname>Zend_Form_Element::setBelongsTo()</classname>
  167. Methode verwendet wird. Um herauszufinden welcher Wert gesetzt ist -- egal ob dieser
  168. explizit gesetzt wurde oder implzit über das Formular -- kann die Zugriffsmethode
  169. <code>getBelongsTo()</code> verwendet werden.
  170. </para>
  171. </sect2>
  172. <sect2 id="zend.form.advanced.multiPage">
  173. <title>Mehrseitige Formulare</title>
  174. <para>
  175. Aktuell werden mehrseitige Formulare nicht offiziell in <classname>Zend_Form</classname>
  176. unterstützt; trotzdem ist die meiste Unterstützung für deren Implementierung bereits
  177. vorhanden und kann mit etwas extra Code angepasst werden.
  178. </para>
  179. <para>
  180. Der Schlüssel in der Erstellung von mehrseitigen Formularen, ist die Anpassung von
  181. Unterformularen, aber der Anzeige, von nur einem Unterformular pro Seite. Das erlaubt
  182. es, ein einzelnes Unterformular auf einmal zu übertragen und diese zu prüfen, aber das
  183. Formular nicht zu bearbeiten bis alle weiteren Unterformulare komplett sind.
  184. </para>
  185. <example id="zend.form.advanced.multiPage.registration">
  186. <title>Beispiel: Anmeldeformular</title>
  187. <para>
  188. Verwenden wir also ein Anmeldeformular als Beispiel. Für unsere Zwecke wollen wir
  189. auf der ersten Seite einen gewünschten Benutzernamen und Passwort holen, dann die
  190. Metadaten des Benutzers -- das heißt Vorname, Familienname und Wohnort -- und
  191. letztendlich die Auswahl welcher Mailingliste, wenn überhaupt, der Benutzer
  192. angehören will.
  193. </para>
  194. <para>
  195. Erstellen wir als erstes unser, eigenes, Formular und definieren in diesem die
  196. verschiedenen Unterformulare:
  197. </para>
  198. <programlisting role="php"><![CDATA[
  199. class My_Form_Registration extends Zend_Form
  200. {
  201. public function init()
  202. {
  203. // Erstellt die Benutzer Subform: Benutzername und Passwort
  204. $user = new Zend_Form_SubForm();
  205. $user->addElements(array(
  206. new Zend_Form_Element_Text('username', array(
  207. 'required' => true,
  208. 'label' => 'Benutzername:',
  209. 'filters' => array('StringTrim', 'StringToLower'),
  210. 'validators' => array(
  211. 'Alnum',
  212. array('Regex',
  213. false,
  214. array('/^[a-z][a-z0-9]{2,}$/'))
  215. )
  216. )),
  217. new Zend_Form_Element_Password('password', array(
  218. 'required' => true,
  219. 'label' => 'Passwort:',
  220. 'filters' => array('StringTrim'),
  221. 'validators' => array(
  222. 'NotEmpty',
  223. array('StringLength', false, array(6))
  224. )
  225. )),
  226. ));
  227. // Erstellt die Demographische Subform: Vorname,
  228. // Familienname und Ort
  229. $demog = new Zend_Form_SubForm();
  230. $demog->addElements(array(
  231. new Zend_Form_Element_Text('givenName', array(
  232. 'required' => true,
  233. 'label' => 'Vorname (erster):',
  234. 'filters' => array('StringTrim'),
  235. 'validators' => array(
  236. array('Regex',
  237. false,
  238. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  239. )
  240. )),
  241. new Zend_Form_Element_Text('familyName', array(
  242. 'required' => true,
  243. 'label' => 'Familienname (letzter):',
  244. 'filters' => array('StringTrim'),
  245. 'validators' => array(
  246. array('Regex',
  247. false,
  248. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  249. )
  250. )),
  251. new Zend_Form_Element_Text('location', array(
  252. 'required' => true,
  253. 'label' => 'Der eigene Ort:',
  254. 'filters' => array('StringTrim'),
  255. 'validators' => array(
  256. array('StringLength', false, array(2))
  257. )
  258. )),
  259. ));
  260. // Erstellt die Mailinglisten Subform
  261. $listOptions = array(
  262. 'none' => 'keine Listen bitte',
  263. 'fw-general' => 'Zend Framework General Liste',
  264. 'fw-mvc' => 'Zend Framework MVC Liste',
  265. 'fw-auth' => 'Zend Framework Authentication und ACL Liste',
  266. 'fw-services' => 'Zend Framework Web Services Liste',
  267. );
  268. $lists = new Zend_Form_SubForm();
  269. $lists->addElements(array(
  270. new Zend_Form_Element_MultiCheckbox('subscriptions', array(
  271. 'label' =>
  272. 'Welche Liste wollen Sie erhalten?',
  273. 'multiOptions' => $listOptions,
  274. 'required' => true,
  275. 'filters' => array('StringTrim'),
  276. 'validators' => array(
  277. array('InArray',
  278. false,
  279. array(array_keys($listOptions)))
  280. )
  281. )),
  282. ));
  283. // Die Subformen der Hauptform anhängen
  284. $this->addSubForms(array(
  285. 'user' => $user,
  286. 'demog' => $demog,
  287. 'lists' => $lists
  288. ));
  289. }
  290. }
  291. ]]>
  292. </programlisting>
  293. <para>
  294. Es ist zu beachten, dass es keinen 'Abschicken' Button gibt, und, dass wir
  295. nichts mit den Dekoratoren des Unterformulars gemacht haben -- was bedeutet,
  296. dass Sie standardmäßig als Fieldsets angezeigt werden. Wir müssen das Überladen
  297. wenn wir jedes individuelle Unterformular anzeigen wollen und einen 'Abschicken'
  298. Button hinzufügen, damit wir sie dann bearbeiten können -- was auch Aktions- und
  299. Methodeneigenschaften benötigt. Füllen wir unsere Klasse ein wenig und bieten
  300. diese Information:
  301. </para>
  302. <programlisting role="php"><![CDATA[
  303. class My_Form_Registration extends Zend_Form
  304. {
  305. // ...
  306. /**
  307. * Eine Subform für die anzeige Vorbereiten
  308. *
  309. * @param string|Zend_Form_SubForm $spec
  310. * @return Zend_Form_SubForm
  311. */
  312. public function prepareSubForm($spec)
  313. {
  314. if (is_string($spec)) {
  315. $subForm = $this->{$spec};
  316. } elseif ($spec instanceof Zend_Form_SubForm) {
  317. $subForm = $spec;
  318. } else {
  319. throw new Exception('Ungültiges Argument an ' .
  320. __FUNCTION__ . '() übergeben');
  321. }
  322. $this->setSubFormDecorators($subForm)
  323. ->addSubmitButton($subForm)
  324. ->addSubFormActions($subForm);
  325. return $subForm;
  326. }
  327. /**
  328. * Form Dekoratore zu einer individuellen Subform hinzufügen
  329. *
  330. * @param Zend_Form_SubForm $subForm
  331. * @return My_Form_Registration
  332. */
  333. public function setSubFormDecorators(Zend_Form_SubForm $subForm)
  334. {
  335. $subForm->setDecorators(array(
  336. 'FormElements',
  337. array('HtmlTag', array('tag' => 'dl',
  338. 'class' => 'zend_form')),
  339. 'Form',
  340. ));
  341. return $this;
  342. }
  343. /**
  344. * Einen Sendebutton in einer individuellen Subform hinzufügen
  345. *
  346. * @param Zend_Form_SubForm $subForm
  347. * @return My_Form_Registration
  348. */
  349. public function addSubmitButton(Zend_Form_SubForm $subForm)
  350. {
  351. $subForm->addElement(new Zend_Form_Element_Submit(
  352. 'save',
  353. array(
  354. 'label' => 'Speichern und Fortfahren',
  355. 'required' => false,
  356. 'ignore' => true,
  357. )
  358. ));
  359. return $this;
  360. }
  361. /**
  362. * Aktion und Methode der Subform hinzufügen
  363. *
  364. * @param Zend_Form_SubForm $subForm
  365. * @return My_Form_Registration
  366. */
  367. public function addSubFormActions(Zend_Form_SubForm $subForm)
  368. {
  369. $subForm->setAction('/registration/process')
  370. ->setMethod('post');
  371. return $this;
  372. }
  373. }
  374. ]]>
  375. </programlisting>
  376. <para>
  377. Als nächstes benötigen wir das Grundgerüst für unseren Action Controller, und wir
  378. haben verschiedene Entscheidungen zu treffen. Zuerst müssen wir sicherstellen, dass
  379. die Formulardaten zwischen den Anfragen fixiert werden, sodass wir feststellen
  380. können wann abgebrochen wird. Zweitens wird etwas Logik benötigt, um festzustellen
  381. welche Formularteile bereits übermittelt wurden und welches Unterformular, basierend
  382. auf dieser Information, angezeigt werden soll. Wir verwenden
  383. <classname>Zend_Session_Namespace</classname> um Daten zu fixieren, was uns auch hilft die
  384. Frage zu beantworten welches Formular zu übertragen ist.
  385. </para>
  386. <para>
  387. Erstellen wir also unseren Controller, und fügen eine Methode für den Empfang der
  388. Formular Instanz hinzu:
  389. </para>
  390. <programlisting role="php"><![CDATA[
  391. class RegistrationController extends Zend_Controller_Action
  392. {
  393. protected $_form;
  394. public function getForm()
  395. {
  396. if (null === $this->_form) {
  397. $this->_form = new My_Form_Registration();
  398. }
  399. return $this->_form;
  400. }
  401. }
  402. ]]>
  403. </programlisting>
  404. <para>
  405. Füllen wir unseren Controller nun um die Funktionalität, zu erkennen, welches
  406. Formular angezeigt werden soll. Grundsätzlich müssen wir, bis das komplette
  407. Formular als gültig angenommen wird, die Darstellung der Formularabschnitte
  408. weiterführen. Zusätzlich müssen wir sicherstellen, dass sie in einer bestimmten
  409. Reihenfolge sind: Benutzer, Zusätze und dann Listen. Wir können feststellen, ob
  410. Daten übertragen wurden, indem wir im Namensraum der Session nach speziellen
  411. Schlüssen suchen, die jedes Unterformular repräsentieren.
  412. </para>
  413. <programlisting role="php"><![CDATA[
  414. class RegistrationController extends Zend_Controller_Action
  415. {
  416. // ...
  417. protected $_namespace = 'RegistrationController';
  418. protected $_session;
  419. /**
  420. * Den Session Namespace erhalten den wir verwenden
  421. *
  422. * @return Zend_Session_Namespace
  423. */
  424. public function getSessionNamespace()
  425. {
  426. if (null === $this->_session) {
  427. $this->_session =
  428. new Zend_Session_Namespace($this->_namespace);
  429. }
  430. return $this->_session;
  431. }
  432. /**
  433. * Eine Liste von bereits in der Session gespeicherten Forms erhalten
  434. *
  435. * @return array
  436. */
  437. public function getStoredForms()
  438. {
  439. $stored = array();
  440. foreach ($this->getSessionNamespace() as $key => $value) {
  441. $stored[] = $key;
  442. }
  443. return $stored;
  444. }
  445. /**
  446. * Eine Liste aller vorhandenen Subforms erhalten
  447. *
  448. * @return array
  449. */
  450. public function getPotentialForms()
  451. {
  452. return array_keys($this->getForm()->getSubForms());
  453. }
  454. /**
  455. * Welche Subform wurde übermittelt?
  456. *
  457. * @return false|Zend_Form_SubForm
  458. */
  459. public function getCurrentSubForm()
  460. {
  461. $request = $this->getRequest();
  462. if (!$request->isPost()) {
  463. return false;
  464. }
  465. foreach ($this->getPotentialForms() as $name) {
  466. if ($data = $request->getPost($name, false)) {
  467. if (is_array($data)) {
  468. return $this->getForm()->getSubForm($name);
  469. break;
  470. }
  471. }
  472. }
  473. return false;
  474. }
  475. /**
  476. * Die nächste Suboform für die Anzeige erhalten
  477. *
  478. * @return Zend_Form_SubForm|false
  479. */
  480. public function getNextSubForm()
  481. {
  482. $storedForms = $this->getStoredForms();
  483. $potentialForms = $this->getPotentialForms();
  484. foreach ($potentialForms as $name) {
  485. if (!in_array($name, $storedForms)) {
  486. return $this->getForm()->getSubForm($name);
  487. }
  488. }
  489. return false;
  490. }
  491. }
  492. ]]>
  493. </programlisting>
  494. <para>
  495. Die obigen Methoden erlauben uns eine Schreibweise wie
  496. <code>$subForm = $this-&gt;getCurrentSubForm();</code> um das aktuelle Unterformular
  497. für die Prüfung zu erhalten, oder <code>$next = $this-&gt;getNextSubForm();</code>,
  498. um die nächste anzuzeigen.
  499. </para>
  500. <para>
  501. Sehen wir uns nun an, wie die verschiedenen Unterformulare bearbeitet und angezeigt
  502. werden können. Wir können <code>getCurrentSubForm()</code> verwenden um
  503. herauszufinden ob ein Unterformular übertragen wurde (<code>false</code> Rückgabewerte
  504. zeigen an, dass keine angezeigt oder übertragen wurden) und <code>getNextSubForm()</code>
  505. empfängt die Form die angezeigt werden soll. Wir können die <code>prepareSubForm()</code>
  506. Methode des Formulars verwenden, um sicherzustellen, dass das Formular bereit zur Anzeige
  507. ist.
  508. </para>
  509. <para>
  510. Wenn ein Formular übertragen wird, kann das Unterformular bestätigt werden, und dann kann
  511. geprüft werden, ob das komplette Formular gültig ist. Um diese Arbeiten durchzuführen
  512. werden zusätzliche Methoden benötigt die sicherstellen, dass die übermittelten Daten der
  513. Session hinzugefügt werden, und, dass, wenn das komplette Formular geprüft wird, die
  514. Prüfung gegen alle Teile der Session durchgeführt wird:
  515. </para>
  516. <programlisting role="php"><![CDATA[
  517. class RegistrationController extends Zend_Form
  518. {
  519. // ...
  520. /**
  521. * Ist die Form gültig?
  522. *
  523. * @param Zend_Form_SubForm $subForm
  524. * @param array $data
  525. * @return bool
  526. */
  527. public function subFormIsValid(Zend_Form_SubForm $subForm,
  528. array $data)
  529. {
  530. $name = $subForm->getName();
  531. if ($subForm->isValid($data)) {
  532. $this->getSessionNamespace()->$name = $subForm->getValues();
  533. return true;
  534. }
  535. return false;
  536. }
  537. /**
  538. * Ist die komplette Form gültig?
  539. *
  540. * @return bool
  541. */
  542. public function formIsValid()
  543. {
  544. $data = array();
  545. foreach ($this->getSessionNamespace() as $key => $info) {
  546. $data[$key] = $info;
  547. }
  548. return $this->getForm()->isValid($data);
  549. }
  550. }
  551. ]]>
  552. </programlisting>
  553. <para>
  554. Jetzt, da die Kleinarbeiten aus dem Weg sind, können die Aktionen für diesen
  555. Controller erstellt werden. Es wird eine Grundseite für das Formular und dann
  556. eine 'process' (Bearbeiten) Aktion für die Bearbeitung des Formulars benötigt.
  557. </para>
  558. <programlisting role="php"><![CDATA[
  559. class RegistrationController extends Zend_Controller_Action
  560. {
  561. // ...
  562. public function indexAction()
  563. {
  564. // Entweder die aktuelle Seite nochmals anzeigen, oder
  565. // die nächste "next" (erste) Subform holen
  566. if (!$form = $this->getCurrentSubForm()) {
  567. $form = $this->getNextSubForm();
  568. }
  569. $this->view->form = $this->getForm()->prepareSubForm($form);
  570. }
  571. public function processAction()
  572. {
  573. if (!$form = $this->getCurrentSubForm()) {
  574. return $this->_forward('index');
  575. }
  576. if (!$this->subFormIsValid($form,
  577. $this->getRequest()->getPost())) {
  578. $this->view->form = $this->getForm()->prepareSubForm($form);
  579. return $this->render('index');
  580. }
  581. if (!$this->formIsValid()) {
  582. $form = $this->getNextSubForm();
  583. $this->view->form = $this->getForm()->prepareSubForm($form);
  584. return $this->render('index');
  585. }
  586. // Gültige Form!
  587. // Information in einer Prüfseite darstellen
  588. $this->view->info = $this->getSessionNamespace();
  589. $this->render('verification');
  590. }
  591. }
  592. ]]>
  593. </programlisting>
  594. <para>
  595. Wie festzustellen ist, ist der aktuelle Code für die Bearbeitung des Formulars
  596. relativ einfach. Wir prüfen, um zu sehen ob wir eine aktuelle Übertragung eines
  597. Unterformulars haben, oder nicht, und wir versuchen sie zu prüfen, und sie nochmals
  598. darzustellen wenn es fehlschlägt. Wenn das Unterformular gültig ist, muss anschließend
  599. geprüft werden, ob das Formular gültig ist, was dann bedeuten würde, dass wir fertig
  600. sind; wen nicht muss das nächste Formularsegment angezeigt werden. Letztendlich wird
  601. eine Prüfseite mit dem Inhalt der Session angezeigt.
  602. </para>
  603. <para>
  604. Die View Skripte sind sehr einfach:
  605. </para>
  606. <programlisting role="php"><![CDATA[
  607. <?php // registration/index.phtml ?>
  608. <h2>Registration</h2>
  609. <?php echo $this->form ?>
  610. <?php // registration/verification.phtml ?>
  611. <h2>Danke für die Registrierung!</h2>
  612. <p>
  613. Hier sind die angegebenen Informationen:
  614. </p>
  615. <?
  616. // Dieses Konstrukt muß getan werden wegen dem Weg wie Elemente
  617. // im Session Namespace gespeichert werden
  618. foreach ($this->info as $info):
  619. foreach ($info as $form => $data): ?>
  620. <h4><?php echo ucfirst($form) ?>:</h4>
  621. <dl>
  622. <?php foreach ($data as $key => $value): ?>
  623. <dt><?php echo ucfirst($key) ?></dt>
  624. <?php if (is_array($value)):
  625. foreach ($value as $label => $val): ?>
  626. <dd><?php echo $val ?></dd>
  627. <?php endforeach;
  628. else: ?>
  629. <dd><?php echo $this->escape($value) ?></dd>
  630. <?php endif;
  631. endforeach; ?>
  632. </dl>
  633. <?php endforeach;
  634. endforeach ?>
  635. ]]>
  636. </programlisting>
  637. <para>
  638. Kommende Releases des Zend Frameworks werden Komponenten enthalten die
  639. mehrseitige Formulare einfacher machen - durch die Abstraktion der Session
  640. und der Reihungslogik. In der Zwischenzeit sollte das obige Beispiel als
  641. angemessene Grundlage dienen, wie diese Aufgabe für eigene Seiten realisiert
  642. werden kann.
  643. </para>
  644. </example>
  645. </sect2>
  646. </sect1>
  647. <!--
  648. vim:se ts=4 sw=4 et:
  649. -->