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