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 / site / helpers / libraries / sef / router / j40.php
vikappointments / site / helpers / libraries / sef / router Last commit date
default.php 6 days ago index.html 6 days ago j40.php 6 days ago
j40.php
796 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 use Joomla\CMS\Component\Router\RouterBase;
15
16 VAPLoader::import('libraries.sef.router');
17
18 /**
19 * Routing class for com_vikappointments component.
20 * Compatible with Joomla 4.0 or higher.
21 *
22 * @since 1.7
23 */
24 class VikAppointmentsRouter extends RouterBase
25 {
26 /**
27 * Use trait for router helping functions.
28 */
29 use VAPSefRouter;
30
31 /**
32 * The current language tag.
33 *
34 * @var string
35 */
36 protected $langtag;
37
38 /**
39 * Class constructor.
40 *
41 * @param JApplicationCms $app Application-object that the router should use.
42 * @param JMenu $menu Menu-object that the router should use.
43 */
44 public function __construct($app = null, $menu = null)
45 {
46 // invoke parent constructor
47 parent::__construct($app, $menu);
48
49 $this->langtag = JFactory::getLanguage()->getTag();
50
51 VAPLoader::import('libraries.sef.helper');
52 }
53
54 /**
55 * Prepare-method for URLs.
56 * This method is meant to validate and complete the URL parameters.
57 * For example it can add the Itemid or set a language parameter.
58 * This method is executed on each URL, regardless of SEF mode switched
59 * on or not.
60 *
61 * @param array $query An associative array of URL arguments.
62 *
63 * @return array The URL arguments to use to assemble the subsequent URL.
64 */
65 public function preprocess($query)
66 {
67 if (!empty($query['lang']))
68 {
69 // always use the specified language
70 $this->langtag = $query['lang'];
71 }
72 else
73 {
74 // force the currently set language
75 $this->langtag = JFactory::getLanguage()->getTag();
76 }
77
78 $dbo = JFactory::getDbo();
79
80 $active = $this->menu->getActive();
81
82 if (!isset($query['view']))
83 {
84 // view not set, do not go ahead
85 return $query;
86 }
87
88 $itemid = null;
89
90 // services list
91
92 if ($query['view'] == 'serviceslist')
93 {
94 if (isset($query['service_group']))
95 {
96 // try to obtain the proper Itemid that belong to the serviceslist view with the given group
97 $itemid = $this->getProperItemID('serviceslist', array('service_group' => $query['service_group']));
98 }
99
100 if (!$itemid)
101 {
102 // attempt to load a default list of services without category
103 $itemid = $this->getProperItemID('serviceslist', array(), array('service_group'));
104 }
105
106 if ($itemid)
107 {
108 // overwrite the Itemid set in the query in order
109 // to rewrite the base URI
110 $query['Itemid'] = $itemid;
111 }
112 }
113
114 // employees list
115
116 else if ($query['view'] == 'employeeslist')
117 {
118 if (isset($query['employee_group']))
119 {
120 // try to obtain the proper Itemid that belong to the employeeslist view with the given group
121 $itemid = $this->getProperItemID('employeeslist', array('employee_group' => $query['employee_group']));
122 }
123
124 if (!$itemid)
125 {
126 // attempt to load a default list of employees without category
127 $itemid = $this->getProperItemID('employeeslist', array(), array('employee_group'));
128 }
129
130 if ($itemid)
131 {
132 // overwrite the Itemid set in the query in order
133 // to rewrite the base URI
134 $query['Itemid'] = $itemid;
135 }
136 }
137
138 // service details
139
140 else if ($query['view'] == 'servicesearch')
141 {
142 // backward compatibility for old query string
143 if (!isset($query['id_service']) && isset($query['id_ser']))
144 {
145 $query['id_service'] = $query['id_ser'];
146 }
147
148 // build URL for service details
149 if (isset($query['id_service']))
150 {
151 // arguments used to check if the active menu item
152 // matches the values set in query string
153 $args = array(
154 'view' => 'servicesearch',
155 'id_service' => $query['id_service'],
156 );
157
158 /**
159 * Make sure the ID of the service is not set within the query of the menu item.
160 * This because the link may be a self redirect, causing duplicated aliases.
161 * For example, if we have something like:
162 * /services/service-name/
163 * we need to avoid pushing the alias of the service.
164 */
165 if (!$this->matchItemArguments($active, $args))
166 {
167 // try to obtain the proper Itemid that belong directly to the service details view
168 $itemid = $this->getProperItemID('servicesearch', array('id_service' => $query['id_service']));
169
170 if (!$itemid)
171 {
172 // try with the old notation too
173 $itemid = $this->getProperItemID('servicesearch', array('id_ser' => $query['id_service']));
174 }
175
176 if (!$itemid)
177 {
178 // get parent group
179 $q = $dbo->getQuery(true)
180 ->select($dbo->qn('id_group'))
181 ->from($dbo->qn('#__vikappointments_service'))
182 ->where($dbo->qn('id') . ' = ' . (int) $query['id_service']);
183
184 $dbo->setQuery($q, 0, 1);
185
186 if ($id_group = (int) $dbo->loadResult())
187 {
188 // try to obtain the proper Itemid that belong to the serviceslist view with the given group
189 $itemid = $this->getProperItemID('serviceslist', array('service_group' => $id_group));
190 }
191
192 if (!$itemid)
193 {
194 // fallback to obtain the proper Itemid that belong to the serviceslist view
195 $itemid = $this->getProperItemID('serviceslist', array(), array('service_group'));
196 }
197 }
198
199 if ($itemid)
200 {
201 // overwrite the Itemid set in the query in order
202 // to rewrite the base URI
203 $query['Itemid'] = $itemid;
204 }
205 }
206 }
207 }
208
209 // employee details
210
211 else if ($query['view'] == 'employeesearch')
212 {
213 // build URL for employee details
214 if (isset($query['id_employee']))
215 {
216 // arguments used to check if the active menu item
217 // matches the values set in query string
218 $args = array(
219 'view' => 'employeesearch',
220 'id_employee' => $query['id_employee'],
221 );
222
223 /**
224 * Make sure the ID of the employee is not set within the query of the menu item.
225 * This because the link may be a self redirect, causing duplicated aliases.
226 * For example, if we have something like:
227 * /employees/employee-name/
228 * we need to avoid pushing the alias of the employee.
229 */
230 if (!$this->matchItemArguments($active, $args))
231 {
232 // try to obtain the proper Itemid that belong directly to the employee details view
233 $itemid = $this->getProperItemID('employeesearch', array('id_employee' => $query['id_employee']));
234
235 if (!$itemid)
236 {
237 // get parent group
238 $q = $dbo->getQuery(true)
239 ->select($dbo->qn('id_group'))
240 ->from($dbo->qn('#__vikappointments_employee'))
241 ->where($dbo->qn('id') . ' = ' . (int) $query['id_employee']);
242
243 $dbo->setQuery($q, 0, 1);
244
245 if ($id_group = (int) $dbo->loadResult())
246 {
247 // try to obtain the proper Itemid that belong to the employeeslist view with the given group
248 $itemid = $this->getProperItemID('employeeslist', array('employee_group' => $id_group));
249 }
250
251 if (!$itemid)
252 {
253 // fallback to obtain the proper Itemid that belong to the employeeslist view
254 $itemid = $this->getProperItemID('employeeslist', array(), array('employee_group'));
255 }
256 }
257
258 if ($itemid)
259 {
260 // overwrite the Itemid set in the query in order
261 // to rewrite the base URI
262 $query['Itemid'] = $itemid;
263 }
264 }
265 }
266 }
267
268 // order | allorders
269
270 else if (in_array($query['view'], array('allorders', 'order', 'packorders', 'packagesorder', 'subscrhistory', 'subscrpayment', 'userprofile')))
271 {
272 // try to obtain the proper Itemid that belong to the specified view
273 $itemid = $this->getProperItemID($query['view']);
274
275
276 if (!$itemid)
277 {
278 // fallback to obtain the proper Itemid that belong to the allorders view
279 $itemid = $this->getProperItemID('allorders');
280 }
281
282 if ($itemid)
283 {
284 // overwrite the Itemid set in the query in order
285 // to rewrite the base URI
286 $query['Itemid'] = $itemid;
287 }
288 }
289
290 // fallback
291
292 else
293 {
294 // check whether the requested view owns an Item ID
295 $itemid = $this->getProperItemID($query['view']);
296
297 // if itemid doesn't exist and the current view is different
298 // than the specified one, push the view within the segments
299 if (empty($itemid) && (!$active || $query['view'] != $active->query['view']))
300 {
301 if (substr($query['view'], 0, 3) == 'emp')
302 {
303 // fallback to obtain a parent item for employees area views
304 $itemid = $this->getProperItemID('emplogin');
305 }
306 }
307
308 if ($itemid)
309 {
310 // set new Item ID
311 $query['Itemid'] = $itemid;
312 }
313 }
314
315 return $query;
316 }
317
318 /**
319 * Build method for URLs.
320 * This method is meant to transform the query parameters into a more human
321 * readable form. It is only executed when SEF mode is switched on.
322 *
323 * @param array &$query An array of URL arguments.
324 *
325 * @return array The URL arguments to use to assemble the subsequent URL.
326 */
327 public function build(&$query)
328 {
329 $dbo = JFactory::getDbo();
330
331 $active = $this->menu->getActive();
332
333 $segments = array();
334
335 if (!isset($query['view']) || !$this->isActive())
336 {
337 // view not set or router is disabled
338 return $segments;
339 }
340
341 // services list
342
343 if ($query['view'] == 'serviceslist')
344 {
345 if (isset($query['service_group']))
346 {
347 // try to obtain the proper Itemid that belong to the serviceslist view with the given group
348 $itemid = $this->getProperItemID('serviceslist', array('service_group' => $query['service_group']));
349
350 if ($itemid)
351 {
352 // page found, unset service group from query
353 unset($query['service_group']);
354 }
355 }
356
357 // unset the view from the query
358 unset($query['view']);
359 }
360
361 // employees list
362
363 else if ($query['view'] == 'employeeslist')
364 {
365 if (isset($query['employee_group']))
366 {
367 // try to obtain the proper Itemid that belong to the employeeslist view with the given group
368 $itemid = $this->getProperItemID('employeeslist', array('employee_group' => $query['employee_group']));
369
370 if ($itemid)
371 {
372 // page found, unset employee group from query
373 unset($query['employee_group']);
374 }
375 }
376
377 // unset the view from the query
378 unset($query['view']);
379 }
380
381 // service details
382
383 else if ($query['view'] == 'servicesearch')
384 {
385 // backward compatibility for old query string
386 if (!isset($query['id_service']) && isset($query['id_ser']))
387 {
388 $query['id_service'] = $query['id_ser'];
389 }
390
391 // build URL for service details
392 if (isset($query['id_service']))
393 {
394 // arguments used to check if the active menu item
395 // matches the values set in query string
396 $args = array(
397 'view' => 'servicesearch',
398 'id_service' => $query['id_service'],
399 );
400
401 /**
402 * Make sure the ID of the service is not set within the query of the menu item.
403 * This because the link may be a self redirect, causing duplicated aliases.
404 * For example, if we have something like:
405 * /services/service-name/
406 * we need to avoid pushing the alias of the service.
407 */
408 if (!$this->matchItemArguments($active, $args))
409 {
410 // try to obtain the proper Itemid that belong directly to the service details view
411 $itemid = $this->getProperItemID('servicesearch', array('id_service' => $query['id_service']));
412
413 if (!$itemid)
414 {
415 // try with the old notation too
416 $itemid = $this->getProperItemID('servicesearch', array('id_ser' => $query['id_service']));
417 }
418
419 if (!$itemid)
420 {
421 // fetch service alias
422 $alias = VAPSefHelper::getRecordAlias($query['id_service'], 'service', $this->langtag);
423
424 if ($alias)
425 {
426 // alias found, push it within the segments array
427 $segments[] = $alias;
428 }
429 }
430 }
431
432 // unset service ID from query
433 unset($query['id_service'], $query['id_ser']);
434 }
435
436 // unset the view from the query
437 unset($query['view']);
438 }
439
440 // employee details
441
442 else if ($query['view'] == 'employeesearch')
443 {
444 // build URL for employee details
445 if (isset($query['id_employee']))
446 {
447 // arguments used to check if the active menu item
448 // matches the values set in query string
449 $args = array(
450 'view' => 'employeesearch',
451 'id_employee' => $query['id_employee'],
452 );
453
454 /**
455 * Make sure the ID of the employee is not set within the query of the menu item.
456 * This because the link may be a self redirect, causing duplicated aliases.
457 * For example, if we have something like:
458 * /employees/employee-name/
459 * we need to avoid pushing the alias of the employee.
460 */
461 if (!$this->matchItemArguments($active, $args))
462 {
463 // try to obtain the proper Itemid that belong directly to the employee details view
464 $itemid = $this->getProperItemID('employeesearch', array('id_employee' => $query['id_employee']));
465
466 if (!$itemid)
467 {
468 // fetch employee alias
469 $alias = VAPSefHelper::getRecordAlias($query['id_employee'], 'employee', $this->langtag);
470
471 if ($alias)
472 {
473 // alias found, push it within the segments array
474 $segments[] = $alias;
475 }
476 }
477 }
478
479 // unset employee ID from query
480 unset($query['id_employee']);
481 }
482
483 // unset the view from the query
484 unset($query['view']);
485 }
486
487 // order | allorders
488
489 else if (in_array($query['view'], array('allorders', 'order', 'packorders', 'packagesorder', 'subscrhistory', 'subscrpayment', 'userprofile')))
490 {
491 // try to obtain the proper Itemid that belong to the specified view
492 $itemid = $this->getProperItemID($query['view']);
493
494 if (!$itemid)
495 {
496 // fallback to obtain the proper Itemid that belong to the allorders view
497 $itemid = $this->getProperItemID('allorders');
498 }
499
500 if ($itemid)
501 {
502 // prepend view name to differentiate orders and reservations
503 switch ($query['view'])
504 {
505 case 'packorders':
506 case 'packagesorder':
507 $segments[] = VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_PACKAGES'));
508 break;
509
510 case 'subscrhistory':
511 case 'subscrpayment':
512 $segments[] = VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_SUBSCRIPTIONS'));
513 break;
514
515 case 'userprofile':
516 $segments[] = VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_USERPROFILE'));
517 break;
518 }
519
520 // build URL for order details
521 if (isset($query['ordnum']) && isset($query['ordkey']))
522 {
523 // ordnum and ordkey must be set
524 $segments[] = VAPSefHelper::stringToAlias(intval($query['ordnum']) . "-" . $query['ordkey']);
525
526 // unset ord num and ord key
527 unset($query['ordnum']);
528 unset($query['ordkey']);
529 }
530
531 // unset the view from the query
532 unset($query['view']);
533 }
534 }
535
536 /**
537 * The code below is used to push the view name within the $segments array in
538 * case that view is not related to the current menu item.
539 *
540 * The resulting segment will look like:
541 * /emplogin/empeditprofile/
542 * instead of:
543 * /emplogin?view=empeditprofile
544 */
545
546 else
547 {
548 // check whether the requested view owns an Item ID
549 $itemid = $this->getProperItemID($query['view']);
550
551 // if itemid doesn't exist and the current view is different
552 // than the specified one, push the view within the segments
553 if (empty($itemid) && (!$active || $query['view'] != $active->query['view']))
554 {
555 if (substr($query['view'], 0, 3) == 'emp')
556 {
557 // fallback to obtain a parent item for employees area views
558 $itemid = $this->getProperItemID('emplogin');
559
560 if ($itemid)
561 {
562 $segments[] = $query['view'];
563 }
564 }
565 }
566
567 if ($itemid)
568 {
569 // unset the view from the query
570 unset($query['view']);
571 }
572 }
573
574 return $segments;
575 }
576
577 /**
578 * Parse method for URLs.
579 * This method is meant to transform the human readable URL back into
580 * query parameters. It is only executed when SEF mode is switched on.
581 *
582 * @param array &$segments The segments of the URL to parse.
583 *
584 * @return array The URL attributes to be used by the application.
585 */
586 public function parse(&$segments)
587 {
588 $total = count($segments);
589 $active = $this->menu->getActive();
590 $query_view = empty($active->query['view']) ? '' : $active->query['view'];
591 $vars = array();
592
593 if (!$total || !$this->isActive())
594 {
595 // no vars or router is disabled
596 return $vars;
597 }
598
599 // load site language because some keywords might be
600 // translated through the component
601 VikAppointments::loadLanguage($this->langtag);
602
603 // order details
604
605 if ($segments[0] == 'order')
606 {
607 $vars['view'] = 'order';
608
609 if (count($segments) > 1)
610 {
611 // make sure the order number and the order key are set
612 $exp = explode('-', $segments[1]);
613
614 if (count($exp) == 2)
615 {
616 $vars['ordnum'] = $exp[0];
617 $vars['ordkey'] = $exp[1];
618 }
619 }
620 }
621
622 // packages history
623
624 else if ($segments[0] == VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_PACKAGES')))
625 {
626 // list view
627 $vars['view'] = 'packorders';
628
629 if ($total > 1)
630 {
631 // make sure the order number and the order key are set
632 $exp = explode('-', $segments[1]);
633
634 if (count($exp) == 2)
635 {
636 $vars['ordnum'] = $exp[0];
637 $vars['ordkey'] = $exp[1];
638
639 // access order details
640 $vars['view'] = 'packagesorder';
641 }
642 }
643 }
644
645 // subscriptions history
646
647 else if ($segments[0] == VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_SUBSCRIPTIONS')))
648 {
649 // list view
650 $vars['view'] = 'subscrhistory';
651
652 if ($total > 1)
653 {
654 // make sure the order number and the order key are set
655 $exp = explode('-', $segments[1]);
656
657 if (count($exp) == 2)
658 {
659 $vars['ordnum'] = $exp[0];
660 $vars['ordkey'] = $exp[1];
661
662 // access order details
663 $vars['view'] = 'subscrpayment';
664 }
665 }
666 }
667
668 // user profile
669
670 else if ($segments[0] == VAPSefHelper::stringToAlias(JText::translate('VAP_SEF_USERPROFILE')))
671 {
672 // list view
673 $vars['view'] = 'userprofile';
674 }
675
676 // order | all orders
677
678 else if ($query_view == 'allorders' || $query_view == 'order')
679 {
680 // fallback to check if we passed the ordnum and ordkey to retrieve the order
681 if (preg_match("/[\d]+-[a-z0-9]{16,16}$/", $segments[0]))
682 {
683 list($ordnum, $ordkey) = explode('-', $segments[0]);
684
685 $vars['view'] = 'order';
686 $vars['ordnum'] = $ordnum;
687 $vars['ordkey'] = $ordkey;
688 }
689 else
690 {
691 $vars['view'] = $segments[0];
692 }
693 }
694
695 // services list
696
697 else if ($segments[0] == 'serviceslist')
698 {
699 $vars['view'] = 'serviceslist';
700
701 $itemid = $this->getProperItemID($vars['view']);
702
703 if (!empty($itemid))
704 {
705 $vars['Itemid'] = $itemid;
706 }
707 }
708
709 // employees list
710
711 else if ($segments[0] == 'employeeslist')
712 {
713 $vars['view'] = 'employeeslist';
714
715 $itemid = $this->getProperItemID($vars['view']);
716
717 if (!empty($itemid))
718 {
719 $vars['Itemid'] = $itemid;
720 }
721 }
722
723 // employee login
724
725 else if ($segments[0] == 'emplogin')
726 {
727 $vars['view'] = 'emplogin';
728
729 $itemid = $this->getProperItemID($vars['view']);
730
731 if (!empty($itemid))
732 {
733 $vars['Itemid'] = $itemid;
734 }
735 }
736
737 // waiting list
738
739 else if ($segments[0] == 'pushwl')
740 {
741 /**
742 * The view name is contained within the segments array.
743 * Without this block, the view name "pushwl" would be
744 * considered as an alias for the service/employee to get.
745 */
746 $vars['view'] = $segments[0];
747 }
748
749 // service search
750
751 else if ($segments[0] == 'servicesearch' || $query_view == 'serviceslist')
752 {
753 // find the index in which the alias should be stored
754 $pos = $total == 1 ? 0 : 1;
755 $alias = $segments[$pos];
756
757 $id = VAPSefHelper::getRecordWithAlias($alias, 'service');
758
759 if ($id)
760 {
761 $vars['id_service'] = (int) $id;
762 $vars['view'] = 'servicesearch';
763 }
764 }
765
766 // employee search
767
768 else if ($segments[0] == 'employeesearch' || $query_view == 'employeeslist')
769 {
770 // find the index in which the alias should be stored
771 $pos = $total == 1 ? 0 : 1;
772 $alias = $segments[$pos];
773
774 $id = VAPSefHelper::getRecordWithAlias($alias, 'employee');
775
776 if ($id)
777 {
778 $vars['id_employee'] = (int) $id;
779 $vars['view'] = 'employeesearch';
780 }
781 }
782
783 // fallback
784
785 else
786 {
787 // the view name is contained within the segments array
788 $vars['view'] = $segments[0];
789 }
790
791 $segments = array();
792
793 return $vars;
794 }
795 }
796