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