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