PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / admin / helpers / vikappointments.php
vikappointments / admin / helpers Last commit date
html 2 days ago resources 2 days ago index.html 2 days ago vikappointments.php 2 days ago
vikappointments.php
1576 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Vikappointments back-end component helper.
16 *
17 * IMPORTANT: this class is automatically loaded by Joomla to invoke the prepareUpdate method
18 * while launching an update for this component. For this reason, since the autoloader hasn't
19 * been required, we MUST NOT autoload external files outside this class.
20 *
21 * @since 1.0
22 * @since 1.7.3 Renamed from AppointmentsHelper.
23 */
24 abstract class VikAppointmentsHelper
25 {
26 /**
27 * Displays the main menu of the component.
28 *
29 * @return void
30 *
31 * @see printFooter() it is needed to invoke also this method when the menu is displayed.
32 */
33 public static function printMenu()
34 {
35 $app = JFactory::getApplication();
36 $vik = VAPApplication::getInstance();
37
38 // load font awesome framework
39 JHtml::fetch('vaphtml.assets.fontawesome');
40
41 $task = self::getActiveView();
42 $auth = self::getAuthorisations();
43
44 $base_href = 'index.php?option=com_vikappointments';
45
46 // load menu factory
47 VAPLoader::import('libraries.menu.factory');
48
49 $board = MenuFactory::createMenu();
50
51 ///// DASHBOARD /////
52
53 if ($auth['dashboard']['numactives'] > 0)
54 {
55 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUDASHBOARD'), $base_href, $task == 'vikappointments');
56
57 $board->push($parent->setCustom('tachometer-alt'));
58 }
59
60 ///// MANAGEMENT /////
61
62 if ($auth['management']['numactives'] > 0)
63 {
64 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUTITLEHEADER1'));
65
66 if ($auth['management']['actions']['groups'])
67 {
68 $item = MenuFactory::createItem(JText::translate('VAPMENUGROUPS'), $base_href . '&view=groups', $task == 'groups');
69 $parent->addChild($item->setCustom('list'));
70 }
71
72 if ($auth['management']['actions']['employees'])
73 {
74 $item = MenuFactory::createItem(JText::translate('VAPMENUEMPLOYEES'), $base_href . '&view=employees', $task == 'employees');
75 $parent->addChild($item->setCustom('user-tie'));
76 }
77
78 if ($auth['management']['actions']['services'])
79 {
80 $item = MenuFactory::createItem(JText::translate('VAPMENUSERVICES'), $base_href . '&view=services', $task == 'services');
81 $parent->addChild($item->setCustom('flask'));
82 }
83
84 if ($auth['management']['actions']['options'])
85 {
86 $item = MenuFactory::createItem(JText::translate('VAPMENUOPTIONS'), $base_href . '&view=options', $task == 'options');
87 $parent->addChild($item->setCustom('tags'));
88 }
89
90 if ($auth['management']['actions']['locations'])
91 {
92 $item = MenuFactory::createItem(JText::translate('VAPMENULOCATIONS'), $base_href . '&view=locations', $task == 'locations');
93 $parent->addChild($item->setCustom('map-marker-alt'));
94 }
95
96 if ($auth['management']['actions']['packages'] && VikAppointments::isPackagesEnabled())
97 {
98 $item = MenuFactory::createItem(JText::translate('VAPMENUPACKAGES'), $base_href . '&view=packorders', $task == 'packorders');
99 $parent->addChild($item->setCustom('gift'));
100 }
101
102 $board->push($parent->setCustom('briefcase'));
103 }
104
105 ///// APPOINTMENTS /////
106
107 if ($auth['appointments']['numactives'] > 0)
108 {
109 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUTITLEHEADER2'));
110
111 if ($auth['appointments']['actions']['reservations'])
112 {
113 $item = MenuFactory::createItem(JText::translate('VAPMENURESERVATIONS'), $base_href . '&view=reservations', $task == 'reservations');
114 $parent->addChild($item->setCustom('shopping-basket'));
115 }
116
117 if ($auth['appointments']['actions']['waitinglist'] && VikAppointments::isWaitingList())
118 {
119 $item = MenuFactory::createItem(JText::translate('VAPCONFIGGLOBTITLE14'), $base_href . '&view=waitinglist', $task == 'waitinglist');
120 $parent->addChild($item->setCustom('hourglass-start'));
121 }
122
123 if ($auth['appointments']['actions']['customers'])
124 {
125 $item = MenuFactory::createItem(JText::translate('VAPMENUCUSTOMERS'), $base_href . '&view=customers', $task == 'customers');
126 $parent->addChild($item->setCustom('user'));
127 }
128
129 if ($auth['appointments']['actions']['coupons'])
130 {
131 $item = MenuFactory::createItem(JText::translate('VAPMENUCOUPONS'), $base_href . '&view=coupons', $task == 'coupons');
132 $parent->addChild($item->setCustom('gift'));
133 }
134
135 if ($auth['appointments']['actions']['calendar'])
136 {
137 // recover calendar layout from user state
138 $layout = $app->getUserState('vap.calendar.layout');
139
140 if (!$layout)
141 {
142 // recover calendar layout from database
143 $layout = VAPFactory::getConfig()->get('calendarlayout');
144 }
145
146 $item = MenuFactory::createItem(JText::translate('VAPMENUCALENDAR'), $base_href . '&view=' . $layout, $task == 'calendar');
147 $parent->addChild($item->setCustom('calendar-alt'));
148 }
149
150 $board->push($parent->setCustom('calendar'));
151 }
152
153 ///// PORTAL /////
154
155 if ($auth['portal']['numactives'] > 0)
156 {
157 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUTITLEHEADER4'));
158
159 if ($auth['portal']['actions']['countries'])
160 {
161 $item = MenuFactory::createItem(JText::translate('VAPMENUCOUNTRIES'), $base_href . '&view=countries', $task == 'countries');
162 $parent->addChild($item->setCustom('globe-americas'));
163 }
164
165 if ($auth['portal']['actions']['reviews'])
166 {
167 $item = MenuFactory::createItem(JText::translate('VAPMENUREVIEWS'), $base_href . '&view=reviews', $task == 'reviews');
168 $parent->addChild($item->setCustom('star'));
169 }
170
171 if ($auth['portal']['actions']['subscriptions'])
172 {
173 $item = MenuFactory::createItem(JText::translate('VAPMENUSUBSCRIPTIONS'), $base_href . '&view=subscriptions', $task == 'subscriptions');
174 $parent->addChild($item->setCustom('ticket-alt'));
175
176 $item = MenuFactory::createItem(JText::translate('VAPMENUSUBSCRIPTIONORDERS'), $base_href . '&view=subscrorders', $task == 'subscrorders');
177 $parent->addChild($item->setCustom('shopping-basket'));
178 }
179
180 $board->push($parent->setCustom('certificate'));
181 }
182
183 ///// ANALYTICS /////
184
185 if ($auth['analytics']['numactives'] > 0)
186 {
187 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUTITLEANALYTICS'));
188
189 if ($auth['analytics']['actions']['analytics.finance'])
190 {
191 $item = MenuFactory::createItem(JText::translate('VAPMENUFINANCE'), $base_href . '&view=analytics&location=finance', $task == 'analytics.finance');
192 $parent->addChild($item->setCustom('wallet'));
193 }
194
195 if ($auth['analytics']['actions']['analytics.appointments'])
196 {
197 $item = MenuFactory::createItem(JText::translate('VAPMENUTITLEHEADER2'), $base_href . '&view=analytics&location=appointments', $task == 'analytics.appointments');
198 $parent->addChild($item->setCustom('calendar-check'));
199 }
200
201 if ($auth['analytics']['actions']['analytics.services'])
202 {
203 $item = MenuFactory::createItem(JText::translate('VAPMENUSERVICES'), $base_href . '&view=analytics&location=services', $task == 'analytics.services');
204 $parent->addChild($item->setCustom('flask'));
205 }
206
207 if ($auth['analytics']['actions']['analytics.employees'])
208 {
209 $item = MenuFactory::createItem(JText::translate('VAPMENUEMPLOYEES'), $base_href . '&view=analytics&location=employees', $task == 'analytics.employees');
210 $parent->addChild($item->setCustom('user-tie'));
211 }
212
213 if ($auth['analytics']['actions']['analytics.options'])
214 {
215 $item = MenuFactory::createItem(JText::translate('VAPMENUOPTIONS'), $base_href . '&view=analytics&location=options', $task == 'analytics.options');
216 $parent->addChild($item->setCustom('tags'));
217 }
218
219 if ($auth['analytics']['actions']['analytics.customers'])
220 {
221 $item = MenuFactory::createItem(JText::translate('VAPMENUCUSTOMERS'), $base_href . '&view=analytics&location=customers', $task == 'analytics.customers');
222 $parent->addChild($item->setCustom('users'));
223 }
224
225 if ($auth['analytics']['actions']['analytics.packages'] && VikAppointments::isPackagesEnabled())
226 {
227 $item = MenuFactory::createItem(JText::translate('VAPMENUPACKAGES'), $base_href . '&view=analytics&location=packages', $task == 'analytics.packages');
228 $parent->addChild($item->setCustom('gift'));
229 }
230
231 // check whether the subscriptions are supported, otherwise avoid to display this section
232 VAPLoader::import('libraries.models.subscriptions');
233
234 if ($auth['analytics']['actions']['analytics.subscriptions'] && (VAPSubscriptions::has(0) || VAPSubscriptions::has(1)))
235 {
236 $item = MenuFactory::createItem(JText::translate('VAPMENUSUBSCRIPTIONS'), $base_href . '&view=analytics&location=subscriptions', $task == 'analytics.subscriptions');
237 $parent->addChild($item->setCustom('ticket-alt'));
238 }
239
240 $board->push($parent->setCustom('search-dollar'));
241 }
242
243 ///// GLOBAL /////
244
245 if ($auth['global']['numactives'] > 0)
246 {
247 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUTITLEHEADER3'));
248
249 if ($auth['global']['actions']['custfields'])
250 {
251 $item = MenuFactory::createItem(JText::translate('VAPMENUCUSTOMF'), $base_href . '&view=customf', $task == 'customf');
252 $parent->addChild($item->setCustom('font'));
253 }
254
255 if ($auth['global']['actions']['payments'])
256 {
257 $item = MenuFactory::createItem(JText::translate('VAPMENUPAYMENTS'), $base_href . '&view=payments', $task == 'payments');
258 $parent->addChild($item->setCustom('credit-card'));
259 }
260
261 if ($auth['global']['actions']['statuscodes'])
262 {
263 $item = MenuFactory::createItem(JText::translate('VAPMENUSTATUSCODES'), $base_href . '&view=statuscodes', $task == 'statuscodes');
264 $parent->addChild($item->setCustom('tags'));
265 }
266
267 if ($auth['global']['actions']['taxes'])
268 {
269 $item = MenuFactory::createItem(JText::translate('VAPMENUTAXES'), $base_href . '&view=taxes', $task == 'taxes');
270 $parent->addChild($item->setCustom('calculator'));
271 }
272
273 if ($auth['global']['actions']['archive'])
274 {
275 $item = MenuFactory::createItem(JText::translate('VAPMENUARCHIVE'), $base_href . '&view=invoices', $task == 'invoices');
276 $parent->addChild($item->setCustom('file-pdf'));
277 }
278
279 if ($auth['global']['actions']['media'])
280 {
281 $item = MenuFactory::createItem(JText::translate('VAPMENUMEDIA'), $base_href . '&view=media', $task == 'media');
282 $parent->addChild($item->setCustom('camera-retro'));
283 }
284
285 $board->push($parent->setCustom('layer-group'));
286 }
287
288 ///// CONFIGURATION /////
289
290 if ($auth['configuration']['numactives'] > 0)
291 {
292 $parent = MenuFactory::createSeparator(JText::translate('VAPMENUCONFIG'));
293
294 if ($auth['configuration']['actions']['config'])
295 {
296 $item = MenuFactory::createItem(JText::translate('VAPMENUTITLEHEADER3'), $base_href . '&view=editconfig', $task == 'editconfig');
297 $parent->addChild($item->setCustom('tools'));
298 }
299
300 if ($auth['configuration']['actions']['config'])
301 {
302 $item = MenuFactory::createItem(JText::translate('VAPCONFIGTABNAME2'), $base_href . '&view=editconfigemp', $task == 'editconfigemp');
303 $parent->addChild($item->setCustom('users'));
304 }
305
306 if ($auth['configuration']['actions']['config'] || $auth['configuration']['actions']['config.closures'])
307 {
308 $item = MenuFactory::createItem(JText::translate('VAPCONFIGTABNAME3'), $base_href . '&view=editconfigcldays', $task == 'editconfigcldays');
309 $parent->addChild($item->setCustom('calendar-times'));
310 }
311
312 if ($auth['configuration']['actions']['config'])
313 {
314 $item = MenuFactory::createItem(JText::translate('VAPCONFIGTABNAME4'), $base_href . '&view=editconfigsmsapi', $task == 'editconfigsmsapi');
315 $parent->addChild($item->setCustom('sms'));
316 }
317
318 if ($auth['configuration']['actions']['config'])
319 {
320 $item = MenuFactory::createItem(JText::translate('VAPCONFIGTABNAME5'), $base_href . '&view=editconfigcron', $task == 'editconfigcron');
321 $parent->addChild($item->setCustom('stopwatch'));
322 }
323
324 if ($auth['configuration']['actions']['config'])
325 {
326 $item = MenuFactory::createItem(JText::translate('VAPCONFIGTABNAME6'), $base_href . '&view=editconfigapp', $task == 'editconfigapp');
327 $parent->addChild($item->setCustom('plug'));
328 }
329
330 $board->push($parent->setCustom('cog'));
331 }
332
333 // CUSTOM
334 $line_separator = MenuFactory::createCustomItem('line');
335
336 // split
337 $board->push($line_separator);
338 $board->push(MenuFactory::createCustomItem('split'));
339
340 // check version
341 if ($auth['configuration']['numactives'] > 0)
342 {
343 /**
344 * Detect current platform and use the correct version button:
345 * - VikUpdater for Joomla
346 * - Go To PRO for WordPress
347 *
348 * @since 1.6.3
349 */
350 if (VersionListener::getPlatform() == 'joomla')
351 {
352 if ($task == 'vikappointments' || $task == 'editconfig')
353 {
354 $board->push($line_separator);
355 $board->push(MenuFactory::createCustomItem('version', self::getCheckVersionParams()));
356 }
357 }
358 else if (VersionListener::getPlatform() == 'wordpress')
359 {
360 // always display license button
361 $board->push(MenuFactory::createCustomItem('license'));
362 }
363 }
364
365 ///// BUILD MENU /////
366
367 /**
368 * Trigger event to allow the plugins to manipulate the back-end menu of VikAppointments.
369 *
370 * @param MenuShape &$menu The menu to build.
371 *
372 * @return void
373 *
374 * @since 1.6.3
375 */
376 VAPFactory::getEventDispatcher()->trigger('onBeforeBuildVikAppointmentsMenu', array(&$board));
377
378 echo $board->build();
379
380 /**
381 * Open body by using the specific menu handler.
382 *
383 * @since 1.6.3
384 */
385 echo $board->openBody();
386 }
387
388 /**
389 * Displays the footer of the component.
390 *
391 * @return void
392 *
393 * @see printMenu() it is needed to invoke also this method when the footer is displayed.
394 */
395 public static function printFooter()
396 {
397 /**
398 * Close body by using the specific menu handler.
399 *
400 * @since 1.6.3
401 */
402 echo MenuFactory::createMenu()->closeBody();
403
404 if (VAPFactory::getConfig()->getBool('showfooter'))
405 {
406 /**
407 * Find manufacturer name according to the platform in use.
408 * Display a link in the format [SHORT] - [LONG].
409 *
410 * @since 1.6.3
411 */
412 $manufacturer = VAPApplication::getInstance()
413 ->getManufacturer(array('link' => true, 'short' => true, 'long' => true));
414
415 ?>
416 <p id="vapfooter">
417 <?php echo JText::sprintf('VAPFOOTER', VIKAPPOINTMENTS_SOFTWARE_VERSION) . ' ' . $manufacturer; ?>
418 </p>
419 <?php
420 }
421 }
422
423 /**
424 * In case of missing view, fetches the first
425 * available one.
426 *
427 * @return string The name of the default view.
428 *
429 * @since 1.7
430 */
431 public static function getDefaultView()
432 {
433 // scan ACL table to find the very first allowed page
434 $acl = static::getAuthorisations();
435
436 // iterate sections
437 foreach ($acl as $section)
438 {
439 // iterates actions
440 foreach ($section['actions'] as $action => $status)
441 {
442 // make sure the view is accessible
443 if ($status)
444 {
445 // look for a specific view name
446 return isset($section['views'][$action]) ? $section['views'][$action] : $action;
447 }
448 }
449 }
450
451 // the user seems to be unable to access any views
452 return null;
453 }
454
455 /**
456 * Returns the parent to which the task belongs.
457 * For example, if we are visiting the states list,
458 * the parent will be "countries", as the states don't
459 * have a specific menu item.
460 *
461 * @param string $task The task to check.
462 * If empty, it will be taken from the request.
463 *
464 * @return void
465 */
466 public static function getParentTask($task = null)
467 {
468 $input = JFactory::getApplication()->input;
469
470 if (empty($task))
471 {
472 $task = 'vikappointments';
473 }
474
475 switch ($task)
476 {
477 case 'serworkdays':
478 case 'rates':
479 case 'restrictions':
480 $task = 'services';
481 break;
482
483 case 'emprates':
484 case 'emplocations':
485 $task = 'employees';
486 break;
487
488 case 'optiongroups':
489 $task = 'options';
490 break;
491
492 case 'packages':
493 case 'packgroups':
494 $task = 'packorders';
495 break;
496
497 case 'usernotes':
498 $task = 'customers';
499 break;
500
501 case 'states':
502 case 'cities':
503 $task = 'countries';
504 break;
505
506 case 'coupongroups':
507 $task = 'coupons';
508 break;
509
510 case 'caldays':
511 $task = 'calendar';
512 break;
513
514 case 'payments':
515 $task = $input->getBool('id_employee') ? 'employees' : 'payments';
516 break;
517
518 case 'analytics':
519 // append macro-group to analytics task
520 $task .= '.' . $input->get('location', 'unknown');
521 break;
522
523 case 'import':
524 case 'export':
525 // recursive search to make sure we select the correct parent
526 $task = $input->getString('import_type', '');
527 $task = self::getParentTask($task);
528 break;
529
530 case 'tags':
531 // recursive search to make sure we select the correct parent
532 $task = $input->getString('group', 'editconfig');
533 $task = self::getParentTask($task);
534 break;
535 }
536
537 return $task;
538 }
539
540 /**
541 * Returns the current active view.
542 * For example, if we are visiting the rooms closures,
543 * the active view will be "rooms", as the closures don't
544 * have a specific menu item.
545 *
546 * @return string The current active view.
547 *
548 * @since 1.7
549 */
550 public static function getActiveView()
551 {
552 $input = JFactory::getApplication()->input;
553
554 // get view/task from request
555 $view = $input->get('view', $input->get('task'));
556
557 if (empty($view))
558 {
559 // get default view
560 $view = static::getDefaultView();
561 }
562
563 return self::getParentTask($view);
564 }
565
566 /**
567 * Returns the arguments used to display a link to check the version.
568 *
569 * @return array
570 */
571 protected static function getCheckVersionParams()
572 {
573 $data = array(
574 'hn' => getenv('HTTP_HOST'),
575 'sn' => getenv('SERVER_NAME'),
576 'app' => 'com_vikappointments',
577 'ver' => VIKAPPOINTMENTS_SOFTWARE_VERSION,
578 );
579
580 return array(
581 'url' => 'https://extensionsforjoomla.com/vikcheck/vikupdater.php?' . http_build_query($data),
582 'label' => 'Check Updates',
583 );
584 }
585
586 /**
587 * Loads the base CSS and JS resources.
588 *
589 * @return void
590 */
591 public static function load_css_js()
592 {
593 $vik = VAPApplication::getInstance();
594
595 /**
596 * Load only jQuery framework provided by the CMS.
597 *
598 * @since 1.6.2
599 */
600 $vik->loadFramework('jquery.framework');
601
602 /**
603 * Do not load jQuery UI on Joomla 4.
604 *
605 * Restore jQuery UI loading on Joomla 4.1 and higher because the
606 * CMS definitively removed its support.
607 *
608 * @since 1.7
609 */
610 if (VersionListener::isJoomla40() === false)
611 {
612 $vik->addScript(VAPASSETS_URI . 'js/jquery-ui.min.js');
613 $vik->addStyleSheet(VAPASSETS_URI . 'css/jquery-ui.min.css');
614 }
615
616 $vik->addScript(VAPASSETS_URI . 'js/jquery-ui.sortable.min.js');
617 $vik->addScript(VAPASSETS_URI . 'js/jquery-ui.draggable.min.js');
618
619 $vik->addScript(VAPASSETS_ADMIN_URI . 'js/vikappointments.js');
620
621 $vik->addStyleSheet(VAPASSETS_ADMIN_URI . 'css/vikappointments.css');
622
623 // always include CSS for confirm dialog in back-end
624 $vik->addStyleSheet(VAPASSETS_URI . 'css/confirmdialog.css');
625
626 if (VersionListener::isJoomla3x())
627 {
628 $vik->addStyleSheet(VAPASSETS_ADMIN_URI . 'css/adapter/J30.css');
629 }
630 else if (VersionListener::isJoomla4x())
631 {
632 $vik->addScript(VAPASSETS_ADMIN_URI . 'js/adapter/J40.js');
633 $vik->addStyleSheet(VAPASSETS_ADMIN_URI . 'css/adapter/J40.css');
634
635 // register adapter scripts on DOM loaded
636 $app = JFactory::getApplication();
637 $app->getDocument()->addScriptDeclaration('jQuery(function($) { $(\'body\').addClass(\'com_vikappointments\'); __vikappointments_j40_adapter(); });');
638
639 if (VersionListener::isJoomla50())
640 {
641 if (VersionListener::isLowerThan('5.1'))
642 {
643 $vik->addStyleSheet(VAPASSETS_ADMIN_URI . 'css/adapter/J50.css');
644 }
645 else
646 {
647 $vik->addStyleSheet(VAPASSETS_ADMIN_URI . 'css/adapter/J51.css');
648 }
649 }
650 }
651
652 /**
653 * Loads utils.
654 *
655 * @since 1.7
656 */
657 JHtml::fetch('vaphtml.assets.utils');
658
659 /**
660 * Always instantiate the currency object.
661 *
662 * @since 1.7
663 */
664 JHtml::fetch('vaphtml.assets.currency');
665
666 /**
667 * Auto set CSRF token to ajaxSetup so all jQuery ajax call will contain CSRF token.
668 *
669 * @since 1.7
670 */
671 JHtml::fetch('vaphtml.sitescripts.ajaxcsrf');
672 }
673
674 /**
675 * Returns a list containing all the media files.
676 *
677 * @param mixed $order The type of ordering to use.
678 * @param mixed $thumbs True to obtain the thumbnails.
679 *
680 * @return array
681 *
682 * @uses getMediaFromPath()
683 */
684 public static function getAllMedia($order = false, $thumbs = false)
685 {
686 if ($thumbs)
687 {
688 $path = VAPMEDIA_SMALL;
689 }
690 else
691 {
692 $path = VAPMEDIA;
693 }
694
695 /**
696 * Ordering boolean flag is deprecated.
697 * Use the correct type instead.
698 *
699 * @deprecated 1.8
700 */
701 if ($order === true)
702 {
703 $order = 'creation';
704 }
705
706 return self::getMediaFromPath($path, $order);
707 }
708
709 /**
710 * Returns a list of images stored in the following folder.
711 *
712 * @param string $path The path from which the images should be loaded.
713 * @param mixed $order The type of ordering to use:
714 * - "name" natural ordering;
715 * - "date" creation date ordering;
716 * - "size" image size ordering;
717 * - "filesize" file size ordering;
718 * It is possible to pass an array with the first
719 * argument to indicate the ordering type and the
720 * second one for the ordering direction.
721 *
722 * @return array
723 *
724 * @since 1.7
725 */
726 public static function getMediaFromPath($path, $order = null)
727 {
728 // since certain server configurations may not support GLOB_BRACE mask,
729 // we need to filter the list manually
730 $arr = glob($path . DIRECTORY_SEPARATOR . '*');
731
732 // use media model to check what are the supported files
733 $model = JModelVAP::getInstance('media');
734
735 $arr = array_filter($arr, function($path) use ($model)
736 {
737 return $model->isFileAllowed($path);
738 });
739
740 if ($order)
741 {
742 // check whether the user requested an ordering direction
743 if (is_array($order))
744 {
745 list($order, $direction) = $order;
746 }
747 else
748 {
749 // fallback to default one
750 $direction = 'asc';
751 }
752
753 // fetch the type of ordering
754 usort($arr, function($a, $b) use ($order, $direction)
755 {
756 switch ($order)
757 {
758 case 'date':
759 // sort by creation date
760 $factor = filemtime($a) - filemtime($b);
761 break;
762
763 case 'filesize':
764 // sort by file size
765 $factor = filesize($a) - filesize($b);
766 break;
767
768 case 'size':
769 // sort by image size
770 $a_size = getimagesize($a);
771 $b_size = getimagesize($b);
772
773 $factor = $a_size[0] * $a_size[1] - $b_size[0] * $b_size[1];
774 break;
775
776 default:
777 // fallback to file name comparison
778 $factor = 0;
779 }
780
781 // in case of same creation date, sort files by name
782 if ($factor == 0)
783 {
784 $factor = strcmp($a, $b);
785
786 if ($order != 'name')
787 {
788 // always force ascending direction when
789 // using this ordering as fallback
790 $direction = 'asc';
791 }
792 }
793
794 // in case of descending direction, reverse the ordering factor
795 if (preg_match("/desc/i", $direction))
796 {
797 $factor *= -1;
798 }
799
800 return $factor;
801 });
802 }
803
804 return $arr;
805 }
806
807 /**
808 * Returns the list of the invoices related to the specified group.
809 *
810 * @param string $group The invoices group.
811 * @param boolean $sort True to sort the invoices by name.
812 *
813 * @return array The invoices list.
814 */
815 public static function getAllInvoices($group = '', $sort = false)
816 {
817 $parts = array(
818 VAPINVOICE,
819 );
820
821 if ($group)
822 {
823 $parts[] = $group;
824 }
825
826 $parts[] = '*.pdf';
827
828 $arr = glob(implode(DIRECTORY_SEPARATOR, $parts));
829
830 if ($sort)
831 {
832 sort($arr);
833 }
834
835 return $arr;
836 }
837
838 /**
839 * Returns an associative array containing the details of
840 * the specified file.
841 *
842 * @param string $file The file path.
843 * @param array $attr An array of options.
844 *
845 * @return mixed An array in case the file exists, null otherwise.
846 *
847 * @since 1.2
848 */
849 public static function getFileProperties($file, $attr = array())
850 {
851 if (!is_file($file))
852 {
853 return null;
854 }
855
856 // fill the options with the attributes needed in
857 // case they were not specified
858 $attr = self::getDefaultFileAttributes($attr);
859
860 $prop = array();
861 $prop['file'] = $file;
862 $prop['path'] = dirname($file);
863 $prop['name'] = basename($file);
864 $prop['file_ext'] = substr($file, strrpos($file, '.'));
865 $prop['size'] = JHtml::fetch('number.bytes', filesize($file));
866 $prop['timestamp'] = filemtime($file);
867 $prop['creation'] = JHtml::fetch('date', $prop['timestamp'], $attr['dateformat'], date_default_timezone_get());
868 $prop['name_no_ext'] = substr($prop['name'], 0, strrpos($prop['name'], '.'));
869
870 // fetch URI
871 if ($prop['path'] == VAPMEDIA)
872 {
873 // use media URI
874 $prop['uri'] = VAPMEDIA_URI;
875 }
876 else if ($prop['path'] == VAPMEDIA_SMALL)
877 {
878 // use media@small URI
879 $prop['uri'] = VAPMEDIA_SMALL_URI;
880 }
881 else if (strpos($prop['path'], VAPCUSTOMERS_DOCUMENTS) !== false)
882 {
883 // get rid of the path to preserve any additional folder
884 $folder = str_replace(VAPCUSTOMERS_DOCUMENTS, '', $prop['path']);
885 $folder = trim($folder, DIRECTORY_SEPARATOR);
886 $folder = str_replace(DIRECTORY_SEPARATOR, '/', $folder);
887
888 /**
889 * Use customers documents folder.
890 *
891 * @since 1.7
892 */
893 $prop['uri'] = VAPCUSTOMERS_DOCUMENTS_URI . $folder . '/';
894 }
895 else if (strpos($prop['path'], VAPCUSTOMERS_AVATAR) !== false)
896 {
897 /**
898 * Use customers avatar folder.
899 *
900 * @since 1.7
901 */
902 $prop['uri'] = VAPCUSTOMERS_AVATAR_URI;
903 }
904 else if (strpos($prop['path'], VAPBASE) !== false)
905 {
906 /**
907 * Fetch URI based on given (internal) site path.
908 *
909 * @since 1.7
910 */
911 $folder = str_replace(VAPBASE, '', $prop['path']);
912 $folder = trim($folder, DIRECTORY_SEPARATOR);
913 $folder = str_replace(DIRECTORY_SEPARATOR, '/', $folder);
914
915 $prop['uri'] = VAPBASE_URI . $folder . '/';
916 }
917 else if (strpos($prop['path'], VAPADMIN) !== false)
918 {
919 /**
920 * Fetch URI based on given (internal) admin path.
921 *
922 * @since 1.7
923 */
924 $folder = str_replace(VAPADMIN, '', $prop['path']);
925 $folder = trim($folder, DIRECTORY_SEPARATOR);
926 $folder = str_replace(DIRECTORY_SEPARATOR, '/', $folder);
927
928 $prop['uri'] = VAPADMIN_URI . $folder . '/';
929 }
930 else
931 {
932 throw new Exception('Unable to read files out of VikAppointments', 500);
933 }
934
935 // complete file URI
936 $prop['uri'] .= $prop['name'];
937
938 if (preg_match('/\.(jpe?g|a?png|bmp|gif|svg)$/i', $prop['file_ext']))
939 {
940 $img_size = getimagesize($file);
941
942 $prop['width'] = $img_size[0];
943 $prop['height'] = $img_size[1];
944 }
945
946 return $prop;
947 }
948
949 /**
950 * Returns an array of options to be used while fetching the
951 * details of a file. The default values will be used only
952 * if the specified attributes array doesn't contain them.
953 *
954 * @param array $attr An array of attributes.
955 *
956 * @return array The resulting array.
957 */
958 public static function getDefaultFileAttributes($attr = array())
959 {
960 if (empty($attr['dateformat']))
961 {
962 $config = VAPFactory::getConfig();
963
964 /**
965 * The date format is now localised.
966 *
967 * @since 1.7
968 */
969 $attr['dateformat'] = JText::translate('DATE_FORMAT_LC3') . ' ' . preg_replace("/:i/", ':i:s', $config->get('timeformat'));
970 }
971
972 return $attr;
973 }
974
975 /**
976 * Creates a dropdown containing all the media files.
977 *
978 * @param mixed $value The selected value.
979 * @param boolean $first_null True to insert an empty value as first option.
980 * @param array $prop An associative array of input properties.
981 *
982 * @return string The HTML of the dropdown.
983 *
984 * @uses getAllMedia()
985 */
986 public static function composeMediaSelect($value = null, $first_null = true, array $prop = array())
987 {
988 if (!isset($prop['name']))
989 {
990 $prop['name'] = 'media';
991 }
992
993 $prop_str = '';
994 foreach ($prop as $k => $v)
995 {
996 $prop_str .= ' ' . $k . (!empty($v) ? '="' . htmlspecialchars($v) . '"' : '');
997 }
998
999 $options = array();
1000
1001 if ($first_null)
1002 {
1003 $options[] = JHtml::fetch('select.option', '', '');
1004 }
1005
1006 foreach (self::getAllMedia() as $img)
1007 {
1008 $img = basename($img);
1009
1010 $options[] = JHtml::fetch('select.option', $img, $img);
1011 }
1012
1013 $selector = isset($prop['id']) ? '#' . $prop['id'] : 'input[name="' . $prop['name'] . '"]';
1014
1015 JFactory::getDocument()->addScriptDeclaration("jQuery(function() {
1016 jQuery('$selector').select2({
1017 placeholder: '" . (!$first_null ? addslashes(JText::translate('VAPFIRSTIMAGENULL')) : '--') . "',
1018 allowClear: true,
1019 width: 300
1020 });
1021 });");
1022
1023 return '<select' . $prop_str . '>' . JHtml::fetch('select.options', $options, 'value', 'text', $value) . '</select>';
1024 }
1025
1026 /**
1027 * Returns an associative array containing the authorisations used
1028 * to check which views can be visited by the logged-in user.
1029 *
1030 * @return array
1031 */
1032 public static function getAuthorisations()
1033 {
1034 static $rules = null;
1035
1036 if ($rules)
1037 {
1038 // return cached array
1039 return $rules;
1040 }
1041
1042 $rules = array(
1043 'dashboard' => array(
1044 'actions' => array('dashboard' => 0),
1045 'views' => array('dashboard' => 'vikappointments'),
1046 'numactives' => 0,
1047 ),
1048 'management' => array(
1049 'actions' => array('employees' => 0, 'groups' => 0, 'services' => 0, 'options' => 0, 'locations' => 0, 'packages' => 0),
1050 'views' => array(),
1051 'numactives' => 0,
1052 ),
1053 'appointments' => array(
1054 'actions' => array('reservations' => 0, 'waitinglist' => 0, 'customers' => 0, 'coupons' => 0, 'calendar' => 0),
1055 'views' => array(),
1056 'numactives' => 0,
1057 ),
1058 'portal' => array(
1059 'actions' => array('countries' => 0, 'reviews' => 0, 'subscriptions' => 0),
1060 'views' => array(),
1061 'numactives' => 0,
1062 ),
1063 'analytics' => array(
1064 'actions' => array(
1065 'analytics.finance' => 0,
1066 'analytics.appointments' => 0,
1067 'analytics.services' => 0,
1068 'analytics.employees' => 0,
1069 'analytics.options' => 0,
1070 'analytics.customers' => 0,
1071 'analytics.packages' => 0,
1072 'analytics.subscriptions' => 0,
1073 ),
1074 'numactives' => 0,
1075 ),
1076 'global' => array(
1077 'actions' => array('custfields' => 0, 'payments' => 0, 'statuscodes' => 0, 'taxes' => 0, 'archive' => 0, 'media' => 0),
1078 'views' => array(
1079 'custfields' => 'customf',
1080 'archive' => 'invoices',
1081 ),
1082 'numactives' => 0,
1083 ),
1084 'configuration' => array(
1085 'actions' => array('config' => 0, 'config.closures' => 0),
1086 'views' => array('config' => 'editconfig', 'config.closures' => 'editconfigcldays'),
1087 'numactives' => 0,
1088 ),
1089 );
1090
1091 $user = JFactory::getUser();
1092
1093 foreach ($rules as $group => $rule)
1094 {
1095 foreach ($rule['actions'] as $action => $val)
1096 {
1097 $rules[$group]['actions'][$action] = $user->authorise("core.access.$action", "com_vikappointments");
1098
1099 if ($rules[$group]['actions'][$action])
1100 {
1101 $rules[$group]['numactives']++;
1102 }
1103 }
1104 }
1105
1106 return $rules;
1107 }
1108
1109 /**
1110 * Register a new Joomla user with the details
1111 * specified in the given $args array.
1112 *
1113 * All the restrictions specified in com_users
1114 * component are always bypassed.
1115 *
1116 * @param array $args The user details.
1117 *
1118 * @return mixed The ID of the user on success, otherwise false.
1119 *
1120 * @throws RuntimeException
1121 */
1122 public static function createNewJoomlaUser($args)
1123 {
1124 jimport('joomla.application.component.helper');
1125 $params = JComponentHelper::getParams('com_users');
1126
1127 $vik = VAPApplication::getInstance();
1128
1129 $user = new JUser;
1130 $data = array();
1131
1132 if (empty($args['usertype']))
1133 {
1134 $groups = array($params->get('new_usertype', 2));
1135 }
1136 else
1137 {
1138 if (is_array($args['usertype']))
1139 {
1140 $groups = $args['usertype'];
1141 }
1142 else
1143 {
1144 $groups = array((string) $args['usertype']);
1145 }
1146 }
1147
1148 if (empty($args['user_username']))
1149 {
1150 // empty username, use the specified name
1151 $args['user_username'] = $args['user_name'];
1152 }
1153
1154 // get the default new user group, Registered if not specified
1155 $data['groups'] = $groups;
1156 $data['name'] = $args['user_name'];
1157 $data['username'] = $args['user_username'];
1158 $data['email'] = $vik->emailToPunycode($args['user_mail']);
1159 $data['password'] = $args['user_pwd1'];
1160 $data['password2'] = $args['user_pwd2'];
1161 $data['sendEmail'] = 0;
1162
1163 /**
1164 * Instead of returning 'false', this method
1165 * throws exceptions in case of errors.
1166 *
1167 * @since 1.7
1168 */
1169
1170 // bind user data
1171 if (!$user->bind($data))
1172 {
1173 // get error from user table
1174 $error = $user->getError(null, true);
1175
1176 // throw exception
1177 throw new RuntimeException($error ? $error : JText::translate('VAP_USER_SAVE_BIND_ERR'));
1178 }
1179
1180 if (!$user->save())
1181 {
1182 // get error from user table
1183 $error = $user->getError(null, true);
1184
1185 // throw exception
1186 throw new RuntimeException($error ? $error : JText::translate('VAP_USER_SAVE_CHECK_ERR'));
1187 }
1188
1189 return $user->id;
1190 }
1191
1192 /**
1193 * Removes the credit card details for the order that have been CONFIRMED
1194 * and don't need them anymore.
1195 *
1196 * @param boolean $force Flag used to skip the waiting check.
1197 * @param integer $wait The number of minutes to wait between each check.
1198 *
1199 * @return void
1200 *
1201 * @since 1.6
1202 */
1203 public static function removeExpiredCreditCards($force = false, $wait = 30)
1204 {
1205 $dbo = JFactory::getDbo();
1206 $session = JFactory::getSession();
1207
1208 $now = time();
1209
1210 // if doesn't exist, get a time in the past
1211 $check = (int) $session->get('cc-flush-check', $now - 3600, 'vikappointments');
1212
1213 if ($force || $check < $now)
1214 {
1215 $threshold = JFactory::getDate('-1 day');
1216
1217 // the reservations must have a checkin date previous than yesterday
1218 $q = $dbo->getQuery(true)
1219 ->update($dbo->qn('#__vikappointments_reservation'))
1220 ->set($dbo->qn('cc_data') . ' = ' . $dbo->q(''))
1221 ->where($dbo->qn('checkin_ts') . ' < ' . $dbo->q($threshold->toSql()));
1222
1223 $dbo->setQuery($q);
1224 $dbo->execute();
1225
1226 $threshold = JFactory::getDate('-1 week');
1227 $threshold2 = JFactory::getDate('-1 month');
1228
1229 // get any approved codes
1230 $approved = JHtml::fetch('vaphtml.status.find', 'code', array('packages' => 1, 'approved' => 1));
1231
1232 if ($approved)
1233 {
1234 // The packages must be confirmed and the creation date
1235 // should be at least one week old. Otherwise remove them
1236 // after one month since the creation date.
1237 $q = $dbo->getQuery(true)
1238 ->update($dbo->qn('#__vikappointments_package_order'))
1239 ->set($dbo->qn('cc_data') . ' = ' . $dbo->q(''))
1240 ->where(array(
1241 $dbo->qn('status') . ' IN (' . implode(',', array_map(array($dbo, 'q'), $approved)) . ')',
1242 $dbo->qn('createdon') . ' < ' . $dbo->q($threshold->toSql()),
1243 ))
1244 ->orWhere($dbo->qn('createdon') . ' < ' . $dbo->q($threshold2->toSql()));
1245
1246 $dbo->setQuery($q);
1247 $dbo->execute();
1248 }
1249
1250 // get any approved codes
1251 $approved = JHtml::fetch('vaphtml.status.find', 'code', array('subscriptions' => 1, 'approved' => 1));
1252
1253 if ($approved)
1254 {
1255 // The subscriptions must be confirmed and the creation date
1256 // should be at least one week old. Otherwise remove them
1257 // after one month since the creation date.
1258 $q = $dbo->getQuery(true)
1259 ->update($dbo->qn('#__vikappointments_subscr_order'))
1260 ->set($dbo->qn('cc_data') . ' = ' . $dbo->q(''))
1261 ->where(array(
1262 $dbo->qn('status') . ' IN (' . implode(',', array_map(array($dbo, 'q'), $approved)) . ')',
1263 $dbo->qn('createdon') . ' < ' . $dbo->q($threshold->toSql()),
1264 ))
1265 ->orWhere($dbo->qn('createdon') . ' < ' . $dbo->q($threshold2->toSql()));
1266
1267 $dbo->setQuery($q);
1268 $dbo->execute();
1269 }
1270
1271 // update time for next check
1272 $session->set('cc-flush-check', time() + $wait * 60, 'vikappointments');
1273 }
1274 }
1275
1276 /**
1277 * Updates the extra fields of VikAppointments to let them
1278 * be sent to our servers during Joomla! updates.
1279 *
1280 * @return void
1281 *
1282 * @since 1.6
1283 */
1284 public static function registerUpdaterFields()
1285 {
1286 // make sure the Joomla version is 3.2.0 or higher
1287 // otherwise the extra_fields wouldn't be available
1288 $jv = new JVersion();
1289
1290 if (version_compare($jv->getShortVersion(), '3.2.0', '<'))
1291 {
1292 // stop to avoid fatal errors
1293 return;
1294 }
1295
1296 /**
1297 * Do not register extra fields in case of Joomla 3.7+, because they are
1298 * injected every time the update is going to be launched.
1299 *
1300 * @since 1.7.3
1301 */
1302 if (version_compare($jv->getShortVersion(), '3.7.0', '>='))
1303 {
1304 return;
1305 }
1306
1307 $config = VAPFactory::getConfig();
1308 $extra_fields = $config->getInt('update_extra_fields', 0);
1309
1310 if ($extra_fields > time())
1311 {
1312 // not needed to rewrite extra fields
1313 return;
1314 }
1315
1316 // get current domain
1317 $server = JFactory::getApplication()->input->server;
1318 $domain = base64_encode($server->getString('HTTP_HOST'));
1319 $ip = $server->getString('REMOTE_ADDR');
1320
1321 // import url update handler
1322 VAPLoader::import('libraries.update.urihandler');
1323
1324 $update = new UriUpdateHandler('com_vikappointments');
1325
1326 $update->addExtraField('domain', $domain)
1327 ->addExtraField('ip', $ip)
1328 ->register();
1329
1330 // validate schema version
1331 $update->checkSchema($config->get('version'));
1332
1333 // rewrite extra fields next week
1334 $config->set('update_extra_fields', time() + 7 * 86400);
1335 }
1336
1337 /**
1338 * Method to add parameters to the update extra query.
1339 *
1340 * @param Update &$update An update definition
1341 * @param JTable &$table The update instance from the database
1342 *
1343 * @return void
1344 *
1345 * @since 1.7.3
1346 */
1347 public static function prepareUpdate(&$update, &$table)
1348 {
1349 // require autoloader
1350 require_once implode(DIRECTORY_SEPARATOR, array(JPATH_SITE, 'components', 'com_vikappointments', 'helpers', 'libraries', 'autoload.php'));
1351
1352 // get current domain
1353 $server = JFactory::getApplication()->input->server;
1354
1355 // build query array
1356 $query = [
1357 'domain' => base64_encode($server->getString('HTTP_HOST')),
1358 'ip' => $server->getString('REMOTE_ADDR'),
1359 ];
1360
1361 // check if we have already validated the license
1362 $licenseKey = VAPFactory::getConfig()->get('licensekey');
1363
1364 if ($licenseKey)
1365 {
1366 // inject license key within the request
1367 $query['key'] = $licenseKey;
1368 }
1369
1370 // always refresh the extra query before an update
1371 $update->set('extra_query', http_build_query($query, '', '&amp;'));
1372 }
1373
1374 /**
1375 * Get the actions.
1376 *
1377 * @param integer $id
1378 *
1379 * @return object
1380 */
1381 public static function getActions($id = 0)
1382 {
1383 jimport('joomla.access.access');
1384
1385 $user = JFactory::getUser();
1386 $result = new stdClass;
1387
1388 if (empty($id))
1389 {
1390 $assetName = 'com_vikappointments';
1391 }
1392 else
1393 {
1394 $assetName = 'com_vikappointments.message.' . (int) $id;
1395 }
1396
1397 $actions = JAccess::getActions('com_vikappointments', 'component');
1398
1399 foreach ($actions as $action)
1400 {
1401 $result->{$action->name} = $user->authorise($action->name, $assetName);
1402 };
1403
1404 return $result;
1405 }
1406 }
1407
1408 if (!class_exists('OrderingManager'))
1409 {
1410 /**
1411 * Helper class used to handle lists ordering.
1412 *
1413 * @since 1.0
1414 * @deprecated 1.8 Use VAPHtmlAdmin::sort() instead.
1415 */
1416 class OrderingManager
1417 {
1418 /**
1419 * The component name.
1420 *
1421 * @var string
1422 */
1423 protected static $option = 'com_vikappointments';
1424
1425 /**
1426 * The value in query string that will be used to
1427 * recover the selected ordering column.
1428 *
1429 * @var string
1430 */
1431 protected static $columnKey = 'vapordcolumn';
1432
1433 /**
1434 * The value in query string that will be used to
1435 * recover the selected ordering direction.
1436 *
1437 * @var string
1438 */
1439 protected static $typeKey = 'vapordtype';
1440
1441 /**
1442 * Class constructor.
1443 */
1444 protected function __construct()
1445 {
1446 // not accessible
1447 }
1448
1449 /**
1450 * Prepares the class with custom configuration.
1451 *
1452 * @param string $option
1453 * @param string $column
1454 * @param string $type
1455 *
1456 * @return void
1457 */
1458 public static function getInstance($option = '', $column = '', $type = '')
1459 {
1460 if (!empty($option))
1461 {
1462 self::$option = $option;
1463 }
1464
1465 if (!empty($column))
1466 {
1467 self::$columnKey = $column;
1468 }
1469
1470 if (!empty($type))
1471 {
1472 self::$typeKey = $type;
1473 }
1474 }
1475
1476 /**
1477 * Returns the link that will be used to sort the column.
1478 *
1479 * @param string $task The task to reach after clicking the link.
1480 * @param string $text The link text.
1481 * @param string $col The column to sort.
1482 * @param string $type The new direction value (1 ASC, 2 DESC).
1483 * @param string $def_type The default direction if $type is empty.
1484 * @param array $params An associative array with addition params to include in the URL-
1485 * @param string $active_class The class used in case of active link.
1486 *
1487 * @return string The HTML of the link.
1488 */
1489 public static function getLinkColumnOrder($task, $text, $col, $type = '', $def_type = '', $params = array(), $active_class = '')
1490 {
1491 if (empty($type))
1492 {
1493 $type = $def_type;
1494 $active_class = '';
1495 }
1496
1497 if (!is_array($params))
1498 {
1499 if (empty($params))
1500 {
1501 $params = array();
1502 }
1503 else
1504 {
1505 $params = array($params);
1506 }
1507 }
1508
1509 // inject URL vars in $params array
1510 $params['option'] = self::$option;
1511 $params['task'] = $task;
1512 $params[self::$columnKey] = $col;
1513 $params[self::$typeKey] = $type;
1514
1515 $href = 'index.php?' . http_build_query($params);
1516
1517 return '<a class="' . $active_class . '" href="' . $href . '">' . $text . '</a>';
1518 }
1519
1520 /**
1521 * Returns the ordering details for the specified values.
1522 *
1523 * @param string $task The task where we are.
1524 * @param string $def_col The default column to sort.
1525 * @param string $def_type The default ordering direction.
1526 *
1527 * @return array An associative array containing the ordering column and direction.
1528 */
1529 public static function getColumnToOrder($task, $def_col = 'id', $def_type = 1)
1530 {
1531 $app = JFactory::getApplication();
1532
1533 $col = $app->getUserStateFromRequest(self::$columnKey . "[$task]", self::$columnKey, $def_col, 'string');
1534 $type = $app->getUserStateFromRequest(self::$typeKey . "[$task]", self::$typeKey, $def_type, 'uint');
1535
1536 return array('column' => $col, 'type' => $type);
1537 }
1538
1539 /**
1540 * Returns the ordering direction, based on the current one.
1541 *
1542 * @param string $task The task where we are.
1543 * @param string $col The column we need to alter.
1544 * @param string $curr_type The current direction.
1545 *
1546 * @return string The new direction value.
1547 */
1548 public static function getSwitchColumnType($task, $col, $curr_type)
1549 {
1550 $stored = JFactory::getApplication()->getUserStateFromRequest(self::$columnKey . "[$task]", self::$columnKey, '', 'string');
1551
1552 $types = array(1, 2);
1553
1554 if ($stored == $col)
1555 {
1556 $index = array_search($curr_type, $types);
1557
1558 if ($index >= 0)
1559 {
1560 return $types[($index + 1) % 2];
1561 }
1562 }
1563
1564 return end($types);
1565 }
1566 }
1567 }
1568
1569 /**
1570 * Vikappointments back-end component helper.
1571 *
1572 * @since 1.0
1573 * @deprecated 1.8 Use VikAppointmentsHelper instead.
1574 */
1575 class_alias('VikAppointmentsHelper', 'AppointmentsHelper');
1576