2
0

Zend_Form-Advanced.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 17987 -->
  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. <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><para>
  158. <methodname>Zend_Form::setElementsBelongTo($array)</methodname>: Durch
  159. Verwendung dieser Methode kann der Name eines Arrays spezifiziert werden dem
  160. alle Elemente des Formulars angehören. Der Name kann durch Verwendung der
  161. Zugriffsmethode <methodname>getElementsBelongTo()</methodname> 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
  167. <methodname>Zend_Form_Element::setBelongsTo()</methodname> Methode verwendet wird. Um
  168. herauszufinden welcher Wert gesetzt ist -- egal ob dieser explizit gesetzt wurde oder
  169. implzit über das Formular -- kann die Zugriffsmethode
  170. <methodname>getBelongsTo()</methodname> verwendet werden.
  171. </para>
  172. </sect2>
  173. <sect2 id="zend.form.advanced.multiPage">
  174. <title>Mehrseitige Formulare</title>
  175. <para>
  176. Aktuell werden mehrseitige Formulare nicht offiziell in <classname>Zend_Form</classname>
  177. unterstützt; trotzdem ist die meiste Unterstützung für deren Implementierung bereits
  178. vorhanden und kann mit etwas extra Code angepasst werden.
  179. </para>
  180. <para>
  181. Der Schlüssel in der Erstellung von mehrseitigen Formularen, ist die Anpassung von
  182. Unterformularen, aber der Anzeige, von nur einem Unterformular pro Seite. Das erlaubt
  183. es, ein einzelnes Unterformular auf einmal zu übertragen und diese zu prüfen, aber das
  184. Formular nicht zu bearbeiten bis alle weiteren Unterformulare komplett sind.
  185. </para>
  186. <example id="zend.form.advanced.multiPage.registration">
  187. <title>Beispiel: Anmeldeformular</title>
  188. <para>
  189. Verwenden wir also ein Anmeldeformular als Beispiel. Für unsere Zwecke wollen wir
  190. auf der ersten Seite einen gewünschten Benutzernamen und Passwort holen, dann die
  191. Metadaten des Benutzers -- das heißt Vorname, Familienname und Wohnort -- und
  192. letztendlich die Auswahl welcher Mailingliste, wenn überhaupt, der Benutzer
  193. angehören will.
  194. </para>
  195. <para>
  196. Erstellen wir als erstes unser, eigenes, Formular und definieren in diesem die
  197. verschiedenen Unterformulare:
  198. </para>
  199. <programlisting language="php"><![CDATA[
  200. class My_Form_Registration extends Zend_Form
  201. {
  202. public function init()
  203. {
  204. // Erstellt die Benutzer Subform: Benutzername und Passwort
  205. $user = new Zend_Form_SubForm();
  206. $user->addElements(array(
  207. new Zend_Form_Element_Text('username', array(
  208. 'required' => true,
  209. 'label' => 'Benutzername:',
  210. 'filters' => array('StringTrim', 'StringToLower'),
  211. 'validators' => array(
  212. 'Alnum',
  213. array('Regex',
  214. false,
  215. array('/^[a-z][a-z0-9]{2,}$/'))
  216. )
  217. )),
  218. new Zend_Form_Element_Password('password', array(
  219. 'required' => true,
  220. 'label' => 'Passwort:',
  221. 'filters' => array('StringTrim'),
  222. 'validators' => array(
  223. 'NotEmpty',
  224. array('StringLength', false, array(6))
  225. )
  226. )),
  227. ));
  228. // Erstellt die Demographische Subform: Vorname,
  229. // Familienname und Ort
  230. $demog = new Zend_Form_SubForm();
  231. $demog->addElements(array(
  232. new Zend_Form_Element_Text('givenName', array(
  233. 'required' => true,
  234. 'label' => 'Vorname (erster):',
  235. 'filters' => array('StringTrim'),
  236. 'validators' => array(
  237. array('Regex',
  238. false,
  239. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  240. )
  241. )),
  242. new Zend_Form_Element_Text('familyName', array(
  243. 'required' => true,
  244. 'label' => 'Familienname (letzter):',
  245. 'filters' => array('StringTrim'),
  246. 'validators' => array(
  247. array('Regex',
  248. false,
  249. array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
  250. )
  251. )),
  252. new Zend_Form_Element_Text('location', array(
  253. 'required' => true,
  254. 'label' => 'Der eigene Ort:',
  255. 'filters' => array('StringTrim'),
  256. 'validators' => array(
  257. array('StringLength', false, array(2))
  258. )
  259. )),
  260. ));
  261. // Erstellt die Mailinglisten Subform
  262. $listOptions = array(
  263. 'none' => 'keine Listen bitte',
  264. 'fw-general' => 'Zend Framework General Liste',
  265. 'fw-mvc' => 'Zend Framework MVC Liste',
  266. 'fw-auth' => 'Zend Framework Authentication und ACL Liste',
  267. 'fw-services' => 'Zend Framework Web Services Liste',
  268. );
  269. $lists = new Zend_Form_SubForm();
  270. $lists->addElements(array(
  271. new Zend_Form_Element_MultiCheckbox('subscriptions', array(
  272. 'label' =>
  273. 'Welche Liste wollen Sie erhalten?',
  274. 'multiOptions' => $listOptions,
  275. 'required' => true,
  276. 'filters' => array('StringTrim'),
  277. 'validators' => array(
  278. array('InArray',
  279. false,
  280. array(array_keys($listOptions)))
  281. )
  282. )),
  283. ));
  284. // Die Subformen der Hauptform anhängen
  285. $this->addSubForms(array(
  286. 'user' => $user,
  287. 'demog' => $demog,
  288. 'lists' => $lists
  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 language="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. ]]></programlisting>
  375. <para>
  376. Als nächstes benötigen wir das Grundgerüst für unseren Action Controller, und wir
  377. haben verschiedene Entscheidungen zu treffen. Zuerst müssen wir sicherstellen, dass
  378. die Formulardaten zwischen den Anfragen fixiert werden, sodass wir feststellen
  379. können wann abgebrochen wird. Zweitens wird etwas Logik benötigt, um festzustellen
  380. welche Formularteile bereits übermittelt wurden und welches Unterformular, basierend
  381. auf dieser Information, angezeigt werden soll. Wir verwenden
  382. <classname>Zend_Session_Namespace</classname> um Daten zu fixieren, was uns auch
  383. hilft die Frage zu beantworten welches Formular zu übertragen ist.
  384. </para>
  385. <para>
  386. Erstellen wir also unseren Controller, und fügen eine Methode für den Empfang der
  387. Formular Instanz hinzu:
  388. </para>
  389. <programlisting language="php"><![CDATA[
  390. class RegistrationController extends Zend_Controller_Action
  391. {
  392. protected $_form;
  393. public function getForm()
  394. {
  395. if (null === $this->_form) {
  396. $this->_form = new My_Form_Registration();
  397. }
  398. return $this->_form;
  399. }
  400. }
  401. ]]></programlisting>
  402. <para>
  403. Füllen wir unseren Controller nun um die Funktionalität, zu erkennen, welches
  404. Formular angezeigt werden soll. Grundsätzlich müssen wir, bis das komplette
  405. Formular als gültig angenommen wird, die Darstellung der Formularabschnitte
  406. weiterführen. Zusätzlich müssen wir sicherstellen, dass sie in einer bestimmten
  407. Reihenfolge sind: Benutzer, Zusätze und dann Listen. Wir können feststellen, ob
  408. Daten übertragen wurden, indem wir im Namensraum der Session nach speziellen
  409. Schlüssen suchen, die jedes Unterformular repräsentieren.
  410. </para>
  411. <programlisting language="php"><![CDATA[
  412. class RegistrationController extends Zend_Controller_Action
  413. {
  414. // ...
  415. protected $_namespace = 'RegistrationController';
  416. protected $_session;
  417. /**
  418. * Den Session Namespace erhalten den wir verwenden
  419. *
  420. * @return Zend_Session_Namespace
  421. */
  422. public function getSessionNamespace()
  423. {
  424. if (null === $this->_session) {
  425. $this->_session =
  426. new Zend_Session_Namespace($this->_namespace);
  427. }
  428. return $this->_session;
  429. }
  430. /**
  431. * Eine Liste von bereits in der Session gespeicherten Forms erhalten
  432. *
  433. * @return array
  434. */
  435. public function getStoredForms()
  436. {
  437. $stored = array();
  438. foreach ($this->getSessionNamespace() as $key => $value) {
  439. $stored[] = $key;
  440. }
  441. return $stored;
  442. }
  443. /**
  444. * Eine Liste aller vorhandenen Subforms erhalten
  445. *
  446. * @return array
  447. */
  448. public function getPotentialForms()
  449. {
  450. return array_keys($this->getForm()->getSubForms());
  451. }
  452. /**
  453. * Welche Subform wurde übermittelt?
  454. *
  455. * @return false|Zend_Form_SubForm
  456. */
  457. public function getCurrentSubForm()
  458. {
  459. $request = $this->getRequest();
  460. if (!$request->isPost()) {
  461. return false;
  462. }
  463. foreach ($this->getPotentialForms() as $name) {
  464. if ($data = $request->getPost($name, false)) {
  465. if (is_array($data)) {
  466. return $this->getForm()->getSubForm($name);
  467. break;
  468. }
  469. }
  470. }
  471. return false;
  472. }
  473. /**
  474. * Die nächste Suboform für die Anzeige erhalten
  475. *
  476. * @return Zend_Form_SubForm|false
  477. */
  478. public function getNextSubForm()
  479. {
  480. $storedForms = $this->getStoredForms();
  481. $potentialForms = $this->getPotentialForms();
  482. foreach ($potentialForms as $name) {
  483. if (!in_array($name, $storedForms)) {
  484. return $this->getForm()->getSubForm($name);
  485. }
  486. }
  487. return false;
  488. }
  489. }
  490. ]]></programlisting>
  491. <para>
  492. Die obigen Methoden erlauben uns eine Schreibweise wie
  493. <command>$subForm = $this-&gt;getCurrentSubForm();</command> um das aktuelle
  494. Unterformular für die Prüfung zu erhalten, oder
  495. <command>$next = $this-&gt;getNextSubForm();</command>, um die nächste anzuzeigen.
  496. </para>
  497. <para>
  498. Sehen wir uns nun an, wie die verschiedenen Unterformulare bearbeitet und angezeigt
  499. werden können. Wir können <methodname>getCurrentSubForm()</methodname> verwenden um
  500. herauszufinden ob ein Unterformular übertragen wurde (<constant>FALSE</constant>
  501. Rückgabewerte zeigen an, dass keine angezeigt oder übertragen wurden) und
  502. <methodname>getNextSubForm()</methodname> empfängt die Form die angezeigt werden
  503. soll. Wir können die <methodname>prepareSubForm()</methodname> Methode des
  504. Formulars verwenden, um sicherzustellen, dass das Formular bereit zur Anzeige ist.
  505. </para>
  506. <para>
  507. Wenn ein Formular übertragen wird, kann das Unterformular bestätigt werden, und dann
  508. kann geprüft werden, ob das komplette Formular gültig ist. Um diese Arbeiten
  509. durchzuführen werden zusätzliche Methoden benötigt die sicherstellen, dass die
  510. übermittelten Daten der Session hinzugefügt werden, und, dass, wenn das komplette
  511. Formular geprüft wird, die Prüfung gegen alle Teile der Session durchgeführt wird:
  512. </para>
  513. <programlisting language="php"><![CDATA[
  514. class RegistrationController extends Zend_Form
  515. {
  516. // ...
  517. /**
  518. * Ist die Form gültig?
  519. *
  520. * @param Zend_Form_SubForm $subForm
  521. * @param array $data
  522. * @return bool
  523. */
  524. public function subFormIsValid(Zend_Form_SubForm $subForm,
  525. array $data)
  526. {
  527. $name = $subForm->getName();
  528. if ($subForm->isValid($data)) {
  529. $this->getSessionNamespace()->$name = $subForm->getValues();
  530. return true;
  531. }
  532. return false;
  533. }
  534. /**
  535. * Ist die komplette Form gültig?
  536. *
  537. * @return bool
  538. */
  539. public function formIsValid()
  540. {
  541. $data = array();
  542. foreach ($this->getSessionNamespace() as $key => $info) {
  543. $data[$key] = $info;
  544. }
  545. return $this->getForm()->isValid($data);
  546. }
  547. }
  548. ]]></programlisting>
  549. <para>
  550. Jetzt, da die Kleinarbeiten aus dem Weg sind, können die Aktionen für diesen
  551. Controller erstellt werden. Es wird eine Grundseite für das Formular und dann
  552. eine 'process' (Bearbeiten) Aktion für die Bearbeitung des Formulars benötigt.
  553. </para>
  554. <programlisting language="php"><![CDATA[
  555. class RegistrationController extends Zend_Controller_Action
  556. {
  557. // ...
  558. public function indexAction()
  559. {
  560. // Entweder die aktuelle Seite nochmals anzeigen, oder
  561. // die nächste "next" (erste) Subform holen
  562. if (!$form = $this->getCurrentSubForm()) {
  563. $form = $this->getNextSubForm();
  564. }
  565. $this->view->form = $this->getForm()->prepareSubForm($form);
  566. }
  567. public function processAction()
  568. {
  569. if (!$form = $this->getCurrentSubForm()) {
  570. return $this->_forward('index');
  571. }
  572. if (!$this->subFormIsValid($form,
  573. $this->getRequest()->getPost())) {
  574. $this->view->form = $this->getForm()->prepareSubForm($form);
  575. return $this->render('index');
  576. }
  577. if (!$this->formIsValid()) {
  578. $form = $this->getNextSubForm();
  579. $this->view->form = $this->getForm()->prepareSubForm($form);
  580. return $this->render('index');
  581. }
  582. // Gültige Form!
  583. // Information in einer Prüfseite darstellen
  584. $this->view->info = $this->getSessionNamespace();
  585. $this->render('verification');
  586. }
  587. }
  588. ]]></programlisting>
  589. <para>
  590. Wie festzustellen ist, ist der aktuelle Code für die Bearbeitung des Formulars
  591. relativ einfach. Wir prüfen, um zu sehen ob wir eine aktuelle Übertragung eines
  592. Unterformulars haben, oder nicht, und wir versuchen sie zu prüfen, und sie nochmals
  593. darzustellen wenn es fehlschlägt. Wenn das Unterformular gültig ist, muss
  594. anschließend geprüft werden, ob das Formular gültig ist, was dann bedeuten würde,
  595. dass wir fertig sind; wen nicht muss das nächste Formularsegment angezeigt werden.
  596. Letztendlich wird eine Prüfseite mit dem Inhalt der Session angezeigt.
  597. </para>
  598. <para>
  599. Die View Skripte sind sehr einfach:
  600. </para>
  601. <programlisting language="php"><![CDATA[
  602. <?php // registration/index.phtml ?>
  603. <h2>Registration</h2>
  604. <?php echo $this->form ?>
  605. <?php // registration/verification.phtml ?>
  606. <h2>Danke für die Registrierung!</h2>
  607. <p>
  608. Hier sind die angegebenen Informationen:
  609. </p>
  610. <?
  611. // Dieses Konstrukt muß getan werden wegen dem Weg wie Elemente
  612. // im Session Namespace gespeichert werden
  613. foreach ($this->info as $info):
  614. foreach ($info as $form => $data): ?>
  615. <h4><?php echo ucfirst($form) ?>:</h4>
  616. <dl>
  617. <?php foreach ($data as $key => $value): ?>
  618. <dt><?php echo ucfirst($key) ?></dt>
  619. <?php if (is_array($value)):
  620. foreach ($value as $label => $val): ?>
  621. <dd><?php echo $val ?></dd>
  622. <?php endforeach;
  623. else: ?>
  624. <dd><?php echo $this->escape($value) ?></dd>
  625. <?php endif;
  626. endforeach; ?>
  627. </dl>
  628. <?php endforeach;
  629. endforeach ?>
  630. ]]></programlisting>
  631. <para>
  632. Kommende Releases des Zend Frameworks werden Komponenten enthalten die
  633. mehrseitige Formulare einfacher machen - durch die Abstraktion der Session
  634. und der Reihungslogik. In der Zwischenzeit sollte das obige Beispiel als
  635. angemessene Grundlage dienen, wie diese Aufgabe für eigene Seiten realisiert
  636. werden kann.
  637. </para>
  638. </example>
  639. </sect2>
  640. </sect1>
  641. <!--
  642. vim:se ts=4 sw=4 et:
  643. -->