PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.4
VikBooking Hotel Booking Engine & PMS v1.6.4
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / helpers / einvoicing / einvoicing.php

einvoicing.php in VikBooking Hotel Booking Engine & PMS 1.6.4, at admin/helpers/einvoicing/einvoicing.php

966 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 /**
14 * eInvoicing parent Class of all sub-classes
15 */
16 abstract class VikBookingEInvoicing
17 {
18 protected $driverFile = '';
19 protected $driverName = '';
20 protected $driverId = null;
21 protected $driverFilters = array();
22 protected $driverButtons = array();
23 protected $driverScript = '';
24 protected $hasSettings = false;
25 protected $warning = [];
26 protected $error = [];
27 protected $info = [];
28 protected $dbo;
29 protected $session;
30
31 protected $cols = array();
32 protected $rows = array();
33 protected $footerRow = array();
34
35 /**
36 * @var mixed flag modifiable by external invokes (cron, analogic invoices)
37 */
38 public $externalCall = null;
39
40 /**
41 * @var array data injectable by external callers
42 */
43 public $externalData = array();
44
45 /**
46 * Class constructors should define some vars of the driver in use.
47 */
48 public function __construct() {
49 $this->dbo = JFactory::getDbo();
50 $this->session = JFactory::getSession();
51
52 /**
53 * Turn on the flag that the eInvocing class is running
54 * so that other parts of the framework can avoid to
55 * invoke again this class and to generate double e-invoices.
56 */
57 defined('VBO_EINVOICING_RUN') OR define('VBO_EINVOICING_RUN', 1);
58 }
59
60 /**
61 * Extending Classes should define this method
62 * to get the name of class file.
63 */
64 abstract public function getFileName();
65
66 /**
67 * Extending Classes should define this method
68 * to get the name of the driver.
69 */
70 abstract public function getName();
71
72 /**
73 * Extending Classes should define this method
74 * to get the filters of the driver.
75 */
76 abstract public function getFilters();
77
78 /**
79 * Extending Classes should define this method
80 * to get the driver action buttons.
81 */
82 abstract public function getButtons();
83
84 /**
85 * Extending Classes should define this method
86 * to generate the bookings data (cols and rows).
87 */
88 abstract public function getBookingsData();
89
90 /**
91 * Extending Classes should define this method
92 * to prepare the settings of the driver before saving.
93 * Views should not call this method.
94 */
95 abstract protected function prepareSavingSettings();
96
97 /**
98 * Extending Classes should define this method
99 * to generate the electronic invoices.
100 */
101 abstract public function generateEInvoices();
102
103 /**
104 * Extending Classes should define this method
105 * to generate the electronic invoice for
106 * the given booking ID or booking array.
107 */
108 abstract public function generateEInvoice($data);
109
110 /**
111 * Extending Classes should define this method
112 * to generate the electronic invoice from a custom
113 * invoice not related to any booking ID.
114 * Existing (analogic) invoice record and customer
115 * shall be passed as arguments.
116 */
117 abstract public function prepareCustomInvoiceData($invoice, $customer);
118
119 /**
120 * Extending Classes should define this method
121 * to check if an electronic invoice exists for
122 * a given booking ID or Number. This is useful
123 * for external scripts to request later the
124 * obliteration of the invoice to create a new one.
125 * For example, during the update of a custom invoice.
126 */
127 abstract public function eInvoiceExists($data);
128
129 /**
130 * Extending Classes should define this method
131 * to obliterate an existingelectronic invoice.
132 * This is useful for external scripts to request the
133 * obliteration of the invoice to create a new one.
134 * For example, during the update of a custom invoice.
135 */
136 abstract public function obliterateEInvoice($data);
137
138 /**
139 * Loads the settings for the driver, which parameters
140 * must be saved as a JSON encoded string. Never cache
141 * the settings fetched as they may be updated by other methods.
142 *
143 * @return mixed array if settings exist, false otherwise
144 */
145 protected function loadSettings()
146 {
147 $q = "SELECT * FROM `#__vikbooking_einvoicing_config` WHERE `driver`=".$this->dbo->quote($this->getFileName())." ORDER BY `id` DESC LIMIT 1;";
148 $this->dbo->setQuery($q);
149 $this->dbo->execute();
150 if (!$this->dbo->getNumRows()) {
151 // no settings defined for this driver
152 return false;
153 }
154 $settings = $this->dbo->loadAssoc();
155 $settings['params'] = !empty($settings['params']) ? json_decode($settings['params'], true) : array();
156 $settings['params'] = is_array($settings['params']) ? $settings['params'] : array();
157
158 // update driverId
159 $this->driverId = $settings['id'];
160
161 // return array of settings with decoded parameters
162 return $settings;
163 }
164
165 /**
166 * Saves the settings for the driver.
167 * The View may call this method to save the driver settings.
168 *
169 * @return boolean true if settings were stored, false otherwise
170 */
171 public function saveSettings()
172 {
173 $data = $this->prepareSavingSettings();
174 if (!$data instanceof stdClass || !count(get_object_vars($data))) {
175 return false;
176 }
177
178 $q = "SELECT * FROM `#__vikbooking_einvoicing_config` WHERE `driver`=".$this->dbo->quote($this->getFileName())." ORDER BY `id` DESC LIMIT 1;";
179 $this->dbo->setQuery($q);
180 $this->dbo->execute();
181 if (!$this->dbo->getNumRows()) {
182 // create new driver record as it's the first time we're saving the settings
183 if (!$this->dbo->insertObject('#__vikbooking_einvoicing_config', $data, 'id')) {
184 return false;
185 }
186 } else {
187 // update the driver record with the new settings
188 $current = $this->dbo->loadAssoc();
189 $data->id = $current['id'];
190 if (!$this->dbo->updateObject('#__vikbooking_einvoicing_config', $data, 'id')) {
191 return false;
192 }
193 }
194
195 $this->setInfo(JText::translate('VBODRIVERSETTSUPD'));
196
197 return true;
198 }
199
200 /**
201 * Returns whether the driver has settings to be defined.
202 *
203 * @return boolean
204 */
205 public function hasSettings()
206 {
207 return $this->hasSettings;
208 }
209
210 /**
211 * Echoes the HTML required for the driver settings form.
212 * This method should be extended by the driver if settings are needed.
213 *
214 * @return void
215 */
216 public function printSettings()
217 {
218 return;
219 }
220
221 /**
222 * Echoes the HTML required for the driver overlay form.
223 * This method should be extended by the driver if needed.
224 * For example, to show contents within a modal.
225 *
226 * @return void
227 */
228 public function printOverlayContent()
229 {
230 return;
231 }
232
233 /**
234 * Returns the ID of the current driver by taking it from the settings.
235 * By calling loadSettings(), if some settings are defined, the ID is set in driverId.
236 *
237 * @return mixed the ID of the current driver if some settings were stored or null.
238 *
239 * @uses loadSettings
240 */
241 protected function getDriverId()
242 {
243 if (is_null($this->driverId)) {
244 // this method will set a value for the property driverId if some settings were saved
245 $this->loadSettings();
246 }
247
248 return $this->driverId;
249 }
250
251 /**
252 * Stores an electronic invoice. If the booking ID is passed through the data
253 * the system will set to obliterated all e-invoices previously made for that booking.
254 * Custom (manual) invoices should be obliterated by the external caller script instead.
255 *
256 * @param object $data stdClass object with the data to store
257 *
258 * @return mixed the ID of the invoice stored, false otherwise
259 */
260 protected function storeEInvoice($data)
261 {
262 if (!$data instanceof stdClass || !count(get_object_vars($data))) {
263 return false;
264 }
265
266 if (isset($data->idorder) && (int)$data->idorder > 0) {
267 // obliterate any possible previous e-invoice for this booking
268 $q = "UPDATE `#__vikbooking_einvoicing_data` SET `obliterated`=1 WHERE `driverid`=".(int)$this->driverId." AND `idorder`=".(int)$data->idorder.";";
269 $this->dbo->setQuery($q);
270 $this->dbo->execute();
271 }
272
273 if ($this->dbo->insertObject('#__vikbooking_einvoicing_data', $data, 'id')) {
274 return $data->id;
275 }
276
277 return false;
278 }
279
280 /**
281 * Updates the information for an electronic invoice.
282 *
283 * @param object $data stdClass object with the data to store
284 *
285 * @return boolean
286 */
287 protected function updateEInvoice($data)
288 {
289 if (!$data instanceof stdClass || !count(get_object_vars($data))) {
290 return false;
291 }
292
293 if ($this->dbo->updateObject('#__vikbooking_einvoicing_data', $data, 'id')) {
294 return true;
295 }
296
297 return false;
298 }
299
300 /**
301 * Checks whether an analogic invoice in PDF was already issued
302 * for the given booking ID. This is to avoid double PDF invoices.
303 *
304 * @param int $idorder the ID of the booking
305 *
306 * @return boolean
307 */
308 protected function hasAnalogicInvoice($idorder)
309 {
310 if (empty($idorder)) {
311 return false;
312 }
313
314 $q = "SELECT `id` FROM `#__vikbooking_invoices` WHERE `idorder`=".(int)$idorder.";";
315 $this->dbo->setQuery($q);
316 $this->dbo->execute();
317 if ($this->dbo->getNumRows()) {
318 return true;
319 }
320
321 return false;
322 }
323
324 /**
325 * Generates an analogic invoice in PDF format for the given booking ID.
326 *
327 * @param int $idorder the ID of the booking.
328 * @param int $invnum the number of the invoice.
329 * @param string $invdate the date for the invoice in Y-m-d format.
330 *
331 * @return boolean
332 */
333 protected function generateAnalogicInvoice($idorder, $invnum, $invdate)
334 {
335 if (empty($idorder)) {
336 return false;
337 }
338
339 // get booking record
340 $booking = array();
341 $q = "SELECT `o`.*,`co`.`idcustomer`,CONCAT_WS(' ',`c`.`first_name`,`c`.`last_name`) AS `customer_name`,`c`.`pin` AS `customer_pin`,`nat`.`country_name` FROM `#__vikbooking_orders` AS `o` LEFT JOIN `#__vikbooking_customers_orders` `co` ON `co`.`idorder`=`o`.`id` LEFT JOIN `#__vikbooking_customers` `c` ON `c`.`id`=`co`.`idcustomer` LEFT JOIN `#__vikbooking_countries` `nat` ON `nat`.`country_3_code`=`o`.`country` WHERE `o`.`id`=".(int)$idorder." AND `o`.`status`='confirmed' AND `o`.`total` > 0;";
342 $this->dbo->setQuery($q);
343 $this->dbo->execute();
344 if ($this->dbo->getNumRows() > 0) {
345 $booking = $this->dbo->loadAssoc();
346 }
347
348 if (!count($booking)) {
349 return false;
350 }
351
352 try {
353 $res = VikBooking::generateBookingInvoice($booking, $invnum, '', date($this->getDateFormat(), strtotime($invdate)));
354 } catch (Exception $e) {
355 return false;
356 }
357
358 return $res;
359 }
360
361 /**
362 * Loads an helper file to obtain HTML content within a buffer.
363 *
364 * @param string the path to the layout/helper file to include
365 * @param array the vars needed by the layout/helper file
366 *
367 * @return string the HTML content to print, or an empty string
368 */
369 protected function loadHelperFile($fpath, $data = array())
370 {
371 if (!is_file($fpath)) {
372 return '';
373 }
374
375 // capture the content of the layout/helper file within a buffer
376 ob_start();
377 include $fpath;
378 $content = ob_get_contents();
379 ob_end_clean();
380
381 // return the content to be displayed
382 return $content;
383 }
384
385 /**
386 * Requires an helper file.
387 *
388 * @return void
389 */
390 protected function importHelper($fpath)
391 {
392 if (!is_file($fpath)) {
393 return;
394 }
395
396 require_once $fpath;
397 }
398
399 /**
400 * Returns whether the driver has some session filters to
401 * immediately call getBookingsData() when the page loads.
402 * Child classes could override this method depending on the needs.
403 *
404 * @return boolean
405 */
406 public function hasFiltersSet()
407 {
408 return false;
409 }
410
411 /**
412 * Loads the jQuery UI Datepicker.
413 * Method used only by sub-classes.
414 *
415 * @return self
416 */
417 protected function loadDatePicker()
418 {
419 $vbo_app = VikBooking::getVboApplication();
420 $vbo_app->loadDatePicker();
421
422 return $this;
423 }
424
425 /**
426 * Loads all the rooms in VBO and returns the array.
427 *
428 * @return array associative array with key=ID value=data
429 */
430 protected function getRooms()
431 {
432 $rooms = array();
433 $q = "SELECT * FROM `#__vikbooking_rooms` ORDER BY `name` ASC;";
434 $this->dbo->setQuery($q);
435 $this->dbo->execute();
436 if ($this->dbo->getNumRows() > 0) {
437 $all = $this->dbo->loadAssocList();
438 foreach ($all as $r) {
439 $rooms[$r['id']] = $r;
440 }
441 }
442
443 return $rooms;
444 }
445
446 /**
447 * Concatenates the JavaScript rules.
448 * Method used only by sub-classes.
449 *
450 * @param string $str
451 *
452 * @return self
453 */
454 protected function setScript($str)
455 {
456 $this->driverScript .= $str."\n";
457
458 return $this;
459 }
460
461 /**
462 * Returns the aliquote number from the given record ID.
463 *
464 * @param int $idvat the ID of the IVA record
465 *
466 * @return float the aliquot found or 0
467 */
468 protected function getAliquoteById($idvat)
469 {
470 $aliq = 0;
471
472 if (!empty($idvat)) {
473 $q = "SELECT `aliq` FROM `#__vikbooking_iva` WHERE `id`=".(int)$idvat.";";
474 $this->dbo->setQuery($q);
475 $this->dbo->execute();
476 if ($this->dbo->getNumRows()) {
477 $aliq = $this->dbo->loadResult();
478 }
479 }
480
481 return floatval($aliq);
482 }
483
484 /**
485 * Returns the aliquote number from the given price ID.
486 *
487 * @param int $idvat the ID of the IVA record
488 *
489 * @return float the aliquot found or 0
490 */
491 protected function getAliquoteFromPriceId($idprice)
492 {
493 $aliq = 0;
494
495 if (!empty($idprice)) {
496 $q = "SELECT `p`.`idiva`,`i`.`aliq` FROM `#__vikbooking_prices` AS `p` LEFT JOIN `#__vikbooking_iva` `i` ON `i`.`id`=`p`.`idiva` WHERE `p`.`id`=".(int)$idprice.";";
497 $this->dbo->setQuery($q);
498 $this->dbo->execute();
499 if ($this->dbo->getNumRows()) {
500 $data = $this->dbo->loadAssoc();
501 $aliq = $data['aliq'];
502 }
503 }
504
505 return floatval($aliq);
506 }
507
508 /**
509 * Updates the current invoice number for later use.
510 *
511 * @param int $invnum the invoice number to set
512 *
513 * @return void
514 */
515 protected function updateInvoiceNumber($invnum)
516 {
517 $q = "UPDATE `#__vikbooking_config` SET `setting`=".$this->dbo->quote((int)$invnum)." WHERE `param`='invoiceinum';";
518 $this->dbo->setQuery($q);
519 $this->dbo->execute();
520 }
521
522 /**
523 * Updates the progrssive number for the data transmission for this driver.
524 *
525 * @param int $num the prograssive number to set (should be already increased)
526 *
527 * @return void
528 */
529 protected function updateProgressiveNumber($num)
530 {
531 $q = "UPDATE `#__vikbooking_einvoicing_config` SET `progcount`=".(int)$num." WHERE `driver`=".$this->dbo->quote($this->getFileName()).";";
532 $this->dbo->setQuery($q);
533 $this->dbo->execute();
534 }
535
536 /**
537 * Attempts to format the given XML string through DOMDocument.
538 * This method takes the XML string by reference.
539 *
540 * @param string $xml the XML string to be formatted
541 *
542 * @return string the formatted string or the original string
543 */
544 protected function formatXmlString(&$xml)
545 {
546 if (!class_exists('DOMDocument')) {
547 // we cannot format the XML because DOMDocument is missing
548 return $xml;
549 }
550
551 $dom = new DOMDocument;
552 $dom->preserveWhiteSpace = false;
553 $dom->loadXML($xml);
554 $dom->formatOutput = true;
555 $xml = $dom->saveXML();
556
557 return $xml;
558 }
559
560 /**
561 * Returns whether the debug request has been set.
562 *
563 * @return boolean
564 */
565 protected function debugging()
566 {
567 $debug = VikRequest::getInt('e4j_debug', 0, 'request');
568
569 return $debug;
570 }
571
572 /**
573 * Gets the current script string.
574 *
575 * @return string
576 */
577 public function getScript()
578 {
579 return rtrim($this->driverScript, "\n");
580 }
581
582 /**
583 * Returns the date format in VBO for date, jQuery UI, Joomla.
584 * Method used only by sub-classes.
585 *
586 * @param string $type
587 *
588 * @return string
589 */
590 protected function getDateFormat($type = 'date')
591 {
592 $nowdf = VikBooking::getDateFormat();
593 if ($nowdf == "%d/%m/%Y") {
594 $df = 'd/m/Y';
595 $juidf = 'dd/mm/yy';
596 } elseif ($nowdf == "%m/%d/%Y") {
597 $df = 'm/d/Y';
598 $juidf = 'mm/dd/yy';
599 } else {
600 $df = 'Y/m/d';
601 $juidf = 'yy/mm/dd';
602 }
603
604 switch ($type) {
605 case 'jui':
606 return $juidf;
607 case 'joomla':
608 return $nowdf;
609 default:
610 return $df;
611 }
612 }
613
614 /**
615 * Returns the translated weekday.
616 * Uses the back-end language definitions.
617 *
618 * @param int $wday
619 * @param string $type use 'long' for the full name of the week, short for the 3-char version
620 *
621 * @return string
622 */
623 protected function getWdayString($wday, $type = 'long')
624 {
625 $wdays_map_long = array(
626 JText::translate('VBWEEKDAYZERO'),
627 JText::translate('VBWEEKDAYONE'),
628 JText::translate('VBWEEKDAYTWO'),
629 JText::translate('VBWEEKDAYTHREE'),
630 JText::translate('VBWEEKDAYFOUR'),
631 JText::translate('VBWEEKDAYFIVE'),
632 JText::translate('VBWEEKDAYSIX')
633 );
634
635 $wdays_map_short = array(
636 JText::translate('VBSUN'),
637 JText::translate('VBMON'),
638 JText::translate('VBTUE'),
639 JText::translate('VBWED'),
640 JText::translate('VBTHU'),
641 JText::translate('VBFRI'),
642 JText::translate('VBSAT')
643 );
644
645 if ($type != 'long') {
646 return isset($wdays_map_short[(int)$wday]) ? $wdays_map_short[(int)$wday] : '';
647 }
648
649 return isset($wdays_map_long[(int)$wday]) ? $wdays_map_long[(int)$wday] : '';
650 }
651
652 /**
653 * Returns the translated month.
654 * Uses the back-end language definitions.
655 *
656 * @param int $month the month to convert (from 1 to 12)
657 *
658 * @return string
659 */
660 protected function getMonthString($mon)
661 {
662 $mon--;
663
664 $months_map_long = array(
665 JText::translate('VBMONTHONE'),
666 JText::translate('VBMONTHTWO'),
667 JText::translate('VBMONTHTHREE'),
668 JText::translate('VBMONTHFOUR'),
669 JText::translate('VBMONTHFIVE'),
670 JText::translate('VBMONTHSIX'),
671 JText::translate('VBMONTHSEVEN'),
672 JText::translate('VBMONTHEIGHT'),
673 JText::translate('VBMONTHNINE'),
674 JText::translate('VBMONTHTEN'),
675 JText::translate('VBMONTHELEVEN'),
676 JText::translate('VBMONTHTWELVE')
677 );
678
679 return isset($months_map_long[(int)$mon]) ? $months_map_long[(int)$mon] : '';
680 }
681
682 /**
683 * Replaces accents and special characters to their non-special version.
684 * Takes also rid of the ampersand symbol that would break the XML.
685 *
686 * @param string $string the string to parse
687 *
688 * @return string
689 */
690 protected function convertSpecials($string)
691 {
692 // map of special characters
693 $table = array(
694 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', '�
695 '=>'A', 'Ă'=>'A', 'Ā'=>'A', 'Ą'=>'A', 'Æ'=>'A', 'Ǽ'=>'A',
696 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'ă'=>'a', 'ā'=>'a', '�
697 '=>'a', 'æ'=>'a', 'ǽ'=>'a',
698
699 'Þ'=>'B', 'þ'=>'b', 'ß'=>'Ss',
700
701 'Ç'=>'C', 'Č'=>'C', 'Ć'=>'C', 'Ĉ'=>'C', 'Ċ'=>'C',
702 'ç'=>'c', 'č'=>'c', 'ć'=>'c', 'ĉ'=>'c', 'ċ'=>'c',
703
704 'Đ'=>'Dj', 'Ď'=>'D',
705 'đ'=>'dj', 'ď'=>'d',
706
707 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ĕ'=>'E', 'Ē'=>'E', 'Ę'=>'E', 'Ė'=>'E',
708 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ĕ'=>'e', 'ē'=>'e', 'ę'=>'e', 'ė'=>'e',
709
710 'Ĝ'=>'G', 'Ğ'=>'G', 'Ġ'=>'G', 'Ģ'=>'G',
711 'ĝ'=>'g', 'ğ'=>'g', 'ġ'=>'g', 'ģ'=>'g',
712
713 'Ĥ'=>'H', 'Ħ'=>'H',
714 'ĥ'=>'h', 'ħ'=>'h',
715
716 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'İ'=>'I', 'Ĩ'=>'I', 'Ī'=>'I', 'Ĭ'=>'I', 'Į'=>'I',
717 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'į'=>'i', 'ĩ'=>'i', 'ī'=>'i', 'ĭ'=>'i', 'ı'=>'i',
718
719 'Ĵ'=>'J',
720 'ĵ'=>'j',
721
722 'Ķ'=>'K',
723 'ķ'=>'k', 'ĸ'=>'k',
724
725 'Ĺ'=>'L', 'Ļ'=>'L', 'Ľ'=>'L', 'Ŀ'=>'L', 'Ł'=>'L',
726 'ĺ'=>'l', 'ļ'=>'l', 'ľ'=>'l', 'ŀ'=>'l', 'ł'=>'l',
727
728 'Ñ'=>'N', 'Ń'=>'N', 'Ň'=>'N', '�
729 '=>'N', 'Ŋ'=>'N',
730 'ñ'=>'n', 'ń'=>'n', 'ň'=>'n', 'ņ'=>'n', 'ŋ'=>'n', 'ʼn'=>'n',
731
732 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ō'=>'O', 'Ŏ'=>'O', 'Ő'=>'O', 'Œ'=>'O',
733 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ō'=>'o', 'ŏ'=>'o', 'ő'=>'o', 'œ'=>'o', 'ð'=>'o',
734
735 'Ŕ'=>'R', 'Ř'=>'R',
736 'ŕ'=>'r', 'ř'=>'r', 'ŗ'=>'r',
737
738 'Š'=>'S', 'Ŝ'=>'S', 'Ś'=>'S', 'Ş'=>'S',
739 'š'=>'s', 'ŝ'=>'s', 'ś'=>'s', 'ş'=>'s',
740
741 'Ŧ'=>'T', 'Ţ'=>'T', 'Ť'=>'T',
742 'ŧ'=>'t', 'ţ'=>'t', 'ť'=>'t',
743
744 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ũ'=>'U', 'Ū'=>'U', 'Ŭ'=>'U', 'Ů'=>'U', 'Ű'=>'U', 'Ų'=>'U',
745 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ü'=>'u', 'ũ'=>'u', 'ū'=>'u', 'ŭ'=>'u', 'ů'=>'u', 'ű'=>'u', 'ų'=>'u',
746
747 'Ŵ'=>'W', 'Ẁ'=>'W', 'Ẃ'=>'W', 'Ẅ'=>'W',
748 'ŵ'=>'w', 'ẁ'=>'w', 'ẃ'=>'w', '�
749 '=>'w',
750
751 'Ý'=>'Y', 'Ÿ'=>'Y', 'Ŷ'=>'Y',
752 'ý'=>'y', 'ÿ'=>'y', 'ŷ'=>'y',
753
754 'Ž'=>'Z', 'Ź'=>'Z', 'Ż'=>'Z',
755 'ž'=>'z', 'ź'=>'z', 'ż'=>'z',
756 '+'=>'',
757 );
758
759 $string = strtr($string, $table);
760
761 $string = preg_replace("/[^\x9\xA\xD\x20-\x7F]/u", "", $string);
762
763 // replace ampersand
764 $string = str_replace('&', 'and', $string);
765 // convert to HTML entities for a safe XML content
766 $string = htmlentities($string);
767 // remove any ampersand added by htmlentities()
768 $string = str_replace('&', '', $string);
769
770 return $string;
771 }
772
773 /**
774 * Sets the columns for this driver.
775 *
776 * @param array $arr
777 *
778 * @return self
779 */
780 protected function setDriverCols($arr)
781 {
782 $this->cols = $arr;
783
784 return $this;
785 }
786
787 /**
788 * Returns the columns for this driver.
789 * Should be called after getBookingsData()
790 * or the returned array will be empty.
791 *
792 * @return array
793 */
794 public function getDriverCols()
795 {
796 return $this->cols;
797 }
798
799 /**
800 * Sorts the rows of the driver by key.
801 *
802 * @param string $krsort the key attribute of the array pairs
803 * @param string $krorder ascending (ASC) or descending (DESC)
804 *
805 * @return void
806 */
807 protected function sortRows($krsort, $krorder)
808 {
809 if (empty($krsort) || !(count($this->rows))) {
810 return;
811 }
812
813 $map = array();
814 foreach ($this->rows as $k => $row) {
815 foreach ($row as $kk => $v) {
816 if (isset($v['key']) && $v['key'] == $krsort) {
817 $map[$k] = $v['value'];
818 }
819 }
820 }
821 if (!(count($map))) {
822 return;
823 }
824
825 if ($krorder == 'ASC') {
826 asort($map);
827 } else {
828 arsort($map);
829 }
830
831 $sorted = array();
832 foreach ($map as $k => $v) {
833 $sorted[$k] = $this->rows[$k];
834 }
835
836 $this->rows = $sorted;
837 }
838
839 /**
840 * Sets the rows for this driver.
841 *
842 * @param array $arr
843 *
844 * @return self
845 */
846 protected function setDriverRows($arr)
847 {
848 $this->rows = $arr;
849
850 return $this;
851 }
852
853 /**
854 * Returns the rows for this driver.
855 * Should be called after getBookingsData()
856 * or the returned array will be empty.
857 *
858 * @return array
859 */
860 public function getDriverRows()
861 {
862 return $this->rows;
863 }
864
865 /**
866 * Sets the footer row (the totals) for this driver.
867 *
868 * @param array $arr
869 *
870 * @return self
871 */
872 protected function setDriverFooterRow($arr)
873 {
874 $this->footerRow = $arr;
875
876 return $this;
877 }
878
879 /**
880 * Returns the footer row for this driver.
881 * Should be called after getBookingsData()
882 * or the returned array will be empty.
883 *
884 * @return array
885 */
886 public function getDriverFooterRow()
887 {
888 return $this->footerRow;
889 }
890
891 /**
892 * Sets warning messages by concatenating the existing ones.
893 * Method used only by sub-classes.
894 *
895 * @param string $str
896 *
897 * @return self
898 */
899 protected function setWarning($str)
900 {
901 $this->warning[] = $str;
902
903 return $this;
904 }
905
906 /**
907 * Gets the current warning string.
908 *
909 * @return string
910 */
911 public function getWarning()
912 {
913 return implode('<br/>', $this->warning);
914 }
915
916 /**
917 * Sets errors by concatenating the existing ones.
918 * Method used only by sub-classes.
919 *
920 * @param string $str
921 *
922 * @return self
923 */
924 protected function setError($str)
925 {
926 $this->error[] = $str;
927
928 return $this;
929 }
930
931 /**
932 * Gets the current error string.
933 *
934 * @return string
935 */
936 public function getError()
937 {
938 return implode('<br/>', $this->error);
939 }
940
941 /**
942 * Sets info messages by concatenating the existing ones.
943 * Method used only by sub-classes.
944 *
945 * @param string $str
946 *
947 * @return self
948 */
949 protected function setInfo($str)
950 {
951 $this->info[] = $str;
952
953 return $this;
954 }
955
956 /**
957 * Gets the current info string.
958 *
959 * @return string
960 */
961 public function getInfo()
962 {
963 return implode('<br/>', $this->info);
964 }
965 }
966