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:
130: public function render(NForm $form, $mode = NULL)
131: {
132: if ($this->form !== $form) {
133: $this->form = $form;
134: $this->init();
135: }
136:
137: $s = '';
138: if (!$mode || $mode === 'begin') {
139: $s .= $this->renderBegin();
140: }
141: if ((!$mode && $this->getValue('form errors')) || $mode === 'errors') {
142: $s .= $this->renderErrors();
143: }
144: if (!$mode || $mode === 'body') {
145: $s .= $this->renderBody();
146: }
147: if (!$mode || $mode === 'end') {
148: $s .= $this->renderEnd();
149: }
150: return $s;
151: }
152:
153:
154:
155:
156: public function setClientScript()
157: {
158: trigger_error(__METHOD__ . '() is deprecated; use unobstructive JavaScript instead.', E_USER_WARNING);
159: return $this;
160: }
161:
162:
163:
164: 165: 166: 167:
168: protected function init()
169: {
170:
171: $wrapper = & $this->wrappers['control'];
172: foreach ($this->form->getControls() as $control) {
173: if ($control->isRequired() && isset($wrapper['.required'])) {
174: $control->getLabelPrototype()->class($wrapper['.required'], TRUE);
175: }
176:
177: $el = $control->getControlPrototype();
178: if ($el->getName() === 'input' && isset($wrapper['.' . $el->type])) {
179: $el->class($wrapper['.' . $el->type], TRUE);
180: }
181: }
182: }
183:
184:
185:
186: 187: 188: 189:
190: public function renderBegin()
191: {
192: $this->counter = 0;
193:
194: foreach ($this->form->getControls() as $control) {
195: $control->setOption('rendered', FALSE);
196: }
197:
198: if (strcasecmp($this->form->getMethod(), 'get') === 0) {
199: $el = clone $this->form->getElementPrototype();
200: $url = explode('?', (string) $el->action, 2);
201: $el->action = $url[0];
202: $s = '';
203: if (isset($url[1])) {
204: foreach (preg_split('#[;&]#', $url[1]) as $param) {
205: $parts = explode('=', $param, 2);
206: $name = urldecode($parts[0]);
207: if (!isset($this->form[$name])) {
208: $s .= NHtml::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
209: }
210: }
211: $s = "\n\t" . $this->getWrapper('hidden container')->setHtml($s);
212: }
213: return $el->startTag() . $s;
214:
215:
216: } else {
217: return $this->form->getElementPrototype()->startTag();
218: }
219: }
220:
221:
222:
223: 224: 225: 226:
227: public function renderEnd()
228: {
229: $s = '';
230: foreach ($this->form->getControls() as $control) {
231: if ($control instanceof NHiddenField && !$control->getOption('rendered')) {
232: $s .= (string) $control->getControl();
233: }
234: }
235: if (iterator_count($this->form->getComponents(TRUE, 'NTextInput')) < 2) {
236: $s .= '<!--[if IE]><input type=IEbug disabled style="display:none"><![endif]-->';
237: }
238: if ($s) {
239: $s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
240: }
241:
242: return $s . $this->form->getElementPrototype()->endTag() . "\n";
243: }
244:
245:
246:
247: 248: 249: 250:
251: public function renderErrors(IFormControl $control = NULL)
252: {
253: $errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
254: if (count($errors)) {
255: $ul = $this->getWrapper('error container');
256: $li = $this->getWrapper('error item');
257:
258: foreach ($errors as $error) {
259: $item = clone $li;
260: if ($error instanceof NHtml) {
261: $item->add($error);
262: } else {
263: $item->setText($error);
264: }
265: $ul->add($item);
266: }
267: return "\n" . $ul->render(0);
268: }
269: }
270:
271:
272:
273: 274: 275: 276:
277: public function renderBody()
278: {
279: $s = $remains = '';
280:
281: $defaultContainer = $this->getWrapper('group container');
282: $translator = $this->form->getTranslator();
283:
284: foreach ($this->form->getGroups() as $group) {
285: if (!$group->getControls() || !$group->getOption('visual')) {
286: continue;
287: }
288:
289: $container = $group->getOption('container', $defaultContainer);
290: $container = $container instanceof NHtml ? clone $container : NHtml::el($container);
291:
292: $s .= "\n" . $container->startTag();
293:
294: $text = $group->getOption('label');
295: if ($text instanceof NHtml) {
296: $s .= $text;
297:
298: } elseif (is_string($text)) {
299: if ($translator !== NULL) {
300: $text = $translator->translate($text);
301: }
302: $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
303: }
304:
305: $text = $group->getOption('description');
306: if ($text instanceof NHtml) {
307: $s .= $text;
308:
309: } elseif (is_string($text)) {
310: if ($translator !== NULL) {
311: $text = $translator->translate($text);
312: }
313: $s .= $this->getWrapper('group description')->setText($text) . "\n";
314: }
315:
316: $s .= $this->renderControls($group);
317:
318: $remains = $container->endTag() . "\n" . $remains;
319: if (!$group->getOption('embedNext')) {
320: $s .= $remains;
321: $remains = '';
322: }
323: }
324:
325: $s .= $remains . $this->renderControls($this->form);
326:
327: $container = $this->getWrapper('form container');
328: $container->setHtml($s);
329: return $container->render(0);
330: }
331:
332:
333:
334: 335: 336: 337: 338:
339: public function renderControls($parent)
340: {
341: if (!($parent instanceof NFormContainer || $parent instanceof NFormGroup)) {
342: throw new InvalidArgumentException("Argument must be FormContainer or FormGroup instance.");
343: }
344:
345: $container = $this->getWrapper('controls container');
346:
347: $buttons = NULL;
348: foreach ($parent->getControls() as $control) {
349: if ($control->getOption('rendered') || $control instanceof NHiddenField || $control->getForm(FALSE) !== $this->form) {
350:
351:
352: } elseif ($control instanceof NButton) {
353: $buttons[] = $control;
354:
355: } else {
356: if ($buttons) {
357: $container->add($this->renderPairMulti($buttons));
358: $buttons = NULL;
359: }
360: $container->add($this->renderPair($control));
361: }
362: }
363:
364: if ($buttons) {
365: $container->add($this->renderPairMulti($buttons));
366: }
367:
368: $s = '';
369: if (count($container)) {
370: $s .= "\n" . $container . "\n";
371: }
372:
373: return $s;
374: }
375:
376:
377:
378: 379: 380: 381:
382: public function renderPair(IFormControl $control)
383: {
384: $pair = $this->getWrapper('pair container');
385: $pair->add($this->renderLabel($control));
386: $pair->add($this->renderControl($control));
387: $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
388: $pair->class($control->getOption('class'), TRUE);
389: if (++$this->counter % 2) {
390: $pair->class($this->getValue('pair .odd'), TRUE);
391: }
392: $pair->id = $control->getOption('id');
393: return $pair->render(0);
394: }
395:
396:
397:
398: 399: 400: 401: 402:
403: public function renderPairMulti(array $controls)
404: {
405: $s = array();
406: foreach ($controls as $control) {
407: if (!$control instanceof IFormControl) {
408: throw new InvalidArgumentException("Argument must be array of IFormControl instances.");
409: }
410: $s[] = (string) $control->getControl();
411: }
412: $pair = $this->getWrapper('pair container');
413: $pair->add($this->renderLabel($control));
414: $pair->add($this->getWrapper('control container')->setHtml(implode(" ", $s)));
415: return $pair->render(0);
416: }
417:
418:
419:
420: 421: 422: 423:
424: public function renderLabel(IFormControl $control)
425: {
426: $head = $this->getWrapper('label container');
427:
428: if ($control instanceof NCheckbox || $control instanceof NButton) {
429: return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? ' ' : '');
430:
431: } else {
432: $label = $control->getLabel();
433: $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
434: if ($label instanceof NHtml) {
435: $label->setHtml($label->getHtml() . $suffix);
436: $suffix = '';
437: }
438: return $head->setHtml((string) $label . $suffix);
439: }
440: }
441:
442:
443:
444: 445: 446: 447:
448: public function renderControl(IFormControl $control)
449: {
450: $body = $this->getWrapper('control container');
451: if ($this->counter % 2) {
452: $body->class($this->getValue('control .odd'), TRUE);
453: }
454:
455: $description = $control->getOption('description');
456: if ($description instanceof NHtml) {
457: $description = ' ' . $control->getOption('description');
458:
459: } elseif (is_string($description)) {
460: $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
461:
462: } else {
463: $description = '';
464: }
465:
466: if ($control->isRequired()) {
467: $description = $this->getValue('control requiredsuffix') . $description;
468: }
469:
470: if ($this->getValue('control errors')) {
471: $description .= $this->renderErrors($control);
472: }
473:
474: if ($control instanceof NCheckbox || $control instanceof NButton) {
475: return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
476:
477: } else {
478: return $body->setHtml((string) $control->getControl() . $description);
479: }
480: }
481:
482:
483:
484: 485: 486: 487:
488: protected function getWrapper($name)
489: {
490: $data = $this->getValue($name);
491: return $data instanceof NHtml ? clone $data : NHtml::el($data);
492: }
493:
494:
495:
496: 497: 498: 499:
500: protected function getValue($name)
501: {
502: $name = explode(' ', $name);
503: $data = & $this->wrappers[$name[0]][$name[1]];
504: return $data;
505: }
506:
507: }
508: