1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: class NDefaultFormRenderer extends NObject implements IFormRenderer
22: {
23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
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:
117: protected $form;
118:
119:
120: protected $counter;
121:
122:
123: 124: 125: 126: 127: 128:
129: public function render(NForm $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:
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: 163: 164:
165: protected function init()
166: {
167:
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: 184: 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 .= NHtml::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: 220: 221:
222: public function renderEnd()
223: {
224: $s = '';
225: foreach ($this->form->getControls() as $control) {
226: if ($control instanceof NHiddenField && !$control->getOption('rendered')) {
227: $s .= (string) $control->getControl();
228: }
229: }
230: if (iterator_count($this->form->getComponents(TRUE, 'NTextInput')) < 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: 243: 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 NHtml) {
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: 268: 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 NHtml ? clone $container : NHtml::el($container);
284:
285: $s .= "\n" . $container->startTag();
286:
287: $text = $group->getOption('label');
288: if ($text instanceof NHtml) {
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 NHtml) {
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: 328: 329: 330:
331: public function renderControls($parent)
332: {
333: if (!($parent instanceof NFormContainer || $parent instanceof NFormGroup)) {
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 NHiddenField || $control->getForm(FALSE) !== $this->form) {
342:
343:
344: } elseif ($control instanceof NButton) {
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: 371: 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: 390: 391: 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: 411: 412:
413: public function renderLabel(IFormControl $control)
414: {
415: $head = $this->getWrapper('label container');
416:
417: if ($control instanceof NCheckbox || $control instanceof NButton) {
418: return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? ' ' : '');
419:
420: } else {
421: $label = $control->getLabel();
422: $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
423: if ($label instanceof NHtml) {
424: $label->setHtml($label->getHtml() . $suffix);
425: $suffix = '';
426: }
427: return $head->setHtml((string) $label . $suffix);
428: }
429: }
430:
431:
432: 433: 434: 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 NHtml) {
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 NCheckbox || $control instanceof NButton) {
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: 473: 474:
475: protected function getWrapper($name)
476: {
477: $data = $this->getValue($name);
478: return $data instanceof NHtml ? clone $data : NHtml::el($data);
479: }
480:
481:
482: 483: 484: 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: