Zend_Form-Advanced.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  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 <acronym>HTML</acronym> Form Code gezeigt, komplett mit Ids, verwendet wird.
  126. Der Arrayname basiert auf dem Namen des Unterformulars, mit den Schlüsseln basierend auf
  127. den 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. <methodname>Zend_Form::setIsArray($flag)</methodname>: Durch das Setzen dieses
  144. Flags auf <constant>TRUE</constant>, kann angezeigt werden, dass das komplette
  145. Formular als Array behandelt werden soll. Standardmäßig wird der Name des
  146. Formulars als Name des Arrays verwendet, solange
  147. <methodname>setElementsBelongTo()</methodname> aufgerufen wurde. Wenn das
  148. Formular keinen Namen spezifiziert hat, oder
  149. <methodname>setElementsBelongTo()</methodname> nicht gesetzt wurde, wird dieses
  150. Flag ignoriert (da es kein Arraynamen gibt zu dem die Elemente gehören).
  151. </para>
  152. <para>
  153. Man kann auswählen, ob ein Formular als Array behandelt wird, indem die
  154. Zugriffsmethode <methodname>isArray()</methodname> verwendet wird.
  155. </para>
  156. </listitem>
  157. <listitem>
  158. <para>
  159. <methodname>Zend_Form::setElementsBelongTo($array)</methodname>: Durch
  160. Verwendung dieser Methode kann der Name eines Arrays spezifiziert werden dem
  161. alle Elemente des Formulars angehören. Der Name kann durch Verwendung der
  162. Zugriffsmethode <methodname>getElementsBelongTo()</methodname> eruiert werden.
  163. </para>
  164. </listitem>
  165. </itemizedlist>
  166. <para>
  167. Zusätzlich können auf dem Element Level, individuelle Elemente spezifiziert werden die
  168. bestimmten Arrays angehören indem die
  169. <methodname>Zend_Form_Element::setBelongsTo()</methodname> Methode verwendet wird. Um
  170. herauszufinden welcher Wert gesetzt ist -- egal ob dieser explizit gesetzt wurde oder
  171. implzit über das Formular -- kann die Zugriffsmethode
  172. <methodname>getBelongsTo()</methodname> verwendet werden.
  173. </para>
  174. </sect2>
  175. <sect2 id="zend.form.advanced.multiPage">
  176. <title>Mehrseitige Formulare</title>
  177. <para>
  178. Aktuell werden mehrseitige Formulare nicht offiziell in <classname>Zend_Form</classname>
  179. unterstützt; trotzdem ist die meiste Unterstützung für deren Implementierung bereits
  180. vorhanden und kann mit etwas extra Code angepasst werden.
  181. </para>
  182. <para>
  183. Der Schlüssel in der Erstellung von mehrseitigen Formularen, ist die Anpassung von
  184. Unterformularen, aber der Anzeige, von nur einem Unterformular pro Seite. Das erlaubt
  185. es, ein einzelnes Unterformular auf einmal zu übertragen und diese zu prüfen, aber das
  186. Formular nicht zu bearbeiten bis alle weiteren Unterformulare komplett sind.
  187. </para>
  188. <example id="zend.form.advanced.multiPage.registration">
  189. <title>Beispiel: Anmeldeformular</title>
  190. <para>
  191. Verwenden wir also ein Anmeldeformular als Beispiel. Für unsere Zwecke wollen wir
  192. auf der ersten Seite einen gewünschten Benutzernamen und Passwort holen, dann die
  193. Metadaten des Benutzers -- das heißt Vorname, Familienname und Wohnort -- und
  194. letztendlich die Auswahl welcher Mailingliste, wenn überhaupt, der Benutzer
  195. angehören will.
  196. </para>
  197. <para>
  198. Erstellen wir als erstes unser, eigenes, Formular und definieren in diesem die
  199. verschiedenen Unterformulare:
  200. </para>
  201. <programlisting language="php"><![CDATA[
  202. class My_Form_Registration extends Zend_Form
  203. {
  204. public function init()
  205. {
  206. // Erstellt die Benutzer Subform: Benutzername und Passwort
  207. $user = new Zend_Form_SubForm();
  208. $user->addElements(array(
  209. new Zend_Form_Element_Text('username', array(
  210. 'required' => true,
  211. 'label' => 'Benutzername:',
  212. 'filters' => array('StringTrim', 'StringToLower'),
  213. 'validators' => array(
  214. 'Alnum',
  215. array('Regex',
  216. false,
  217. array('/^[a-z][a-z0-9]{2,}$/'))
  218. )
  219. )),
  220. new Zend_Form_Element_Password('password', array(
  221. 'required' => true,
  222. 'label' => 'Passwort:',
  223. 'filters' => array('StringTrim'),
  224. 'validators' => array(
  225. 'NotEmpty',
  226. array('StringLength', false, array(6))
  227. )
  228. )),
  229. ));
  230. // Erstellt die Demographische Subform: Vorname,
  231. // Familienname und Ort
  232. $demog = new Zend_Form_SubForm();
  233. $demog->addElements(array(
  234. new Zend_Form_Element_Text('givenName', array(
  235. 'required' => true,
  236. 'label' => 'Vorname (erster):',
  237. 'filters' => array('StringTrim'),
  238. 'validators' => array(
  239. array('Regex',
  240. false,
  241. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  242. )
  243. )),
  244. new Zend_Form_Element_Text('familyName', array(
  245. 'required' => true,
  246. 'label' => 'Familienname (letzter):',
  247. 'filters' => array('StringTrim'),
  248. 'validators' => array(
  249. array('Regex',
  250. false,
  251. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  252. )
  253. )),
  254. new Zend_Form_Element_Text('location', array(
  255. 'required' => true,
  256. 'label' => 'Der eigene Ort:',
  257. 'filters' => array('StringTrim'),
  258. 'validators' => array(
  259. array('StringLength', false, array(2))
  260. )
  261. )),
  262. ));
  263. // Erstellt die Mailinglisten Subform
  264. $listOptions = array(
  265. 'none' => 'keine Listen bitte',
  266. 'fw-general' => 'Zend Framework General Liste',
  267. 'fw-mvc' => 'Zend Framework MVC Liste',
  268. 'fw-auth' => 'Zend Framework Authentication und ACL Liste',
  269. 'fw-services' => 'Zend Framework Web Services Liste',
  270. );
  271. $lists = new Zend_Form_SubForm();
  272. $lists->addElements(array(
  273. new Zend_Form_Element_MultiCheckbox('subscriptions', array(
  274. 'label' =>
  275. 'Welche Liste wollen Sie erhalten?',
  276. 'multiOptions' => $listOptions,
  277. 'required' => true,
  278. 'filters' => array('StringTrim'),
  279. 'validators' => array(
  280. array('InArray',
  281. false,
  282. array(array_keys($listOptions)))
  283. )
  284. )),
  285. ));
  286. // Die Subformen der Hauptform anhängen
  287. $this->addSubForms(array(
  288. 'user' => $user,
  289. 'demog' => $demog,
  290. 'lists' => $lists
  291. ));
  292. }
  293. }
  294. ]]></programlisting>
  295. <para>
  296. Es ist zu beachten, dass es keinen 'Abschicken' Button gibt, und, dass wir
  297. nichts mit den Dekoratoren des Unterformulars gemacht haben -- was bedeutet,
  298. dass Sie standardmäßig als Fieldsets angezeigt werden. Wir müssen das Überladen
  299. wenn wir jedes individuelle Unterformular anzeigen wollen und einen 'Abschicken'
  300. Button hinzufügen, damit wir sie dann bearbeiten können -- was auch Aktions- und
  301. Methodeneigenschaften benötigt. Füllen wir unsere Klasse ein wenig und bieten
  302. diese Information:
  303. </para>
  304. <programlisting language="php"><![CDATA[
  305. class My_Form_Registration extends Zend_Form
  306. {
  307. // ...
  308. /**
  309. * Eine Subform für die anzeige Vorbereiten
  310. *
  311. * @param string|Zend_Form_SubForm $spec
  312. * @return Zend_Form_SubForm
  313. */
  314. public function prepareSubForm($spec)
  315. {
  316. if (is_string($spec)) {
  317. $subForm = $this->{$spec};
  318. } elseif ($spec instanceof Zend_Form_SubForm) {
  319. $subForm = $spec;
  320. } else {
  321. throw new Exception('Ungültiges Argument an ' .
  322. __FUNCTION__ . '() übergeben');
  323. }
  324. $this->setSubFormDecorators($subForm)
  325. ->addSubmitButton($subForm)
  326. ->addSubFormActions($subForm);
  327. return $subForm;
  328. }
  329. /**
  330. * Form Dekoratore zu einer individuellen Subform hinzufügen
  331. *
  332. * @param Zend_Form_SubForm $subForm
  333. * @return My_Form_Registration
  334. */
  335. public function setSubFormDecorators(Zend_Form_SubForm $subForm)
  336. {
  337. $subForm->setDecorators(array(
  338. 'FormElements',
  339. array('HtmlTag', array('tag' => 'dl',
  340. 'class' => 'zend_form')),
  341. 'Form',
  342. ));
  343. return $this;
  344. }
  345. /**
  346. * Einen Sendebutton in einer individuellen Subform hinzufügen
  347. *
  348. * @param Zend_Form_SubForm $subForm
  349. * @return My_Form_Registration
  350. */
  351. public function addSubmitButton(Zend_Form_SubForm $subForm)
  352. {
  353. $subForm->addElement(new Zend_Form_Element_Submit(
  354. 'save',
  355. array(
  356. 'label' => 'Speichern und Fortfahren',
  357. 'required' => false,
  358. 'ignore' => true,
  359. )
  360. ));
  361. return $this;
  362. }
  363. /**
  364. * Aktion und Methode der Subform hinzufügen
  365. *
  366. * @param Zend_Form_SubForm $subForm
  367. * @return My_Form_Registration
  368. */
  369. public function addSubFormActions(Zend_Form_SubForm $subForm)
  370. {
  371. $subForm->setAction('/registration/process')
  372. ->setMethod('post');
  373. return $this;
  374. }
  375. }
  376. ]]></programlisting>
  377. <para>
  378. Als nächstes benötigen wir das Grundgerüst für unseren Action Controller, und wir
  379. haben verschiedene Entscheidungen zu treffen. Zuerst müssen wir sicherstellen, dass
  380. die Formulardaten zwischen den Anfragen fixiert werden, sodass wir feststellen
  381. können wann abgebrochen wird. Zweitens wird etwas Logik benötigt, um festzustellen
  382. welche Formularteile bereits übermittelt wurden und welches Unterformular, basierend
  383. auf dieser Information, angezeigt werden soll. Wir verwenden
  384. <classname>Zend_Session_Namespace</classname> um Daten zu fixieren, was uns auch
  385. hilft die Frage zu beantworten welches Formular zu übertragen ist.
  386. </para>
  387. <para>
  388. Erstellen wir also unseren Controller, und fügen eine Methode für den Empfang der
  389. Formular Instanz hinzu:
  390. </para>
  391. <programlisting language="php"><![CDATA[
  392. class RegistrationController extends Zend_Controller_Action
  393. {
  394. protected $_form;
  395. public function getForm()
  396. {
  397. if (null === $this->_form) {
  398. $this->_form = new My_Form_Registration();
  399. }
  400. return $this->_form;
  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 language="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. ]]></programlisting>
  493. <para>
  494. Die obigen Methoden erlauben uns eine Schreibweise wie
  495. <command>$subForm = $this-&gt;getCurrentSubForm();</command> um das aktuelle
  496. Unterformular für die Prüfung zu erhalten, oder
  497. <command>$next = $this-&gt;getNextSubForm();</command>, um die nächste anzuzeigen.
  498. </para>
  499. <para>
  500. Sehen wir uns nun an, wie die verschiedenen Unterformulare bearbeitet und angezeigt
  501. werden können. Wir können <methodname>getCurrentSubForm()</methodname> verwenden um
  502. herauszufinden ob ein Unterformular übertragen wurde (<constant>FALSE</constant>
  503. Rückgabewerte zeigen an, dass keine angezeigt oder übertragen wurden) und
  504. <methodname>getNextSubForm()</methodname> empfängt die Form die angezeigt werden
  505. soll. Wir können die <methodname>prepareSubForm()</methodname> Methode des
  506. Formulars verwenden, um sicherzustellen, dass das Formular bereit zur Anzeige ist.
  507. </para>
  508. <para>
  509. Wenn ein Formular übertragen wird, kann das Unterformular bestätigt werden, und dann
  510. kann geprüft werden, ob das komplette Formular gültig ist. Um diese Arbeiten
  511. durchzuführen werden zusätzliche Methoden benötigt die sicherstellen, dass die
  512. übermittelten Daten der Session hinzugefügt werden, und, dass, wenn das komplette
  513. Formular geprüft wird, die Prüfung gegen alle Teile der Session durchgeführt wird:
  514. </para>
  515. <programlisting language="php"><![CDATA[
  516. class RegistrationController extends Zend_Form
  517. {
  518. // ...
  519. /**
  520. * Ist die Form gültig?
  521. *
  522. * @param Zend_Form_SubForm $subForm
  523. * @param array $data
  524. * @return bool
  525. */
  526. public function subFormIsValid(Zend_Form_SubForm $subForm,
  527. array $data)
  528. {
  529. $name = $subForm->getName();
  530. if ($subForm->isValid($data)) {
  531. $this->getSessionNamespace()->$name = $subForm->getValues();
  532. return true;
  533. }
  534. return false;
  535. }
  536. /**
  537. * Ist die komplette Form gültig?
  538. *
  539. * @return bool
  540. */
  541. public function formIsValid()
  542. {
  543. $data = array();
  544. foreach ($this->getSessionNamespace() as $key => $info) {
  545. $data[$key] = $info;
  546. }
  547. return $this->getForm()->isValid($data);
  548. }
  549. }
  550. ]]></programlisting>
  551. <para>
  552. Jetzt, da die Kleinarbeiten aus dem Weg sind, können die Aktionen für diesen
  553. Controller erstellt werden. Es wird eine Grundseite für das Formular und dann
  554. eine 'process' (Bearbeiten) Aktion für die Bearbeitung des Formulars benötigt.
  555. </para>
  556. <programlisting language="php"><![CDATA[
  557. class RegistrationController extends Zend_Controller_Action
  558. {
  559. // ...
  560. public function indexAction()
  561. {
  562. // Entweder die aktuelle Seite nochmals anzeigen, oder
  563. // die nächste "next" (erste) Subform holen
  564. if (!$form = $this->getCurrentSubForm()) {
  565. $form = $this->getNextSubForm();
  566. }
  567. $this->view->form = $this->getForm()->prepareSubForm($form);
  568. }
  569. public function processAction()
  570. {
  571. if (!$form = $this->getCurrentSubForm()) {
  572. return $this->_forward('index');
  573. }
  574. if (!$this->subFormIsValid($form,
  575. $this->getRequest()->getPost())) {
  576. $this->view->form = $this->getForm()->prepareSubForm($form);
  577. return $this->render('index');
  578. }
  579. if (!$this->formIsValid()) {
  580. $form = $this->getNextSubForm();
  581. $this->view->form = $this->getForm()->prepareSubForm($form);
  582. return $this->render('index');
  583. }
  584. // Gültige Form!
  585. // Information in einer Prüfseite darstellen
  586. $this->view->info = $this->getSessionNamespace();
  587. $this->render('verification');
  588. }
  589. }
  590. ]]></programlisting>
  591. <para>
  592. Wie festzustellen ist, ist der aktuelle Code für die Bearbeitung des Formulars
  593. relativ einfach. Wir prüfen, um zu sehen ob wir eine aktuelle Übertragung eines
  594. Unterformulars haben, oder nicht, und wir versuchen sie zu prüfen, und sie nochmals
  595. darzustellen wenn es fehlschlägt. Wenn das Unterformular gültig ist, muss
  596. anschließend geprüft werden, ob das Formular gültig ist, was dann bedeuten würde,
  597. dass wir fertig sind; wen nicht muss das nächste Formularsegment angezeigt werden.
  598. Letztendlich wird eine Prüfseite mit dem Inhalt der Session angezeigt.
  599. </para>
  600. <para>
  601. Die View Skripte sind sehr einfach:
  602. </para>
  603. <programlisting language="php"><![CDATA[
  604. <?php // registration/index.phtml ?>
  605. <h2>Registration</h2>
  606. <?php echo $this->form ?>
  607. <?php // registration/verification.phtml ?>
  608. <h2>Danke für die Registrierung!</h2>
  609. <p>
  610. Hier sind die angegebenen Informationen:
  611. </p>
  612. <?
  613. // Dieses Konstrukt muß getan werden wegen dem Weg wie Elemente
  614. // im Session Namespace gespeichert werden
  615. foreach ($this->info as $info):
  616. foreach ($info as $form => $data): ?>
  617. <h4><?php echo ucfirst($form) ?>:</h4>
  618. <dl>
  619. <?php foreach ($data as $key => $value): ?>
  620. <dt><?php echo ucfirst($key) ?></dt>
  621. <?php if (is_array($value)):
  622. foreach ($value as $label => $val): ?>
  623. <dd><?php echo $val ?></dd>
  624. <?php endforeach;
  625. else: ?>
  626. <dd><?php echo $this->escape($value) ?></dd>
  627. <?php endif;
  628. endforeach; ?>
  629. </dl>
  630. <?php endforeach;
  631. endforeach ?>
  632. ]]></programlisting>
  633. <para>
  634. Kommende Releases des Zend Frameworks werden Komponenten enthalten die
  635. mehrseitige Formulare einfacher machen - durch die Abstraktion der Session
  636. und der Reihungslogik. In der Zwischenzeit sollte das obige Beispiel als
  637. angemessene Grundlage dienen, wie diese Aufgabe für eigene Seiten realisiert
  638. werden kann.
  639. </para>
  640. </example>
  641. </sect2>
  642. </sect1>