| 1 |
<?php |
| 2 |
/** |
| 3 |
* @package VikBooking |
| 4 |
* @subpackage core |
| 5 |
* @author Alessio Gaggii - E4J s.r.l. |
| 6 |
* @copyright Copyright (C) 2023 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 |
* Class handler for loading PMS Reports. |
| 16 |
* |
| 17 |
* @since 1.16.1 (J) - 1.6.1 (WP) |
| 18 |
*/ |
| 19 |
final class VBOReportLoader |
| 20 |
{ |
| 21 |
/** |
| 22 |
* The singleton instance of the class. |
| 23 |
* |
| 24 |
* @var VBOReportLoader |
| 25 |
*/ |
| 26 |
private static $instance = null; |
| 27 |
|
| 28 |
/** |
| 29 |
* @var array |
| 30 |
*/ |
| 31 |
private $global_reports = []; |
| 32 |
|
| 33 |
/** |
| 34 |
* @var array |
| 35 |
*/ |
| 36 |
private $country_reports = []; |
| 37 |
|
| 38 |
/** |
| 39 |
* @var array |
| 40 |
*/ |
| 41 |
private $countries = []; |
| 42 |
|
| 43 |
/** |
| 44 |
* Proxy to construct the object. |
| 45 |
* |
| 46 |
* @return self |
| 47 |
*/ |
| 48 |
public static function getInstance() |
| 49 |
{ |
| 50 |
if (is_null(static::$instance)) { |
| 51 |
static::$instance = new static(); |
| 52 |
} |
| 53 |
|
| 54 |
return static::$instance; |
| 55 |
} |
| 56 |
|
| 57 |
/** |
| 58 |
* Class constructor will require the necessary dependencies. |
| 59 |
*/ |
| 60 |
public function __construct() |
| 61 |
{ |
| 62 |
// require the report abstract class |
| 63 |
$report_base = $this->getReportBasePath(); |
| 64 |
require_once $report_base . 'report.php'; |
| 65 |
} |
| 66 |
|
| 67 |
/** |
| 68 |
* Gets the instance of a specific report class. |
| 69 |
* |
| 70 |
* @param string $report the name of the report to load. |
| 71 |
* |
| 72 |
* @return mixed false or report object instance. |
| 73 |
*/ |
| 74 |
public function getDriver($report) |
| 75 |
{ |
| 76 |
return VikBooking::getReportInstance($report); |
| 77 |
} |
| 78 |
|
| 79 |
/** |
| 80 |
* Loads and returns the list of available PMS Report objects. |
| 81 |
* |
| 82 |
* @return array list of "global" and "country" reports. |
| 83 |
*/ |
| 84 |
public function getDrivers($type = '') |
| 85 |
{ |
| 86 |
if ($this->global_reports || $this->country_reports) { |
| 87 |
// drivers loaded already |
| 88 |
return [$this->global_reports, $this->country_reports]; |
| 89 |
} |
| 90 |
|
| 91 |
// read all driver files |
| 92 |
$report_files = glob($this->getReportBasePath() . '*.php'); |
| 93 |
|
| 94 |
/** |
| 95 |
* Trigger event to let other plugins register additional driver full paths. |
| 96 |
* |
| 97 |
* @since 1.16.0 (J) - 1.6.0 (WP) |
| 98 |
*/ |
| 99 |
$list = VBOFactory::getPlatform()->getDispatcher()->filter('onLoadPmsReports'); |
| 100 |
foreach ($list as $chunk) { |
| 101 |
// merge default driver files with the returned ones |
| 102 |
$report_files = array_merge($report_files, (array)$chunk); |
| 103 |
} |
| 104 |
|
| 105 |
// parse and invoke all drivers |
| 106 |
foreach ($report_files as $k => $report_path) { |
| 107 |
// driver file name |
| 108 |
$report_file = basename($report_path, '.php'); |
| 109 |
|
| 110 |
if ($report_file == 'report') { |
| 111 |
// exclude protected abstract report class |
| 112 |
unset($report_files[$k]); |
| 113 |
continue; |
| 114 |
} |
| 115 |
|
| 116 |
// load report file |
| 117 |
require_once $report_path; |
| 118 |
|
| 119 |
// build report class name |
| 120 |
$classname = 'VikBookingReport' . str_replace(' ', '', ucwords(str_replace('_', ' ', $report_file))); |
| 121 |
if (!class_exists($classname)) { |
| 122 |
// invalid class name declared |
| 123 |
unset($report_files[$k]); |
| 124 |
continue; |
| 125 |
} |
| 126 |
|
| 127 |
// instantiate the report object |
| 128 |
$reportInstance = new $classname; |
| 129 |
|
| 130 |
// ensure the report is compatible with the current environment |
| 131 |
if ($reportInstance->preflight() === false) { |
| 132 |
// exclude non-compatible report |
| 133 |
unset($report_files[$k]); |
| 134 |
continue; |
| 135 |
} |
| 136 |
|
| 137 |
if ($report_file == 'revenue' && $this->global_reports) { |
| 138 |
// make the "revenue" the first element of the list |
| 139 |
array_unshift($this->global_reports, $reportInstance); |
| 140 |
} elseif (strpos($report_file, 'istat') !== false || strpos($report_file, 'polizia') !== false) { |
| 141 |
// this is a country (italy) specific report so we push it to a separate array |
| 142 |
$country_key = 'IT'; |
| 143 |
if (!isset($this->country_reports[$country_key])) { |
| 144 |
$this->country_reports[$country_key] = []; |
| 145 |
} |
| 146 |
$this->country_reports[$country_key][] = $reportInstance; |
| 147 |
} elseif (substr($report_file, 2, 1) == '_') { |
| 148 |
// this is probably a country specific report so we push it to a separate array (two-letter country code + underscore in file name) |
| 149 |
$country_key = strtoupper(substr($report_file, 0, 2)); |
| 150 |
if (!isset($this->country_reports[$country_key])) { |
| 151 |
$this->country_reports[$country_key] = []; |
| 152 |
} |
| 153 |
$this->country_reports[$country_key][] = $reportInstance; |
| 154 |
} else { |
| 155 |
// push this object as a global report |
| 156 |
$this->global_reports[] = $reportInstance; |
| 157 |
} |
| 158 |
} |
| 159 |
|
| 160 |
// get countries information for the reports |
| 161 |
$countries = $this->getInvolvedCountries(); |
| 162 |
|
| 163 |
// check whether some country specific reports truly belong to a country |
| 164 |
foreach ($this->country_reports as $ckey => $cvalue) { |
| 165 |
if (!isset($countries[$ckey])) { |
| 166 |
// this country does not exist, so maybe the report file was given a short beginning name. Push it to the global reports array |
| 167 |
unset($this->country_reports[$ckey]); |
| 168 |
$this->global_reports = array_merge($this->global_reports, $cvalue); |
| 169 |
} |
| 170 |
} |
| 171 |
|
| 172 |
/** |
| 173 |
* Apply sorting based on most advanced PMS reports supporting electronic transmission. |
| 174 |
* |
| 175 |
* @since 1.17.2 (J) - 1.7.2 (WP) |
| 176 |
*/ |
| 177 |
foreach ($this->country_reports as $ckey => &$creports) { |
| 178 |
// apply sorting by priority and then by name |
| 179 |
usort($creports, function($a, $b) use ($ckey) { |
| 180 |
// calculate the priority based on electronic transmission functions |
| 181 |
$a_reflection = new ReflectionMethod($a, 'getScopedActions'); |
| 182 |
$a_priority = (int) ($a_reflection->getDeclaringClass()->getName() === get_class($a)); |
| 183 |
$b_reflection = new ReflectionMethod($b, 'getScopedActions'); |
| 184 |
$b_priority = (int) ($b_reflection->getDeclaringClass()->getName() === get_class($b)); |
| 185 |
|
| 186 |
// technical priority |
| 187 |
$tech_priority = $b_priority - $a_priority; |
| 188 |
|
| 189 |
if ($tech_priority !== 0) { |
| 190 |
// the higher the priority is, the higher the position will be |
| 191 |
return $tech_priority; |
| 192 |
} |
| 193 |
|
| 194 |
// get report names |
| 195 |
$a_name = $a->getName(); |
| 196 |
$b_name = $b->getName(); |
| 197 |
|
| 198 |
if ($ckey === 'IT') { |
| 199 |
// static priority to Police related reports |
| 200 |
$police_priority = (int) stripos($b_name, 'poli') - (int) stripos($a_name, 'poli'); |
| 201 |
if ($police_priority !== 0) { |
| 202 |
// sort by authority |
| 203 |
return $police_priority; |
| 204 |
} |
| 205 |
} |
| 206 |
|
| 207 |
// sort by report name |
| 208 |
return strcasecmp($a_name, $b_name); |
| 209 |
}); |
| 210 |
} |
| 211 |
// unset last reference |
| 212 |
unset($creports); |
| 213 |
|
| 214 |
// return the list of drivers |
| 215 |
return [$this->global_reports, $this->country_reports]; |
| 216 |
} |
| 217 |
|
| 218 |
/** |
| 219 |
* Returns the associative list of the involved countries for the reports. |
| 220 |
* |
| 221 |
* @return array |
| 222 |
*/ |
| 223 |
public function getInvolvedCountries() |
| 224 |
{ |
| 225 |
if ($this->countries || !$this->country_reports) { |
| 226 |
return $this->countries; |
| 227 |
} |
| 228 |
|
| 229 |
$dbo = JFactory::getDbo(); |
| 230 |
|
| 231 |
// get countries information for the reports |
| 232 |
$country_keys = array_keys($this->country_reports); |
| 233 |
$country_keys = array_map(array($dbo, 'quote'), $country_keys); |
| 234 |
|
| 235 |
$q = $dbo->getQuery(true); |
| 236 |
|
| 237 |
$q->select($dbo->qn(['country_name', 'country_2_code'])); |
| 238 |
$q->from($dbo->qn('#__vikbooking_countries')); |
| 239 |
$q->where($dbo->qn('country_2_code') . ' IN (' . implode(', ', $country_keys) . ')'); |
| 240 |
|
| 241 |
$dbo->setQuery($q); |
| 242 |
$cdata = $dbo->loadAssocList(); |
| 243 |
|
| 244 |
foreach ($cdata as $cd) { |
| 245 |
$this->countries[$cd['country_2_code']] = $cd['country_name']; |
| 246 |
} |
| 247 |
|
| 248 |
return $this->countries; |
| 249 |
} |
| 250 |
|
| 251 |
/** |
| 252 |
* Returns the report base path. |
| 253 |
* |
| 254 |
* @return string the base path for the reports. |
| 255 |
*/ |
| 256 |
private function getReportBasePath() |
| 257 |
{ |
| 258 |
return VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'report' . DIRECTORY_SEPARATOR; |
| 259 |
} |
| 260 |
} |
| 261 |
|