2
0

Zend_Form-Advanced.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 15617 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.form.advanced">
  5. <title>Fortgeschrittene Verwendung von Zend_Form</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 language="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. ]]></programlisting>
  61. <para>
  62. In diesem Beispiel enthalten die Rechnungs- und Versanadresse einige identische
  63. Felder, was bedeueten würde, dass sie sich gegenseitig überschreiben. Wir können
  64. das durch die Verwendung der Array Schreibweise lösen:
  65. </para>
  66. <programlisting language="html"><![CDATA[
  67. <form>
  68. <fieldset>
  69. <legend>Versandadresse</legend>
  70. <dl>
  71. <dt><label for="shipping-recipient">Versand an:</label></dt>
  72. <dd><input name="shipping[recipient]" id="shipping-recipient"
  73. type="text" value="" /></dd>
  74. <dt><label for="shipping-address">Adresse:</label></dt>
  75. <dd><input name="shipping[address]" id="shipping-address"
  76. type="text" value="" /></dd>
  77. <dt><label for="shipping-municipality">Stadt:</label></dt>
  78. <dd><input name="shipping[municipality]" id="shipping-municipality"
  79. type="text" value="" /></dd>
  80. <dt><label for="shipping-province">Bundesland:</label></dt>
  81. <dd><input name="shipping[province]" id="shipping-province"
  82. type="text" value="" /></dd>
  83. <dt><label for="shipping-postal">Postleitzahl:</label></dt>
  84. <dd><input name="shipping[postal]" id="shipping-postal"
  85. type="text" value="" /></dd>
  86. </dl>
  87. </fieldset>
  88. <fieldset>
  89. <legend>Rechnungsadresse</legend>
  90. <dl>
  91. <dt><label for="billing-payer">Rechnung an:</label></dt>
  92. <dd><input name="billing[payer]" id="billing-payer"
  93. type="text" value="" /></dd>
  94. <dt><label for="billing-address">Adresse:</label></dt>
  95. <dd><input name="billing[address]" id="billing-address"
  96. type="text" value="" /></dd>
  97. <dt><label for="billing-municipality">Stadt:</label></dt>
  98. <dd><input name="billing[municipality]" id="billing-municipality"
  99. type="text" value="" /></dd>
  100. <dt><label for="billing-province">Bundesland:</label></dt>
  101. <dd><input name="billing[province]" id="billing-province"
  102. type="text" value="" /></dd>
  103. <dt><label for="billing-postal">Postleitzahl:</label></dt>
  104. <dd><input name="billing[postal]" id="billing-postal"
  105. type="text" value="" /></dd>
  106. </dl>
  107. </fieldset>
  108. <dl>
  109. <dt><label for="terms">Ich stimme den AGBs zu</label></dt>
  110. <dd><input name="terms" type="checkbox" value="" /></dd>
  111. <dt></dt>
  112. <dd><input name="save" type="submit" value="Speichern" /></dd>
  113. </dl>
  114. </form>
  115. ]]></programlisting>
  116. <para>
  117. In dem obigen Beispiel erhalten wir jetzt separate Adressen. In der übermittelten Form
  118. haben wir jetzt zwei Elemente, 'shipping' und 'billing', jedes mit Schlüsseln für
  119. deren verschiedene Elemente.
  120. </para>
  121. <para>
  122. <classname>Zend_Form</classname> versucht diesen Prozess mit seinen
  123. <link linkend="zend.form.forms.subforms">Unterformularen</link> zu automatisieren.
  124. Standardmäßig werden Unterformulare dargestellt, indem die Array Schreibweise, wie im
  125. vorherigen HTML Form Code gezeigt, komplett mit Ids, verwendet wird. Der Arrayname
  126. basiert auf dem Namen des Unterformulars, mit den Schlüsseln basierend auf den
  127. Elementen, die im Unterformualr enthalten sind. Unterformulare können beliebig tief
  128. verschachtelt sein, und das erzeugt verschachtelte Arrays um die Struktur zu
  129. reflektieren. Zusätzlich beachten die verschiedenen Prüfroutinen in
  130. <classname>Zend_Form</classname> die Arraystruktur, und stellen sicher, dass die form
  131. korrekt überprüft wird, egal wie tief verschachtelt die Unterformulare sind. Es muss
  132. nichts getan werden, um davon zu profitieren; dieses Verhalten ist standardmäßig
  133. aktiviert.
  134. </para>
  135. <para>
  136. Zusätzlich gibt es Möglichkeiten, die es erlauben die Array Schreibweise fallweise
  137. zu aktivieren, wie auch die Spezifikation eines speziellen Array zu welchem ein
  138. Element oder eine Sammlung gehört:
  139. </para>
  140. <itemizedlist>
  141. <listitem>
  142. <para>
  143. <classname>Zend_Form::setIsArray($flag)</classname>: Durch das Setzen dieses
  144. Flags auf <constant>TRUE</constant>, kann angezeigt werden, dass das komplette Formular
  145. als Array behandelt werden soll. Standardmäßig wird der Name des Formulars als
  146. Name des Arrays verwendet, solange <code>setElementsBelongTo()</code> aufgerufen
  147. wurde. Wenn das Formular keinen Namen spezifiziert hat, oder
  148. <code>setElementsBelongTo()</code> nicht gesetzt wurde, wird dieses Flag
  149. ignoriert (da es kein Arraynamen gibt zu dem die Elemente gehören).
  150. </para>
  151. <para>
  152. Man kann auswählen, ob ein Formular als Array behandelt wird, indem die
  153. Zugriffsmethode <code>isArray()</code> verwendet wird.
  154. </para>
  155. </listitem>
  156. <listitem><para>
  157. <classname>Zend_Form::setElementsBelongTo($array)</classname>: Durch Verwendung
  158. dieser Methode kann der Name eines Arrays spezifiziert werden dem alle Elemente
  159. des Formulars angehören. Der Name kann durch Verwendung der Zugriffsmethode
  160. <code>getElementsBelongTo()</code> eruiert werden.
  161. </para></listitem>
  162. </itemizedlist>
  163. <para>
  164. Zusätzlich können auf dem Element Level, individuelle Elemente spezifiziert werden die
  165. bestimmten Arrays angehören indem die
  166. <classname>Zend_Form_Element::setBelongsTo()</classname> Methode verwendet wird. Um
  167. herauszufinden welcher Wert gesetzt ist -- egal ob dieser explizit gesetzt wurde oder
  168. implzit über das Formular -- kann die Zugriffsmethode <code>getBelongsTo()</code>
  169. 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 language="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. ]]></programlisting>
  292. <para>
  293. Es ist zu beachten, dass es keinen 'Abschicken' Button gibt, und, dass wir
  294. nichts mit den Dekoratoren des Unterformulars gemacht haben -- was bedeutet,
  295. dass Sie standardmäßig als Fieldsets angezeigt werden. Wir müssen das Überladen
  296. wenn wir jedes individuelle Unterformular anzeigen wollen und einen 'Abschicken'
  297. Button hinzufügen, damit wir sie dann bearbeiten können -- was auch Aktions- und
  298. Methodeneigenschaften benötigt. Füllen wir unsere Klasse ein wenig und bieten
  299. diese Information:
  300. </para>
  301. <programlisting language="php"><![CDATA[
  302. class My_Form_Registration extends Zend_Form
  303. {
  304. // ...
  305. /**
  306. * Eine Subform für die anzeige Vorbereiten
  307. *
  308. * @param string|Zend_Form_SubForm $spec
  309. * @return Zend_Form_SubForm
  310. */
  311. public function prepareSubForm($spec)
  312. {
  313. if (is_string($spec)) {
  314. $subForm = $this->{$spec};
  315. } elseif ($spec instanceof Zend_Form_SubForm) {
  316. $subForm = $spec;
  317. } else {
  318. throw new Exception('Ungültiges Argument an ' .
  319. __FUNCTION__ . '() übergeben');
  320. }
  321. $this->setSubFormDecorators($subForm)
  322. ->addSubmitButton($subForm)
  323. ->addSubFormActions($subForm);
  324. return $subForm;
  325. }
  326. /**
  327. * Form Dekoratore zu einer individuellen Subform hinzufügen
  328. *
  329. * @param Zend_Form_SubForm $subForm
  330. * @return My_Form_Registration
  331. */
  332. public function setSubFormDecorators(Zend_Form_SubForm $subForm)
  333. {
  334. $subForm->setDecorators(array(
  335. 'FormElements',
  336. array('HtmlTag', array('tag' => 'dl',
  337. 'class' => 'zend_form')),
  338. 'Form',
  339. ));
  340. return $this;
  341. }
  342. /**
  343. * Einen Sendebutton in einer individuellen Subform hinzufügen
  344. *
  345. * @param Zend_Form_SubForm $subForm
  346. * @return My_Form_Registration
  347. */
  348. public function addSubmitButton(Zend_Form_SubForm $subForm)
  349. {
  350. $subForm->addElement(new Zend_Form_Element_Submit(
  351. 'save',
  352. array(
  353. 'label' => 'Speichern und Fortfahren',
  354. 'required' => false,
  355. 'ignore' => true,
  356. )
  357. ));
  358. return $this;
  359. }
  360. /**
  361. * Aktion und Methode der Subform hinzufügen
  362. *
  363. * @param Zend_Form_SubForm $subForm
  364. * @return My_Form_Registration
  365. */
  366. public function addSubFormActions(Zend_Form_SubForm $subForm)
  367. {
  368. $subForm->setAction('/registration/process')
  369. ->setMethod('post');
  370. return $this;
  371. }
  372. }
  373. ]]></programlisting>
  374. <para>
  375. Als nächstes benötigen wir das Grundgerüst für unseren Action Controller, und wir
  376. haben verschiedene Entscheidungen zu treffen. Zuerst müssen wir sicherstellen, dass
  377. die Formulardaten zwischen den Anfragen fixiert werden, sodass wir feststellen
  378. können wann abgebrochen wird. Zweitens wird etwas Logik benötigt, um festzustellen
  379. welche Formularteile bereits übermittelt wurden und welches Unterformular, basierend
  380. auf dieser Information, angezeigt werden soll. Wir verwenden
  381. <classname>Zend_Session_Namespace</classname> um Daten zu fixieren, was uns auch
  382. hilft die Frage zu beantworten welches Formular zu übertragen ist.
  383. </para>
  384. <para>
  385. Erstellen wir also unseren Controller, und fügen eine Methode für den Empfang der
  386. Formular Instanz hinzu:
  387. </para>
  388. <programlisting language="php"><![CDATA[
  389. class RegistrationController extends Zend_Controller_Action
  390. {
  391. protected $_form;
  392. public function getForm()
  393. {
  394. if (null === $this->_form) {
  395. $this->_form = new My_Form_Registration();
  396. }
  397. return $this->_form;
  398. }
  399. }
  400. ]]></programlisting>
  401. <para>
  402. Füllen wir unseren Controller nun um die Funktionalität, zu erkennen, welches
  403. Formular angezeigt werden soll. Grundsätzlich müssen wir, bis das komplette
  404. Formular als gültig angenommen wird, die Darstellung der Formularabschnitte
  405. weiterführen. Zusätzlich müssen wir sicherstellen, dass sie in einer bestimmten
  406. Reihenfolge sind: Benutzer, Zusätze und dann Listen. Wir können feststellen, ob
  407. Daten übertragen wurden, indem wir im Namensraum der Session nach speziellen
  408. Schlüssen suchen, die jedes Unterformular repräsentieren.
  409. </para>
  410. <programlisting language="php"><![CDATA[
  411. class RegistrationController extends Zend_Controller_Action
  412. {
  413. // ...
  414. protected $_namespace = 'RegistrationController';
  415. protected $_session;
  416. /**
  417. * Den Session Namespace erhalten den wir verwenden
  418. *
  419. * @return Zend_Session_Namespace
  420. */
  421. public function getSessionNamespace()
  422. {
  423. if (null === $this->_session) {
  424. $this->_session =
  425. new Zend_Session_Namespace($this->_namespace);
  426. }
  427. return $this->_session;
  428. }
  429. /**
  430. * Eine Liste von bereits in der Session gespeicherten Forms erhalten
  431. *
  432. * @return array
  433. */
  434. public function getStoredForms()
  435. {
  436. $stored = array();
  437. foreach ($this->getSessionNamespace() as $key => $value) {
  438. $stored[] = $key;
  439. }
  440. return $stored;
  441. }
  442. /**
  443. * Eine Liste aller vorhandenen Subforms erhalten
  444. *
  445. * @return array
  446. */
  447. public function getPotentialForms()
  448. {
  449. return array_keys($this->getForm()->getSubForms());
  450. }
  451. /**
  452. * Welche Subform wurde übermittelt?
  453. *
  454. * @return false|Zend_Form_SubForm
  455. */
  456. public function getCurrentSubForm()
  457. {
  458. $request = $this->getRequest();
  459. if (!$request->isPost()) {
  460. return false;
  461. }
  462. foreach ($this->getPotentialForms() as $name) {
  463. if ($data = $request->getPost($name, false)) {
  464. if (is_array($data)) {
  465. return $this->getForm()->getSubForm($name);
  466. break;
  467. }
  468. }
  469. }
  470. return false;
  471. }
  472. /**
  473. * Die nächste Suboform für die Anzeige erhalten
  474. *
  475. * @return Zend_Form_SubForm|false
  476. */
  477. public function getNextSubForm()
  478. {
  479. $storedForms = $this->getStoredForms();
  480. $potentialForms = $this->getPotentialForms();
  481. foreach ($potentialForms as $name) {
  482. if (!in_array($name, $storedForms)) {
  483. return $this->getForm()->getSubForm($name);
  484. }
  485. }
  486. return false;
  487. }
  488. }
  489. ]]></programlisting>
  490. <para>
  491. Die obigen Methoden erlauben uns eine Schreibweise wie
  492. <code>$subForm = $this-&gt;getCurrentSubForm();</code> um das aktuelle Unterformular
  493. für die Prüfung zu erhalten, oder <code>$next = $this-&gt;getNextSubForm();</code>,
  494. um die nächste anzuzeigen.
  495. </para>
  496. <para>
  497. Sehen wir uns nun an, wie die verschiedenen Unterformulare bearbeitet und angezeigt
  498. werden können. Wir können <code>getCurrentSubForm()</code> verwenden um
  499. herauszufinden ob ein Unterformular übertragen wurde (<constant>FALSE</constant>
  500. Rückgabewerte zeigen an, dass keine angezeigt oder übertragen wurden) und
  501. <code>getNextSubForm()</code> empfängt die Form die angezeigt werden soll. Wir
  502. können die <code>prepareSubForm()</code> Methode des Formulars verwenden, um
  503. sicherzustellen, dass das Formular bereit zur Anzeige ist.
  504. </para>
  505. <para>
  506. Wenn ein Formular übertragen wird, kann das Unterformular bestätigt werden, und dann
  507. kann geprüft werden, ob das komplette Formular gültig ist. Um diese Arbeiten
  508. durchzuführen werden zusätzliche Methoden benötigt die sicherstellen, dass die
  509. übermittelten Daten der Session hinzugefügt werden, und, dass, wenn das komplette
  510. Formular geprüft wird, die Prüfung gegen alle Teile der Session durchgeführt wird:
  511. </para>
  512. <programlisting language="php"><![CDATA[
  513. class RegistrationController extends Zend_Form
  514. {
  515. // ...
  516. /**
  517. * Ist die Form gültig?
  518. *
  519. * @param Zend_Form_SubForm $subForm
  520. * @param array $data
  521. * @return bool
  522. */
  523. public function subFormIsValid(Zend_Form_SubForm $subForm,
  524. array $data)
  525. {
  526. $name = $subForm->getName();
  527. if ($subForm->isValid($data)) {
  528. $this->getSessionNamespace()->$name = $subForm->getValues();
  529. return true;
  530. }
  531. return false;
  532. }
  533. /**
  534. * Ist die komplette Form gültig?
  535. *
  536. * @return bool
  537. */
  538. public function formIsValid()
  539. {
  540. $data = array();
  541. foreach ($this->getSessionNamespace() as $key => $info) {
  542. $data[$key] = $info;
  543. }
  544. return $this->getForm()->isValid($data);
  545. }
  546. }
  547. ]]></programlisting>
  548. <para>
  549. Jetzt, da die Kleinarbeiten aus dem Weg sind, können die Aktionen für diesen
  550. Controller erstellt werden. Es wird eine Grundseite für das Formular und dann
  551. eine 'process' (Bearbeiten) Aktion für die Bearbeitung des Formulars benötigt.
  552. </para>
  553. <programlisting language="php"><![CDATA[
  554. class RegistrationController extends Zend_Controller_Action
  555. {
  556. // ...
  557. public function indexAction()
  558. {
  559. // Entweder die aktuelle Seite nochmals anzeigen, oder
  560. // die nächste "next" (erste) Subform holen
  561. if (!$form = $this->getCurrentSubForm()) {
  562. $form = $this->getNextSubForm();
  563. }
  564. $this->view->form = $this->getForm()->prepareSubForm($form);
  565. }
  566. public function processAction()
  567. {
  568. if (!$form = $this->getCurrentSubForm()) {
  569. return $this->_forward('index');
  570. }
  571. if (!$this->subFormIsValid($form,
  572. $this->getRequest()->getPost())) {
  573. $this->view->form = $this->getForm()->prepareSubForm($form);
  574. return $this->render('index');
  575. }
  576. if (!$this->formIsValid()) {
  577. $form = $this->getNextSubForm();
  578. $this->view->form = $this->getForm()->prepareSubForm($form);
  579. return $this->render('index');
  580. }
  581. // Gültige Form!
  582. // Information in einer Prüfseite darstellen
  583. $this->view->info = $this->getSessionNamespace();
  584. $this->render('verification');
  585. }
  586. }
  587. ]]></programlisting>
  588. <para>
  589. Wie festzustellen ist, ist der aktuelle Code für die Bearbeitung des Formulars
  590. relativ einfach. Wir prüfen, um zu sehen ob wir eine aktuelle Übertragung eines
  591. Unterformulars haben, oder nicht, und wir versuchen sie zu prüfen, und sie nochmals
  592. darzustellen wenn es fehlschlägt. Wenn das Unterformular gültig ist, muss
  593. anschließend geprüft werden, ob das Formular gültig ist, was dann bedeuten würde,
  594. dass wir fertig sind; wen nicht muss das nächste Formularsegment angezeigt werden.
  595. Letztendlich wird eine Prüfseite mit dem Inhalt der Session angezeigt.
  596. </para>
  597. <para>
  598. Die View Skripte sind sehr einfach:
  599. </para>
  600. <programlisting language="php"><![CDATA[
  601. <?php // registration/index.phtml ?>
  602. <h2>Registration</h2>
  603. <?php echo $this->form ?>
  604. <?php // registration/verification.phtml ?>
  605. <h2>Danke für die Registrierung!</h2>
  606. <p>
  607. Hier sind die angegebenen Informationen:
  608. </p>
  609. <?
  610. // Dieses Konstrukt muß getan werden wegen dem Weg wie Elemente
  611. // im Session Namespace gespeichert werden
  612. foreach ($this->info as $info):
  613. foreach ($info as $form => $data): ?>
  614. <h4><?php echo ucfirst($form) ?>:</h4>
  615. <dl>
  616. <?php foreach ($data as $key => $value): ?>
  617. <dt><?php echo ucfirst($key) ?></dt>
  618. <?php if (is_array($value)):
  619. foreach ($value as $label => $val): ?>
  620. <dd><?php echo $val ?></dd>
  621. <?php endforeach;
  622. else: ?>
  623. <dd><?php echo $this->escape($value) ?></dd>
  624. <?php endif;
  625. endforeach; ?>
  626. </dl>
  627. <?php endforeach;
  628. endforeach ?>
  629. ]]></programlisting>
  630. <para>
  631. Kommende Releases des Zend Frameworks werden Komponenten enthalten die
  632. mehrseitige Formulare einfacher machen - durch die Abstraktion der Session
  633. und der Reihungslogik. In der Zwischenzeit sollte das obige Beispiel als
  634. angemessene Grundlage dienen, wie diese Aufgabe für eigene Seiten realisiert
  635. werden kann.
  636. </para>
  637. </example>
  638. </sect2>
  639. </sect1>
  640. <!--
  641. vim:se ts=4 sw=4 et:
  642. -->