PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
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
← All changes | admin/helpers/src/checkin/adapter.php +456 -0 1.6.0 → 1.8.16 View file →
@@ -1,0 +1,456 @@
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 +}