Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • DefaultFormRenderer
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Forms\Rendering
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * Converts a Form into the HTML output.
 17:  *
 18:  * @author     David Grudl
 19:  * @package Nette\Forms\Rendering
 20:  */
 21: class DefaultFormRenderer extends Object implements IFormRenderer
 22: {
 23:     /**
 24:      *  /--- form.container
 25:      *
 26:      *    /--- if (form.errors) error.container
 27:      *      .... error.item [.class]
 28:      *    \---
 29:      *
 30:      *    /--- hidden.container
 31:      *      .... HIDDEN CONTROLS
 32:      *    \---
 33:      *
 34:      *    /--- group.container
 35:      *      .... group.label
 36:      *      .... group.description
 37:      *
 38:      *      /--- controls.container
 39:      *
 40:      *        /--- pair.container [.required .optional .odd]
 41:      *
 42:      *          /--- label.container
 43:      *            .... LABEL
 44:      *            .... label.suffix
 45:      *            .... label.requiredsuffix
 46:      *          \---
 47:      *
 48:      *          /--- control.container [.odd]
 49:      *            .... CONTROL [.required .text .password .file .submit .button]
 50:      *            .... control.requiredsuffix
 51:      *            .... control.description
 52:      *            .... if (control.errors) error.container
 53:      *          \---
 54:      *        \---
 55:      *      \---
 56:      *    \---
 57:      *  \--
 58:      *
 59:      * @var array of HTML tags */
 60:     public $wrappers = array(
 61:         'form' => array(
 62:             'container' => NULL,
 63:             'errors' => TRUE,
 64:         ),
 65: 
 66:         'error' => array(
 67:             'container' => 'ul class=error',
 68:             'item' => 'li',
 69:         ),
 70: 
 71:         'group' => array(
 72:             'container' => 'fieldset',
 73:             'label' => 'legend',
 74:             'description' => 'p',
 75:         ),
 76: 
 77:         'controls' => array(
 78:             'container' => 'table',
 79:         ),
 80: 
 81:         'pair' => array(
 82:             'container' => 'tr',
 83:             '.required' => 'required',
 84:             '.optional' => NULL,
 85:             '.odd' => NULL,
 86:         ),
 87: 
 88:         'control' => array(
 89:             'container' => 'td',
 90:             '.odd' => NULL,
 91: 
 92:             'errors' => FALSE,
 93:             'description' => 'small',
 94:             'requiredsuffix' => '',
 95: 
 96:             '.required' => 'required',
 97:             '.text' => 'text',
 98:             '.password' => 'text',
 99:             '.file' => 'text',
100:             '.submit' => 'button',
101:             '.image' => 'imagebutton',
102:             '.button' => 'button',
103:         ),
104: 
105:         'label' => array(
106:             'container' => 'th',
107:             'suffix' => NULL,
108:             'requiredsuffix' => '',
109:         ),
110: 
111:         'hidden' => array(
112:             'container' => 'div',
113:         ),
114:     );
115: 
116:     /** @var Form */
117:     protected $form;
118: 
119:     /** @var int */
120:     protected $counter;
121: 
122: 
123:     /**
124:      * Provides complete form rendering.
125:      * @param  Form
126:      * @param  string 'begin', 'errors', 'body', 'end' or empty to render all
127:      * @return string
128:      */
129:     public function render(Form $form, $mode = NULL)
130:     {
131:         if ($this->form !== $form) {
132:             $this->form = $form;
133:             $this->init();
134:         }
135: 
136:         $s = '';
137:         if (!$mode || $mode === 'begin') {
138:             $s .= $this->renderBegin();
139:         }
140:         if ((!$mode && $this->getValue('form errors')) || $mode === 'errors') {
141:             $s .= $this->renderErrors();
142:         }
143:         if (!$mode || $mode === 'body') {
144:             $s .= $this->renderBody();
145:         }
146:         if (!$mode || $mode === 'end') {
147:             $s .= $this->renderEnd();
148:         }
149:         return $s;
150:     }
151: 
152: 
153:     /** @deprecated */
154:     public function setClientScript()
155:     {
156:         trigger_error(__METHOD__ . '() is deprecated; use unobstructive JavaScript instead.', E_USER_WARNING);
157:         return $this;
158:     }
159: 
160: 
161:     /**
162:      * Initializes form.
163:      * @return void
164:      */
165:     protected function init()
166:     {
167:         // TODO: only for back compatiblity - remove?
168:         $wrapper = & $this->wrappers['control'];
169:         foreach ($this->form->getControls() as $control) {
170:             if ($control->isRequired() && isset($wrapper['.required'])) {
171:                 $control->getLabelPrototype()->class($wrapper['.required'], TRUE);
172:             }
173: 
174:             $el = $control->getControlPrototype();
175:             if ($el->getName() === 'input' && isset($wrapper['.' . $el->type])) {
176:                 $el->class($wrapper['.' . $el->type], TRUE);
177:             }
178:         }
179:     }
180: 
181: 
182:     /**
183:      * Renders form begin.
184:      * @return string
185:      */
186:     public function renderBegin()
187:     {
188:         $this->counter = 0;
189: 
190:         foreach ($this->form->getControls() as $control) {
191:             $control->setOption('rendered', FALSE);
192:         }
193: 
194:         if (strcasecmp($this->form->getMethod(), 'get') === 0) {
195:             $el = clone $this->form->getElementPrototype();
196:             $url = explode('?', (string) $el->action, 2);
197:             $el->action = $url[0];
198:             $s = '';
199:             if (isset($url[1])) {
200:                 foreach (preg_split('#[;&]#', $url[1]) as $param) {
201:                     $parts = explode('=', $param, 2);
202:                     $name = urldecode($parts[0]);
203:                     if (!isset($this->form[$name])) {
204:                         $s .= Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
205:                     }
206:                 }
207:                 $s = "\n\t" . $this->getWrapper('hidden container')->setHtml($s);
208:             }
209:             return $el->startTag() . $s;
210: 
211: 
212:         } else {
213:             return $this->form->getElementPrototype()->startTag();
214:         }
215:     }
216: 
217: 
218:     /**
219:      * Renders form end.
220:      * @return string
221:      */
222:     public function renderEnd()
223:     {
224:         $s = '';
225:         foreach ($this->form->getControls() as $control) {
226:             if ($control instanceof HiddenField && !$control->getOption('rendered')) {
227:                 $s .= (string) $control->getControl();
228:             }
229:         }
230:         if (iterator_count($this->form->getComponents(TRUE, 'TextInput')) < 2) {
231:             $s .= '<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->';
232:         }
233:         if ($s) {
234:             $s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
235:         }
236: 
237:         return $s . $this->form->getElementPrototype()->endTag() . "\n";
238:     }
239: 
240: 
241:     /**
242:      * Renders validation errors (per form or per control).
243:      * @return string
244:      */
245:     public function renderErrors(IFormControl $control = NULL)
246:     {
247:         $errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
248:         if (count($errors)) {
249:             $ul = $this->getWrapper('error container');
250:             $li = $this->getWrapper('error item');
251: 
252:             foreach ($errors as $error) {
253:                 $item = clone $li;
254:                 if ($error instanceof Html) {
255:                     $item->add($error);
256:                 } else {
257:                     $item->setText($error);
258:                 }
259:                 $ul->add($item);
260:             }
261:             return "\n" . $ul->render(0);
262:         }
263:     }
264: 
265: 
266:     /**
267:      * Renders form body.
268:      * @return string
269:      */
270:     public function renderBody()
271:     {
272:         $s = $remains = '';
273: 
274:         $defaultContainer = $this->getWrapper('group container');
275:         $translator = $this->form->getTranslator();
276: 
277:         foreach ($this->form->getGroups() as $group) {
278:             if (!$group->getControls() || !$group->getOption('visual')) {
279:                 continue;
280:             }
281: 
282:             $container = $group->getOption('container', $defaultContainer);
283:             $container = $container instanceof Html ? clone $container : Html::el($container);
284: 
285:             $s .= "\n" . $container->startTag();
286: 
287:             $text = $group->getOption('label');
288:             if ($text instanceof Html) {
289:                 $s .= $text;
290: 
291:             } elseif (is_string($text)) {
292:                 if ($translator !== NULL) {
293:                     $text = $translator->translate($text);
294:                 }
295:                 $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
296:             }
297: 
298:             $text = $group->getOption('description');
299:             if ($text instanceof Html) {
300:                 $s .= $text;
301: 
302:             } elseif (is_string($text)) {
303:                 if ($translator !== NULL) {
304:                     $text = $translator->translate($text);
305:                 }
306:                 $s .= $this->getWrapper('group description')->setText($text) . "\n";
307:             }
308: 
309:             $s .= $this->renderControls($group);
310: 
311:             $remains = $container->endTag() . "\n" . $remains;
312:             if (!$group->getOption('embedNext')) {
313:                 $s .= $remains;
314:                 $remains = '';
315:             }
316:         }
317: 
318:         $s .= $remains . $this->renderControls($this->form);
319: 
320:         $container = $this->getWrapper('form container');
321:         $container->setHtml($s);
322:         return $container->render(0);
323:     }
324: 
325: 
326:     /**
327:      * Renders group of controls.
328:      * @param  FormContainer|FormGroup
329:      * @return string
330:      */
331:     public function renderControls($parent)
332:     {
333:         if (!($parent instanceof FormContainer || $parent instanceof FormGroup)) {
334:             throw new InvalidArgumentException("Argument must be FormContainer or FormGroup instance.");
335:         }
336: 
337:         $container = $this->getWrapper('controls container');
338: 
339:         $buttons = NULL;
340:         foreach ($parent->getControls() as $control) {
341:             if ($control->getOption('rendered') || $control instanceof HiddenField || $control->getForm(FALSE) !== $this->form) {
342:                 // skip
343: 
344:             } elseif ($control instanceof Button) {
345:                 $buttons[] = $control;
346: 
347:             } else {
348:                 if ($buttons) {
349:                     $container->add($this->renderPairMulti($buttons));
350:                     $buttons = NULL;
351:                 }
352:                 $container->add($this->renderPair($control));
353:             }
354:         }
355: 
356:         if ($buttons) {
357:             $container->add($this->renderPairMulti($buttons));
358:         }
359: 
360:         $s = '';
361:         if (count($container)) {
362:             $s .= "\n" . $container . "\n";
363:         }
364: 
365:         return $s;
366:     }
367: 
368: 
369:     /**
370:      * Renders single visual row.
371:      * @return string
372:      */
373:     public function renderPair(IFormControl $control)
374:     {
375:         $pair = $this->getWrapper('pair container');
376:         $pair->add($this->renderLabel($control));
377:         $pair->add($this->renderControl($control));
378:         $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
379:         $pair->class($control->getOption('class'), TRUE);
380:         if (++$this->counter % 2) {
381:             $pair->class($this->getValue('pair .odd'), TRUE);
382:         }
383:         $pair->id = $control->getOption('id');
384:         return $pair->render(0);
385:     }
386: 
387: 
388:     /**
389:      * Renders single visual row of multiple controls.
390:      * @param  IFormControl[]
391:      * @return string
392:      */
393:     public function renderPairMulti(array $controls)
394:     {
395:         $s = array();
396:         foreach ($controls as $control) {
397:             if (!$control instanceof IFormControl) {
398:                 throw new InvalidArgumentException("Argument must be array of IFormControl instances.");
399:             }
400:             $s[] = (string) $control->getControl();
401:         }
402:         $pair = $this->getWrapper('pair container');
403:         $pair->add($this->renderLabel($control));
404:         $pair->add($this->getWrapper('control container')->setHtml(implode(" ", $s)));
405:         return $pair->render(0);
406:     }
407: 
408: 
409:     /**
410:      * Renders 'label' part of visual row of controls.
411:      * @return string
412:      */
413:     public function renderLabel(IFormControl $control)
414:     {
415:         $head = $this->getWrapper('label container');
416: 
417:         if ($control instanceof Checkbox || $control instanceof Button) {
418:             return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? '&nbsp;' : '');
419: 
420:         } else {
421:             $label = $control->getLabel();
422:             $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
423:             if ($label instanceof Html) {
424:                 $label->setHtml($label->getHtml() . $suffix);
425:                 $suffix = '';
426:             }
427:             return $head->setHtml((string) $label . $suffix);
428:         }
429:     }
430: 
431: 
432:     /**
433:      * Renders 'control' part of visual row of controls.
434:      * @return string
435:      */
436:     public function renderControl(IFormControl $control)
437:     {
438:         $body = $this->getWrapper('control container');
439:         if ($this->counter % 2) {
440:             $body->class($this->getValue('control .odd'), TRUE);
441:         }
442: 
443:         $description = $control->getOption('description');
444:         if ($description instanceof Html) {
445:             $description = ' ' . $control->getOption('description');
446: 
447:         } elseif (is_string($description)) {
448:             $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
449: 
450:         } else {
451:             $description = '';
452:         }
453: 
454:         if ($control->isRequired()) {
455:             $description = $this->getValue('control requiredsuffix') . $description;
456:         }
457: 
458:         if ($this->getValue('control errors')) {
459:             $description .= $this->renderErrors($control);
460:         }
461: 
462:         if ($control instanceof Checkbox || $control instanceof Button) {
463:             return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
464: 
465:         } else {
466:             return $body->setHtml((string) $control->getControl() . $description);
467:         }
468:     }
469: 
470: 
471:     /**
472:      * @param  string
473:      * @return Html
474:      */
475:     protected function getWrapper($name)
476:     {
477:         $data = $this->getValue($name);
478:         return $data instanceof Html ? clone $data : Html::el($data);
479:     }
480: 
481: 
482:     /**
483:      * @param  string
484:      * @return string
485:      */
486:     protected function getValue($name)
487:     {
488:         $name = explode(' ', $name);
489:         $data = & $this->wrappers[$name[0]][$name[1]];
490:         return $data;
491:     }
492: 
493: }
494: 
Nette Framework 2.0.12 (for PHP 5.2, un-prefixed) API API documentation generated by ApiGen 2.8.0