PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
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 1.7.3 All 36 releases
vikbooking / admin / helpers / src / checkin / adapter.php

adapter.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/helpers/src/checkin/adapter.php

457 lines 13.0 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 core
5 * @author Alessio Gaggii - E4J s.r.l.
6 * @copyright Copyright (C) 2022 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 * Defines an abstract adapter to extend the pax data collection.
16 *
17 * @since 1.15.0 (J) - 1.5.0 (WP)
18 */
19 abstract class VBOCheckinAdapter implements VBOCheckinPaxfields
20 {
21 /**
22 * The ID of the pax data collector class.
23 *
24 * @var string
25 */
26 protected $collector_id = '';
27
28 /**
29 * Default pax fields MRZ type map.
30 *
31 * @var VBOCheckinPaxfieldsMrzMap
32 */
33 protected $mrzFieldsMapper = null;
34
35 /**
36 * Class constructor will define internal properties.
37 *
38 * @since 1.18.6 (J) - 1.8.6 (WP)
39 */
40 public function __construct()
41 {
42 // get pax data collector base class name
43 $collector_base_class = preg_replace('/^VBOCheckinPaxfields/i', '', strtolower(get_class($this))) ?: 'basic';
44
45 // build expected pax fields MRZ type map class name
46 $pax_mrz_class = 'VBOCheckinPaxfieldsMrzMap' . ucfirst($collector_base_class);
47
48 // define current pax fields MRZ type map
49 if (class_exists($pax_mrz_class)) {
50 // pax data collector provides a dedicated MRZ type map
51 $this->mrzFieldsMapper = new $pax_mrz_class($this->collector_id, $this->listFields());
52 } else {
53 // use the default (basic) MRZ type map
54 $this->mrzFieldsMapper = new VBOCheckinPaxfieldsMrzMapBasic($this->collector_id, $this->listFields());
55 }
56 }
57
58 /**
59 * Tells whether children should be registered.
60 * Children registration is disabled by default.
61 *
62 * @param bool $precheckin true if requested for front-end pre check-in.
63 *
64 * @return bool true to also register the children.
65 *
66 * @since 1.16.3 (J) - 1.6.3 (WP) added $precheckin argument.
67 */
68 public function registerChildren($precheckin = false)
69 {
70 // disabled by default, unless method gets overridden
71 return false;
72 }
73
74 /**
75 * Tells whether the check-in driver supports MRZ detection
76 * for the uploaded guest documents (Machine Readable Zone).
77 *
78 * @return bool True if MRZ is supported, or false.
79 *
80 * @since 1.18.6 (J) - 1.8.6 (WP)
81 */
82 public function supportsMRZDetection()
83 {
84 static $mrzSupportChecked = null;
85
86 if ($mrzSupportChecked !== null) {
87 // use the cached support check
88 return (bool) $mrzSupportChecked;
89 }
90
91 // enabled by default, only if the Channel Manager is installed with active AI support
92 $mrzSupportChecked = class_exists('VikChannelManager') &&
93 defined('VikChannelManagerConfig::AI') &&
94 VikChannelManager::getChannel(VikChannelManagerConfig::AI);
95
96 // return the support value
97 return $mrzSupportChecked;
98 }
99
100 /**
101 * Returns the current pax fields MRZ mapper.
102 *
103 * @return VBOCheckinPaxfieldsMrzMap
104 *
105 * @since 1.18.6 (J) - 1.8.6 (WP)
106 */
107 public function getMRZMapper()
108 {
109 return $this->mrzFieldsMapper;
110 }
111
112 /**
113 * Returns the instance of the given pax field key.
114 *
115 * @param string $key the field key identifier.
116 *
117 * @return VBOCheckinPaxfield the requested pax field object.
118 */
119 public function getField($key)
120 {
121 // get all the existing field attributes
122 $attributes = $this->getAttributes();
123
124 // create a new instance of the field registry object
125 $pax_field = new VBOCheckinPaxfield();
126
127 // inject key and type of field
128 $field_type = (isset($attributes[$key]) ? $attributes[$key] : 'text');
129 $pax_field->setKey($key);
130 $pax_field->setType($field_type);
131
132 // return the field registry object
133 return $pax_field;
134 }
135
136 /**
137 * Attempts to find the first field attribute key from the given type.
138 *
139 * @param string $type The type of pax field.
140 *
141 * @return string Empty string or first field attribute key found for this type.
142 *
143 * @since 1.18.0 (J) - 1.8.0 (WP)
144 */
145 public function getFieldTypeKey(string $type)
146 {
147 // get all the existing field attributes
148 $attributes = $this->getAttributes();
149
150 if (!in_array($type, $attributes)) {
151 // unknown pax field type
152 return '';
153 }
154
155 // search for the pax field key from the given type
156 $key = array_search($type, $attributes);
157
158 if ($key === false) {
159 // pax field type not found
160 return '';
161 }
162
163 return (string) $key;
164 }
165
166 /**
167 * Renders a specific pax field type.
168 *
169 * @param VBOCheckinPaxfield $field the pax field object to render.
170 *
171 * @return string the HTML string to display the field.
172 */
173 public function render(VBOCheckinPaxfield $field)
174 {
175 // get the field implementor
176 $implementor = $this->getFieldTypeImplementor($field);
177
178 if ($implementor === null) {
179 // could not access the implementor
180 return '';
181 }
182
183 // let the handler render the field
184 return $implementor->render();
185 }
186
187 /**
188 * Attempts to return an instance of the field-type implementor object being parsed.
189 *
190 * @param VBOCheckinPaxfield $field the pax field object to render.
191 *
192 * @return null|object the field implementor class of VBOCheckinPaxfieldType or null.
193 */
194 public function getFieldTypeImplementor(VBOCheckinPaxfield $field)
195 {
196 // get the type of field to render
197 $field_type = $field->getType();
198
199 if ($field_type === null) {
200 return null;
201 }
202
203 if (is_array($field_type)) {
204 // convert field type to "select" string
205 $field_type = 'select';
206 }
207
208 if (!is_string($field_type)) {
209 // invalid field type
210 return null;
211 }
212
213 // compose dinamically the implementor class name
214 $field_class = $this->getFieldTypeClass($field_type);
215
216 if (!$field_class || !class_exists($field_class)) {
217 // no implementor handler found for this type of field
218 return null;
219 }
220
221 // return the field handler by passing the pax field object and the data collector id
222 return new $field_class($field, $this->collector_id);
223 }
224
225 /**
226 * Builds the list of back-end pax fields for the extended collection type.
227 *
228 * @return array the list of pax fields to collect in the back-end.
229 */
230 public function listFields()
231 {
232 return [$this->getLabels(), $this->getAttributes()];
233 }
234
235 /**
236 * Builds the list of front-end (pre-checkin) pax fields for the extended collection type.
237 * Check-in pax fields data collector implementations may override this method, if needed.
238 *
239 * @param array $def_fields list of default pre-checkin field labels and attributes.
240 *
241 * @return array the list of pax fields to collect in the front-end during pre-checkin.
242 *
243 * @since 1.17.2 (J) - 1.7.2 (WP)
244 */
245 public function listPrecheckinFields(array $def_fields)
246 {
247 // return no labels, nor attributes by default
248 return [
249 [],
250 [],
251 ];
252 }
253
254 /**
255 * Invokes a callback for the extended collection type after the pre-checkin
256 * information have been stored or updated to perform certain actions.
257 *
258 * @param array $data the guest registration data stored.
259 * @param array $booking the booking record involved with the guests registration.
260 * @param array $customer optional customer record associated with the booking.
261 *
262 * @return void
263 *
264 * @since 1.17.5 (J) - 1.7.5 (WP)
265 */
266 public function onPrecheckinDataStored(array $data, array $booking, array $customer)
267 {
268 // no actions to be performed by default
269 return;
270 }
271
272 /**
273 * Performs a validation over the guest registration field types for a given reservation.
274 * Those responsible for storing the pre-check-in information should call this method first,
275 * which will invoke the validation method over every registration field type, and then the
276 * driver validation will be automatically called to verify the data submitted.
277 *
278 * @param array $booking The booking record involved with the guests registration.
279 * @param array $booking_rooms The booking room records involved with the guests registration.
280 * @param array $data The guests registration data to validate.
281 * @param bool $precheckin True if validating pre-checkin fields.
282 *
283 * @return void
284 *
285 * @throws Exception
286 *
287 * @uses validateRegistrationFields()
288 *
289 * @since 1.18.0 (J) - 1.8.0 (WP)
290 */
291 public function validateRegistrationFieldTypes(array $booking, array $booking_rooms, array $data, bool $precheckin = true)
292 {
293 // first off, let the driver perform the validation over the field contents submitted to ensure mandatory values are set
294 $this->validateRegistrationFields($booking, $booking_rooms, $data, $precheckin);
295
296 // get the current driver's attributes
297 $supported_attributes = $this->getAttributes();
298
299 // iterate over all rooms booked to identify the custom registration field types
300 foreach ($booking_rooms as $index => $booking_room) {
301 // count expected room registration guests data
302 $room_adults = $booking_room['adults'] ?? 1;
303 $room_children = $booking_room['children'] ?? 0;
304 $room_guests = $this->registerChildren($precheckin) ? ($room_adults + $room_children) : $room_adults;
305
306 // scan room guests for the expected room guest registration data
307 for ($g = 1; $g <= $room_guests; $g++) {
308 if (!is_array(($data[$index][$g] ?? null))) {
309 // no registration data available for this room and guest
310 continue;
311 }
312
313 // iterate over the registration fields
314 foreach ($supported_attributes as $field_type) {
315 if (!is_string($field_type) || !$this->isCustomFieldType($field_type)) {
316 // known field types will not be invoked for triggering a custom validation
317 continue;
318 }
319
320 // find the first pax field key from the given type
321 $pax_field_key = $this->getFieldTypeKey($field_type);
322
323 if (!$pax_field_key) {
324 // unknown pax field type
325 continue;
326 }
327
328 // get an instance of the VBOCheckinPaxfield object
329 $pax_field_obj = $this->getField($pax_field_key);
330
331 // detect the current type of guest
332 $guest_type = $g > $room_adults ? 'child' : 'adult';
333
334 // set object data
335 $pax_field_obj->setGuestType($guest_type)
336 ->setGuestNumber($g)
337 ->setGuestData($data[$index][$g])
338 ->setRoomIndex($index)
339 ->setBooking($booking)
340 ->setBookingRooms($booking_rooms)
341 ->setRoomGuests($room_adults, $room_children)
342 ->setTotalRooms(count($booking_rooms));
343
344 // get the field implementor
345 if ($implementor = $this->getFieldTypeImplementor($pax_field_obj)) {
346 // invoke the registration data validation on the field implementor
347 $implementor->validateGuestRegistrationData();
348 }
349 }
350 }
351 }
352
353 // all good
354 return;
355 }
356
357 /**
358 * Performs a validation over the guest registration fields data for a given reservation.
359 * Custom drivers can override this method to implement their own validation method.
360 *
361 * @param array $booking The booking record involved with the guests registration.
362 * @param array $booking_rooms The booking room records involved with the guests registration.
363 * @param array $data The guests registration data to validate.
364 * @param bool $precheckin True if validating pre-checkin fields.
365 *
366 * @return void
367 *
368 * @throws Exception
369 *
370 * @see validateRegistrationFieldTypes()
371 *
372 * @since 1.17.7 (J) - 1.7.7 (WP)
373 */
374 public function validateRegistrationFields(array $booking, array $booking_rooms, array $data, bool $precheckin = true)
375 {
376 // no guest fields data validation performed by default
377 return;
378 }
379
380 /**
381 * Tells whether the given field attribute typr correspond to a custom paxfield type.
382 *
383 * @param string $type The field attribute type.
384 *
385 * @return bool True if this is a custom field type.
386 *
387 * @since 1.18.0 (J) - 1.8.0 (WP)
388 */
389 protected function isCustomFieldType(string $type)
390 {
391 // get the current driver's attributes
392 $supported_attributes = $this->getAttributes();
393
394 if (!in_array($type, $supported_attributes)) {
395 // unknown attribute type for this driver
396 return false;
397 }
398
399 // declare the known field types that will not require a validation at field-object level
400 $known_types = [
401 'calendar',
402 'country',
403 'file',
404 'number',
405 'select',
406 'text',
407 'textarea',
408 ];
409
410 return !in_array($type, $known_types);
411 }
412
413 /**
414 * Composes the field type class name given its type-string.
415 *
416 * @param string $field_type the field type-string identifier.
417 *
418 * @return bool|string the class name to use for the field, or false.
419 */
420 protected function getFieldTypeClass($field_type)
421 {
422 if (!is_string($field_type) || empty($field_type)) {
423 return false;
424 }
425
426 // base class name
427 $base_paxf_class = 'VBOCheckinPaxfieldType';
428
429 // compose field type class name
430 $field_type = ucwords(str_replace(array('_', '-'), ' ', $field_type));
431 $field_type = preg_replace("/[^a-zA-Z0-9]/", '', $field_type);
432
433 return $base_paxf_class . $field_type;
434 }
435
436 /**
437 * Returns the name of the current pax data driver.
438 *
439 * @return string the name of the driver.
440 */
441 abstract public function getName();
442
443 /**
444 * Builds the list pax fields labels.
445 *
446 * @return array the list of pax fields labels.
447 */
448 abstract public function getLabels();
449
450 /**
451 * Builds the list pax fields attributes.
452 *
453 * @return array the list of pax fields attributes.
454 */
455 abstract public function getAttributes();
456 }
457