PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.7
VikBooking Hotel Booking Engine & PMS v1.8.7
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 / src / dooraccess / integration / device.php

device.php in VikBooking Hotel Booking Engine & PMS 1.8.7, at admin/helpers/src/dooraccess/integration/device.php

656 lines 16.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 E4J s.r.l.
6 * @copyright Copyright (C) 2025 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 * Door Access integration device decorator. Such objects are
16 * serialized and stored onto the database as blobs.
17 *
18 * @since 1.18.4 (J) - 1.8.4 (WP)
19 */
20 final class VBODooraccessIntegrationDevice
21 {
22 /**
23 * @var array
24 */
25 protected array $payload = [];
26
27 /**
28 * @var array
29 */
30 protected array $connectedListings = [];
31
32 /**
33 * @var array
34 *
35 * @since 1.18.7 (J) - 1.8.7 (WP)
36 */
37 protected array $connectedSubunits = [];
38
39 /**
40 * @var array
41 */
42 protected array $capabilities = [];
43
44 /**
45 * @var ?string
46 */
47 protected ?string $identifier = null;
48
49 /**
50 * @var ?string
51 */
52 protected ?string $name = null;
53
54 /**
55 * @var ?string
56 */
57 protected ?string $description = null;
58
59 /**
60 * @var ?string
61 */
62 protected ?string $icon = null;
63
64 /**
65 * @var ?string
66 */
67 protected ?string $model = null;
68
69 /**
70 * @var ?float
71 */
72 protected ?float $batterylevel = null;
73
74 /**
75 * @var bool
76 */
77 protected bool $dataChanged = false;
78
79 /**
80 * Class constructor.
81 *
82 * @param array $payload The remote device raw payload.
83 */
84 public function __construct(array $payload)
85 {
86 // set device full payload
87 $this->setPayload($payload);
88 }
89
90 /**
91 * Gets the device identification value.
92 *
93 * @return ?string The device identification value.
94 */
95 public function getID()
96 {
97 return $this->identifier;
98 }
99
100 /**
101 * Sets the device identification value.
102 *
103 * @param string $id The identification value.
104 * @param bool $raw True to accept any value.
105 *
106 * @return self
107 *
108 * @since 1.18.7 (J) - 1.8.7 (WP) added argument $raw to support MAC addresses.
109 */
110 public function setID(string $id, bool $raw = false)
111 {
112 if (!$raw) {
113 // sanitize value
114 $id = preg_replace('/[^a-z0-9\-\_\.\|]/i', '', $id);
115 }
116
117 $this->identifier = $id;
118
119 return $this;
120 }
121
122 /**
123 * Gets the device name.
124 *
125 * @return ?string The device name.
126 */
127 public function getName()
128 {
129 return $this->name;
130 }
131
132 /**
133 * Sets the device name.
134 *
135 * @param string $name The device name.
136 *
137 * @return self
138 */
139 public function setName(string $name)
140 {
141 // set value
142 $this->name = $name;
143
144 // turn data-changed flag on
145 $this->setDataChanged(true);
146
147 return $this;
148 }
149
150 /**
151 * Gets the device description.
152 *
153 * @return ?string The device description.
154 */
155 public function getDescription()
156 {
157 return $this->description;
158 }
159
160 /**
161 * Sets the device description.
162 *
163 * @param string $description The device description.
164 *
165 * @return self
166 */
167 public function setDescription(string $description)
168 {
169 // set value
170 $this->description = $description;
171
172 // turn data-changed flag on
173 $this->setDataChanged(true);
174
175 return $this;
176 }
177
178 /**
179 * Gets the device icon (image URI or HTML icon).
180 *
181 * @return ?string The device icon.
182 */
183 public function getIcon()
184 {
185 return $this->icon;
186 }
187
188 /**
189 * Sets the device icon (image URI or HTML icon).
190 *
191 * @param string $icon The device icon.
192 *
193 * @return self
194 */
195 public function setIcon(string $icon)
196 {
197 $this->icon = $icon;
198
199 return $this;
200 }
201
202 /**
203 * Gets the device model.
204 *
205 * @return ?string The device model.
206 */
207 public function getModel()
208 {
209 return $this->model;
210 }
211
212 /**
213 * Sets the device model.
214 *
215 * @param string $model The device model.
216 *
217 * @return self
218 */
219 public function setModel(string $model)
220 {
221 // set value
222 $this->model = $model;
223
224 // turn data-changed flag on
225 $this->setDataChanged(true);
226
227 return $this;
228 }
229
230 /**
231 * Gets the device battery level.
232 *
233 * @return ?float The device battery level.
234 */
235 public function getBatteryLevel()
236 {
237 return $this->batterylevel;
238 }
239
240 /**
241 * Sets the device battery level.
242 *
243 * @param float $level The device battery level.
244 *
245 * @return self
246 */
247 public function setBatteryLevel(float $level)
248 {
249 // set value
250 $this->batterylevel = $level;
251
252 // turn data-changed flag on
253 $this->setDataChanged(true);
254
255 return $this;
256 }
257
258 /**
259 * Gets the device payload.
260 *
261 * @return array The device raw payload.
262 */
263 public function getPayload()
264 {
265 return $this->payload;
266 }
267
268 /**
269 * Sets the device payload.
270 *
271 * @param array $payload The device raw payload.
272 *
273 * @return self
274 */
275 public function setPayload(array $payload)
276 {
277 $this->payload = $payload;
278
279 return $this;
280 }
281
282 /**
283 * Whether data has changed on the device.
284 *
285 * @return bool
286 *
287 * @since 1.18.7 (J) - 1.8.7 (WP)
288 */
289 public function getDataChanged()
290 {
291 return $this->dataChanged;
292 }
293
294 /**
295 * Toggles device data-changed flag.
296 *
297 * @param bool $changed Whether data on device has changed.
298 *
299 * @return self
300 *
301 * @since 1.18.7 (J) - 1.8.7 (WP)
302 */
303 public function setDataChanged(bool $changed)
304 {
305 $this->dataChanged = $changed;
306
307 return $this;
308 }
309
310 /**
311 * Counts all connected listings by taking care of subunits.
312 *
313 * @return int
314 *
315 * @since 1.18.7 (J) - 1.8.7 (WP)
316 */
317 public function countConnectedListings()
318 {
319 $totalSubunitsCount = 0;
320 $excludeParents = 0;
321
322 foreach ($this->connectedSubunits as $listingId => $subunits) {
323 // count listing subunits
324 $totalSubunits = count($subunits);
325
326 // increase total subunits count
327 $totalSubunitsCount += $totalSubunits;
328
329 // increase parent listings to exclude
330 $excludeParents += $totalSubunits ? 1 : 0;
331 }
332
333 // return the accurate total connected listings count (inclusive of subunits)
334 return count($this->connectedListings) + $totalSubunitsCount - $excludeParents;
335 }
336
337 /**
338 * Counts the connected listing-subunits from the given list.
339 *
340 * @param array $listingSubunits Linear array of strings as "roomid-subunit".
341 *
342 * @return int Total number of device connected listing units.
343 *
344 * @since 1.18.7 (J) - 1.8.7 (WP)
345 */
346 public function countMatchingListingUnits(array $listingSubunits)
347 {
348 $totalCount = 0;
349
350 foreach ($listingSubunits as $listingSubunit) {
351 // extract listing ID and subunit number
352 $segments = explode('-', (string) $listingSubunit);
353 $listingId = (int) $segments[0];
354 $subunitId = (int) ($segments[1] ?? 0);
355
356 if (!in_array($listingId, $this->connectedListings)) {
357 // main listing ID not connected
358 continue;
359 }
360
361 if ($subunitId && ($this->connectedSubunits[$listingId] ?? [])) {
362 // make sure this exact subunit number is connected on the device
363 if (in_array($subunitId, $this->connectedSubunits[$listingId])) {
364 // match found, increase counter
365 $totalCount++;
366 }
367 } else {
368 // safely increase the counter for the matching listing ID
369 $totalCount++;
370 }
371 }
372
373 return $totalCount;
374 }
375
376 /**
377 * Given a list of listing-subunit pairs, intersects the available connections.
378 *
379 * @param array $listingSubunits Linear array of strings as "roomid-subunit".
380 *
381 * @return array List of intersecting listing-subunit pairs.
382 *
383 * @since 1.18.7 (J) - 1.8.7 (WP)
384 */
385 public function intersectListingUnits(array $listingSubunits)
386 {
387 $intersections = [];
388
389 foreach ($listingSubunits as $listingSubunit) {
390 // extract listing ID and subunit number
391 $segments = explode('-', (string) $listingSubunit);
392 $listingId = (int) $segments[0];
393 $subunitId = (int) ($segments[1] ?? 0);
394
395 if (!in_array($listingId, $this->connectedListings)) {
396 // main listing ID not connected
397 continue;
398 }
399
400 if ($subunitId && ($this->connectedSubunits[$listingId] ?? [])) {
401 // make sure this exact subunit number is connected on the device
402 if (in_array($subunitId, $this->connectedSubunits[$listingId])) {
403 // intersection found for listing and sub-unit
404 $intersections[] = [$listingId, $subunitId];
405 }
406 } else {
407 // intersection found for listing
408 $intersections[] = [$listingId, 0];
409 }
410 }
411
412 return $intersections;
413 }
414
415 /**
416 * Gets the listing IDs connected to the device.
417 *
418 * @return array Linear array of VikBooking listing IDs.
419 */
420 public function getConnectedListings()
421 {
422 return $this->connectedListings;
423 }
424
425 /**
426 * Sets the listing IDs connected to the device.
427 *
428 * @param array $listings List of VikBooking listing IDs.
429 *
430 * @return self
431 */
432 public function setConnectedListings(array $listings)
433 {
434 $this->connectedListings = array_values(
435 array_unique(
436 array_filter(
437 array_map('intval', $listings)
438 )
439 )
440 );
441
442 return $this;
443 }
444
445 /**
446 * Gets the listing subunit IDs connected to the device.
447 *
448 * @return array Associative list of listing sub-unit IDs.
449 *
450 * @since 1.18.7 (J) - 1.8.7 (WP)
451 */
452 public function getConnectedSubunits()
453 {
454 return $this->connectedSubunits;
455 }
456
457 /**
458 * Sets the subunit IDs connected to the device.
459 *
460 * @param array $subunits Associative list of listing sub-unit IDs.
461 *
462 * @return self
463 *
464 * @since 1.18.7 (J) - 1.8.7 (WP)
465 */
466 public function setConnectedSubunits(array $subunits)
467 {
468 $this->connectedSubunits = array_filter(array_map(function($list) {
469 return array_map('intval', (array) $list);
470 }, $subunits));
471
472 return $this;
473 }
474
475 /**
476 * Gets the subunit IDs of the given listing ID connected to the device.
477 *
478 * @param int $listingId The VikBooking listing ID.
479 *
480 * @return array Linear array of listing sub-unit IDs.
481 *
482 * @since 1.18.7 (J) - 1.8.7 (WP)
483 */
484 public function getConnectedListingSubunits(int $listingId)
485 {
486 return $this->connectedSubunits[$listingId] ?? [];
487 }
488
489 /**
490 * Adds an entry to the list of device connected listing IDs.
491 *
492 * @param int $listingId The listing ID to add as connected.
493 * @param ?int $subunitId Optional listing sub-unit ID (1-based).
494 *
495 * @return self
496 *
497 * @since 1.18.7 (J) - 1.8.7 (WP) added argument $subunitId.
498 */
499 public function addConnectedListing(int $listingId, ?int $subunitId = null)
500 {
501 if (!in_array($listingId, $this->connectedListings)) {
502 // push listing ID
503 $this->connectedListings[] = $listingId;
504 }
505
506 if ($subunitId) {
507 // push listing sub-unit ID relation
508 $this->connectedSubunits[$listingId] = $this->connectedSubunits[$listingId] ?? [];
509 if (!in_array($subunitId, $this->connectedSubunits[$listingId])) {
510 $this->connectedSubunits[$listingId][] = $subunitId;
511 }
512 }
513
514 return $this;
515 }
516
517 /**
518 * Removes an entry from the list of device connected listing IDs.
519 *
520 * @param int $listingId The listing ID to remove and disconnect.
521 *
522 * @return self
523 *
524 * @since 1.18.7 (J) - 1.8.7 (WP) added argument $subunitId.
525 */
526 public function removeConnectedListing(int $listingId, ?int $subunitId = null)
527 {
528 // process subunit-level connection first
529 if ($subunitId && ($this->connectedSubunits[$listingId] ?? [])) {
530 $this->connectedSubunits[$listingId] = array_values(array_filter($this->connectedSubunits[$listingId], function($currentSubunitId) use ($subunitId) {
531 return $currentSubunitId != $subunitId;
532 }));
533
534 if ($this->connectedSubunits[$listingId]) {
535 // the main listing still has some sub-units connected
536 // do not proceed
537 return $this;
538 }
539
540 // no more sub-units under this listing
541 // proceed with the listil-level connection removal for the whole listing
542 unset($this->connectedSubunits[$listingId]);
543 }
544
545 // process listing-level connection
546 $this->connectedListings = array_values(array_filter($this->connectedListings, function($currentId) use ($listingId) {
547 return $currentId != $listingId;
548 }));
549
550 return $this;
551 }
552
553 /**
554 * Gets the device capabilities.
555 *
556 * @return VBODooraccessDeviceCapability[]
557 */
558 public function getCapabilities()
559 {
560 return $this->capabilities;
561 }
562
563 /**
564 * Returns a specific capability from the current device.
565 *
566 * @param string $capabilityId The device capability identifier.
567 *
568 * @return VBODooraccessDeviceCapability
569 *
570 * @throws Exception
571 */
572 public function getCapabilityById(string $capabilityId)
573 {
574 foreach ($this->getCapabilities() as $cap) {
575 if ($cap->getID() == $capabilityId) {
576 return $cap;
577 }
578 }
579
580 throw new Exception(sprintf('Could not access the requested capability ID: %s.', $capabilityId), 404);
581 }
582
583 /**
584 * Tells if the device has got capabilities.
585 *
586 * @return bool
587 */
588 public function hasCapabilities()
589 {
590 return (bool) count($this->capabilities);
591 }
592
593 /**
594 * Sets a device capability.
595 *
596 * @param VBODooraccessDeviceCapability $capability
597 *
598 * @return self
599 *
600 * @throws Exception
601 */
602 public function setCapability(VBODooraccessDeviceCapability $capability)
603 {
604 if (!$capability->isValid()) {
605 throw new Exception('Capability is missing required information.', 500);
606 }
607
608 // push capability
609 $this->capabilities[] = $capability;
610
611 return $this;
612 }
613
614 /**
615 * Sets multiple device capability objects.
616 *
617 * @param VBODooraccessDeviceCapability[] $capabilities List of device capability objects.
618 *
619 * @return self
620 */
621 public function setCapabilities(array $capabilities)
622 {
623 foreach ($capabilities as $capability) {
624 $this->setCapability($capability);
625 }
626
627 return $this;
628 }
629
630 /**
631 * Resets the device capabilities.
632 *
633 * @return self
634 */
635 public function resetCapabilities()
636 {
637 $this->capabilities = [];
638
639 return $this;
640 }
641
642 /**
643 * Tells if the device has decorated the mandatory properties.
644 *
645 * @return bool
646 */
647 public function isComplete()
648 {
649 if (!$this->identifier || !$this->name) {
650 return false;
651 }
652
653 return true;
654 }
655 }
656