1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: class DefaultFormRenderer extends Object 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(Form $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 .= Html::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 HiddenField && !$control->getOption('rendered')) {
232: $s .= (string) $control->getControl();
233: }
234: }
235: if (iterator_count($this->form->getComponents(TRUE, 'TextInput')) < 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:
252: public function renderErrors(IFormControl $control = NULL)
253: {
254: $errors = $control === NULL ? $this->form->getErrors() : $control->getErrors();
255: if (count($errors)) {
256: $ul = $this->getWrapper('error container');
257: $li = $this->getWrapper('error item');
258:
259: foreach ($errors as $error) {
260: $item = clone $li;
261: if ($error instanceof Html) {
262: $item->add($error);
263: } else {
264: $item->setText($error);
265: }
266: $ul->add($item);
267: }
268: return "\n" . $ul->render(0);
269: }
270: }
271:
272:
273:
274: 275: 276: 277:
278: public function renderBody()
279: {
280: $s = $remains = '';
281:
282: $defaultContainer = $this->getWrapper('group container');
283: $translator = $this->form->getTranslator();
284:
285: foreach ($this->form->getGroups() as $group) {
286: if (!$group->getControls() || !$group->getOption('visual')) {
287: continue;
288: }
289:
290: $container = $group->getOption('container', $defaultContainer);
291: $container = $container instanceof Html ? clone $container : Html::el($container);
292:
293: $s .= "\n" . $container->startTag();
294:
295: $text = $group->getOption('label');
296: if ($text instanceof Html) {
297: $s .= $text;
298:
299: } elseif (is_string($text)) {
300: if ($translator !== NULL) {
301: $text = $translator->translate($text);
302: }
303: $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
304: }
305:
306: $text = $group->getOption('description');
307: if ($text instanceof Html) {
308: $s .= $text;
309:
310: } elseif (is_string($text)) {
311: if ($translator !== NULL) {
312: $text = $translator->translate($text);
313: }
314: $s .= $this->getWrapper('group description')->setText($text) . "\n";
315: }
316:
317: $s .= $this->renderControls($group);
318:
319: $remains = $container->endTag() . "\n" . $remains;
320: if (!$group->getOption('embedNext')) {
321: $s .= $remains;
322: $remains = '';
323: }
324: }
325:
326: $s .= $remains . $this->renderControls($this->form);
327:
328: $container = $this->getWrapper('form container');
329: $container->setHtml($s);
330: return $container->render(0);
331: }
332:
333:
334:
335: 336: 337: 338: 339:
340: public function renderControls($parent)
341: {
342: if (!($parent instanceof FormContainer || $parent instanceof FormGroup)) {
343: throw new InvalidArgumentException("Argument must be FormContainer or FormGroup instance.");
344: }
345:
346: $container = $this->getWrapper('controls container');
347:
348: $buttons = NULL;
349: foreach ($parent->getControls() as $control) {
350: if ($control->getOption('rendered') || $control instanceof HiddenField || $control->getForm(FALSE) !== $this->form) {
351:
352:
353: } elseif ($control instanceof Button) {
354: $buttons[] = $control;
355:
356: } else {
357: if ($buttons) {
358: $container->add($this->renderPairMulti($buttons));
359: $buttons = NULL;
360: }
361: $container->add($this->renderPair($control));
362: }
363: }
364:
365: if ($buttons) {
366: $container->add($this->renderPairMulti($buttons));
367: }
368:
369: $s = '';
370: if (count($container)) {
371: $s .= "\n" . $container . "\n";
372: }
373:
374: return $s;
375: }
376:
377:
378:
379: 380: 381: 382: 383:
384: public function renderPair(IFormControl $control)
385: {
386: $pair = $this->getWrapper('pair container');
387: $pair->add($this->renderLabel($control));
388: $pair->add($this->renderControl($control));
389: $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
390: $pair->class($control->getOption('class'), TRUE);
391: if (++$this->counter % 2) {
392: $pair->class($this->getValue('pair .odd'), TRUE);
393: }
394: $pair->id = $control->getOption('id');
395: return $pair->render(0);
396: }
397:
398:
399:
400: 401: 402: 403: 404:
405: public function renderPairMulti(array $controls)
406: {
407: $s = array();
408: foreach ($controls as $control) {
409: if (!$control instanceof IFormControl) {
410: throw new InvalidArgumentException("Argument must be array of IFormControl instances.");
411: }
412: $s[] = (string) $control->getControl();
413: }
414: $pair = $this->getWrapper('pair container');
415: $pair->add($this->renderLabel($control));
416: $pair->add($this->getWrapper('control container')->setHtml(implode(" ", $s)));
417: return $pair->render(0);
418: }
419:
420:
421:
422: 423: 424: 425: 426:
427: public function renderLabel(IFormControl $control)
428: {
429: $head = $this->getWrapper('label container');
430:
431: if ($control instanceof Checkbox || $control instanceof Button) {
432: return $head->setHtml(($head->getName() === 'td' || $head->getName() === 'th') ? ' ' : '');
433:
434: } else {
435: $label = $control->getLabel();
436: $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
437: if ($label instanceof Html) {
438: $label->setHtml($label->getHtml() . $suffix);
439: $suffix = '';
440: }
441: return $head->setHtml((string) $label . $suffix);
442: }
443: }
444:
445:
446:
447: 448: 449: 450: 451:
452: public function renderControl(IFormControl $control)
453: {
454: $body = $this->getWrapper('control container');
455: if ($this->counter % 2) {
456: $body->class($this->getValue('control .odd'), TRUE);
457: }
458:
459: $description = $control->getOption('description');
460: if ($description instanceof Html) {
461: $description = ' ' . $control->getOption('description');
462:
463: } elseif (is_string($description)) {
464: $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
465:
466: } else {
467: $description = '';
468: }
469:
470: if ($control->isRequired()) {
471: $description = $this->getValue('control requiredsuffix') . $description;
472: }
473:
474: if ($this->getValue('control errors')) {
475: $description .= $this->renderErrors($control);
476: }
477:
478: if ($control instanceof Checkbox || $control instanceof Button) {
479: return $body->setHtml((string) $control->getControl() . (string) $control->getLabel() . $description);
480:
481: } else {
482: return $body->setHtml((string) $control->getControl() . $description);
483: }
484: }
485:
486:
487:
488: 489: 490: 491:
492: protected function getWrapper($name)
493: {
494: $data = $this->getValue($name);
495: return $data instanceof Html ? clone $data : Html::el($data);
496: }
497:
498:
499:
500: 501: 502: 503:
504: protected function getValue($name)
505: {
506: $name = explode(' ', $name);
507: $data = & $this->wrappers[$name[0]][$name[1]];
508: return $data;
509: }
510:
511: }
512: