1 <?php
2 /**
3 * @package FrameworkOnFramework
4 * @subpackage form
5 * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
6 * @license GNU General Public License version 2 or later; see LICENSE.txt
7 */
8 // Protect from unauthorized access
9 defined('FOF_INCLUDED') or die;
10
11 /**
12 * An interface for FOFFormHeader fields, used to define the filters and the
13 * elements of the header row in repeatable (browse) views
14 *
15 * @package FrameworkOnFramework
16 * @since 2.0
17 */
18 abstract class FOFFormHeader
19 {
20 /**
21 * The description text for the form field. Usually used in tooltips.
22 *
23 * @var string
24 * @since 2.0
25 */
26 protected $description;
27
28 /**
29 * The SimpleXMLElement object of the <field /> XML element that describes the header field.
30 *
31 * @var SimpleXMLElement
32 * @since 2.0
33 */
34 protected $element;
35
36 /**
37 * The FOFForm object of the form attached to the header field.
38 *
39 * @var FOFForm
40 * @since 2.0
41 */
42 protected $form;
43
44 /**
45 * The label for the header field.
46 *
47 * @var string
48 * @since 2.0
49 */
50 protected $label;
51
52 /**
53 * The header HTML.
54 *
55 * @var string|null
56 * @since 2.0
57 */
58 protected $header;
59
60 /**
61 * The filter HTML.
62 *
63 * @var string|null
64 * @since 2.0
65 */
66 protected $filter;
67
68 /**
69 * The buttons HTML.
70 *
71 * @var string|null
72 * @since 2.0
73 */
74 protected $buttons;
75
76 /**
77 * The options for a drop-down filter.
78 *
79 * @var array|null
80 * @since 2.0
81 */
82 protected $options;
83
84 /**
85 * The name of the form field.
86 *
87 * @var string
88 * @since 2.0
89 */
90 protected $name;
91
92 /**
93 * The name of the field.
94 *
95 * @var string
96 * @since 2.0
97 */
98 protected $fieldname;
99
100 /**
101 * The group of the field.
102 *
103 * @var string
104 * @since 2.0
105 */
106 protected $group;
107
108 /**
109 * The form field type.
110 *
111 * @var string
112 * @since 2.0
113 */
114 protected $type;
115
116 /**
117 * The value of the filter.
118 *
119 * @var mixed
120 * @since 2.0
121 */
122 protected $value;
123
124 /**
125 * The intended table data width (in pixels or percent).
126 *
127 * @var mixed
128 * @since 2.0
129 */
130 protected $tdwidth;
131
132 /**
133 * The key of the filter value in the model state.
134 *
135 * @var mixed
136 * @since 2.0
137 */
138 protected $filterSource;
139
140 /**
141 * Is this a sortable column?
142 *
143 * @var bool
144 * @since 2.0
145 */
146 protected $sortable = false;
147
148 /**
149 * Method to instantiate the form field object.
150 *
151 * @param FOFForm $form The form to attach to the form field object.
152 *
153 * @since 2.0
154 */
155 public function __construct(FOFForm $form = null)
156 {
157 // If there is a form passed into the constructor set the form and form control properties.
158 if ($form instanceof FOFForm)
159 {
160 $this->form = $form;
161 }
162 }
163
164 /**
165 * Method to get certain otherwise inaccessible properties from the form field object.
166 *
167 * @param string $name The property name for which to the the value.
168 *
169 * @return mixed The property value or null.
170 *
171 * @since 2.0
172 */
173 public function __get($name)
174 {
175 switch ($name)
176 {
177 case 'description':
178 case 'name':
179 case 'type':
180 case 'fieldname':
181 case 'group':
182 case 'tdwidth':
183 return $this->$name;
184 break;
185
186 case 'label':
187 if (empty($this->label))
188 {
189 $this->label = $this->getLabel();
190 }
191
192 return $this->label;
193
194 case 'value':
195 if (empty($this->value))
196 {
197 $this->value = $this->getValue();
198 }
199
200 return $this->value;
201 break;
202
203 case 'header':
204 if (empty($this->header))
205 {
206 $this->header = $this->getHeader();
207 }
208
209 return $this->header;
210 break;
211
212 case 'filter':
213 if (empty($this->filter))
214 {
215 $this->filter = $this->getFilter();
216 }
217
218 return $this->filter;
219 break;
220
221 case 'buttons':
222 if (empty($this->buttons))
223 {
224 $this->buttons = $this->getButtons();
225 }
226
227 return $this->buttons;
228 break;
229
230 case 'options':
231 if (empty($this->options))
232 {
233 $this->options = $this->getOptions();
234 }
235
236 return $this->options;
237 break;
238
239 case 'sortable':
240 if (empty($this->sortable))
241 {
242 $this->sortable = $this->getSortable();
243 }
244
245 return $this->sortable;
246 break;
247 }
248
249 return null;
250 }
251
252 /**
253 * Method to attach a JForm object to the field.
254 *
255 * @param FOFForm $form The JForm object to attach to the form field.
256 *
257 * @return FOFFormHeader The form field object so that the method can be used in a chain.
258 *
259 * @since 2.0
260 */
261 public function setForm(FOFForm $form)
262 {
263 $this->form = $form;
264
265 return $this;
266 }
267
268 /**
269 * Method to attach a FOFForm object to the field.
270 *
271 * @param SimpleXMLElement $element The SimpleXMLElement object representing the <field /> tag for the form field object.
272 * @param mixed $value The form field value to validate.
273 * @param string $group The field name group control value. This acts as an array container for the field.
274 * For example if the field has name="foo" and the group value is set to "bar" then the
275 * full field name would end up being "bar[foo]".
276 *
277 * @return boolean True on success.
278 *
279 * @since 2.0
280 */
281 public function setup(SimpleXMLElement $element, $value, $group = null)
282 {
283 // Make sure there is a valid JFormField XML element.
284 if ((string) $element->getName() != 'header')
285 {
286 return false;
287 }
288
289 // Reset the internal fields
290 $this->label = null;
291 $this->header = null;
292 $this->filter = null;
293 $this->buttons = null;
294 $this->options = null;
295 $this->value = null;
296 $this->filterSource = null;
297
298 // Set the XML element object.
299 $this->element = $element;
300
301 // Get some important attributes from the form field element.
302 $class = (string) $element['class'];
303 $id = (string) $element['id'];
304 $name = (string) $element['name'];
305 $filterSource = (string) $element['filter_source'];
306 $tdwidth = (string) $element['tdwidth'];
307
308 // Set the field description text.
309 $this->description = (string) $element['description'];
310
311 // Set the group of the field.
312 $this->group = $group;
313
314 // Set the td width of the field.
315 $this->tdwidth = $tdwidth;
316
317 // Set the field name and id.
318 $this->fieldname = $this->getFieldName($name);
319 $this->name = $this->getName($this->fieldname);
320 $this->id = $this->getId($id, $this->fieldname);
321 $this->filterSource = $this->getFilterSource($filterSource);
322
323 // Set the field default value.
324 $this->value = $this->getValue();
325
326 return true;
327 }
328
329 /**
330 * Method to get the id used for the field input tag.
331 *
332 * @param string $fieldId The field element id.
333 * @param string $fieldName The field element name.
334 *
335 * @return string The id to be used for the field input tag.
336 *
337 * @since 2.0
338 */
339 protected function getId($fieldId, $fieldName)
340 {
341 $id = '';
342
343 // If the field is in a group add the group control to the field id.
344
345 if ($this->group)
346 {
347 // If we already have an id segment add the group control as another level.
348
349 if ($id)
350 {
351 $id .= '_' . str_replace('.', '_', $this->group);
352 }
353 else
354 {
355 $id .= str_replace('.', '_', $this->group);
356 }
357 }
358
359 // If we already have an id segment add the field id/name as another level.
360
361 if ($id)
362 {
363 $id .= '_' . ($fieldId ? $fieldId : $fieldName);
364 }
365 else
366 {
367 $id .= ($fieldId ? $fieldId : $fieldName);
368 }
369
370 // Clean up any invalid characters.
371 $id = preg_replace('#\W#', '_', $id);
372
373 return $id;
374 }
375
376 /**
377 * Method to get the name used for the field input tag.
378 *
379 * @param string $fieldName The field element name.
380 *
381 * @return string The name to be used for the field input tag.
382 *
383 * @since 2.0
384 */
385 protected function getName($fieldName)
386 {
387 $name = '';
388
389 // If the field is in a group add the group control to the field name.
390
391 if ($this->group)
392 {
393 // If we already have a name segment add the group control as another level.
394 $groups = explode('.', $this->group);
395
396 if ($name)
397 {
398 foreach ($groups as $group)
399 {
400 $name .= '[' . $group . ']';
401 }
402 }
403 else
404 {
405 $name .= array_shift($groups);
406
407 foreach ($groups as $group)
408 {
409 $name .= '[' . $group . ']';
410 }
411 }
412 }
413
414 // If we already have a name segment add the field name as another level.
415
416 if ($name)
417 {
418 $name .= '[' . $fieldName . ']';
419 }
420 else
421 {
422 $name .= $fieldName;
423 }
424
425 return $name;
426 }
427
428 /**
429 * Method to get the field name used.
430 *
431 * @param string $fieldName The field element name.
432 *
433 * @return string The field name
434 *
435 * @since 2.0
436 */
437 protected function getFieldName($fieldName)
438 {
439 return $fieldName;
440 }
441
442 /**
443 * Method to get the field label.
444 *
445 * @return string The field label.
446 *
447 * @since 2.0
448 */
449 protected function getLabel()
450 {
451 // Get the label text from the XML element, defaulting to the element name.
452 $title = $this->element['label'] ? (string) $this->element['label'] : '';
453
454 if (empty($title))
455 {
456 $view = $this->form->getView();
457 $params = $view->getViewOptionAndName();
458 $title = $params['option'] . '_' .
459 FOFInflector::pluralize($params['view']) . '_FIELD_' .
460 (string) $this->element['name'];
461 $title = strtoupper($title);
462 $result = JText::_($title);
463
464 if ($result === $title)
465 {
466 $title = ucfirst((string) $this->element['name']);
467 }
468 }
469
470 return $title;
471 }
472
473 /**
474 * Get the filter value for this header field
475 *
476 * @return mixed The filter value
477 */
478 protected function getValue()
479 {
480 $model = $this->form->getModel();
481
482 return $model->getState($this->filterSource);
483 }
484
485 /**
486 * Return the key of the filter value in the model state or, if it's not set,
487 * the name of the field.
488 *
489 * @param string $filterSource The filter source value to return
490 *
491 * @return string
492 */
493 protected function getFilterSource($filterSource)
494 {
495 if ($filterSource)
496 {
497 return $filterSource;
498 }
499 else
500 {
501 return $this->name;
502 }
503 }
504
505 /**
506 * Is this a sortable field?
507 *
508 * @return boolean True if it's sortable
509 */
510 protected function getSortable()
511 {
512 $sortable = ($this->element['sortable'] != 'false');
513
514 if ($sortable)
515 {
516 if (empty($this->header))
517 {
518 $this->header = $this->getHeader();
519 }
520
521 $sortable = !empty($this->header);
522 }
523
524 return $sortable;
525 }
526
527 /**
528 * Returns the HTML for the header row, or null if this element should
529 * render no header element
530 *
531 * @return string|null HTML code or null if nothing is to be rendered
532 *
533 * @since 2.0
534 */
535 protected function getHeader()
536 {
537 return null;
538 }
539
540 /**
541 * Returns the HTML for a text filter to be rendered in the filter row,
542 * or null if this element should render no text input filter.
543 *
544 * @return string|null HTML code or null if nothing is to be rendered
545 *
546 * @since 2.0
547 */
548 protected function getFilter()
549 {
550 return null;
551 }
552
553 /**
554 * Returns the HTML for the buttons to be rendered in the filter row,
555 * next to the text input filter, or null if this element should render no
556 * text input filter buttons.
557 *
558 * @return string|null HTML code or null if nothing is to be rendered
559 *
560 * @since 2.0
561 */
562 protected function getButtons()
563 {
564 return null;
565 }
566
567 /**
568 * Returns the JHtml options for a drop-down filter. Do not include an
569 * empty option, it is added automatically.
570 *
571 * @return array The JHtml options for a drop-down filter
572 *
573 * @since 2.0
574 */
575 protected function getOptions()
576 {
577 return array();
578 }
579 }
580