Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.29% covered (warning)
72.29%
60 / 83
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncService
72.29% covered (warning)
72.29%
60 / 83
33.33% covered (danger)
33.33%
1 / 3
61.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 synchronize
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
9
 objidRequest
60.00% covered (warning)
60.00%
33 / 55
0.00% covered (danger)
0.00%
0 / 1
65.00
1<?php
2
3declare(strict_types=1);
4
5namespace UppServices;
6
7use Psr\Http\Message\ServerRequestInterface;
8
9/**
10 * Handles sync flow: apply client changes and return updates (long-poll).
11 * Uses sync logic in Services/legacy/model/synchronize.php (run_synchronize).
12 * Follows tenantddbb-bestpractices: single ConxHelper; the helper creates connections lazily
13 * (->global, ->tenant when place is set). run_synchronize uses ->global for user target and ->tenant for place/table.
14 */
15class SyncService
16{
17    public function __construct()
18    {
19        require_once __DIR__.'/legacy/model/synchronize.php';
20    }
21
22    /**
23     * Run the full sync flow: validate session, apply changes, refresh/wait, load updates.
24     * Central when target=user or no place; place DB (P + 8 digits) when target=place and place is set.
25     * ConxHelper creates connections on first use; run_synchronize receives $conx and schema name for reconnect.
26     *
27     * @return array{errorcode: int, timestamp: mixed, reference: int, target: mixed, updated: bool, expired: bool, updates: array}
28     */
29    public function synchronize(ServerRequestInterface $request): array
30    {
31        $retval = \ApplicationError::Success;
32        $queryParams = $request->getQueryParams();
33        $postBody = (string) $request->getBody();
34        $target = $queryParams['target'] ?? null;
35        $place = isset($queryParams['place']) ? $queryParams['place'] : null;
36
37        $result = [
38            'errorcode' => $retval,
39            'timestamp' => null,
40            'reference' => 0,
41            'target' => $target,
42            'updated' => false,
43            'expired' => false,
44            'updates' => [],
45        ];
46
47        $conx = null;
48        if (\success($retval)) {
49            require_once __DIR__ . '/legacy/ddbb/conx.php';
50            $conx = new \ConxHelper(__FILE__);
51        }
52
53        if (\success($retval) && $conx !== null) {
54            $conx->tenant = $place;
55        }
56
57        if (\success($retval) && $conx !== null) {
58            $result = \run_synchronize($conx, $queryParams, $postBody);
59        }
60
61        if ($conx !== null) {
62            $conx->release();
63        }
64
65        // When we never ran run_synchronize, ensure errorcode reflects current $retval (e.g. validation failure).
66        if ($result['timestamp'] === null) {
67            $result['errorcode'] = $retval;
68        }
69
70        return $result;
71    }
72
73    /**
74     * Fetch a single row by objid (on-demand refresh during sync).
75     * Validates session (central DB), then queries the schema connection for that
76     * table: central (`SESSION`, `QRSCAN`, …) or the place tenant.
77     *
78     * @param ServerRequestInterface $request Query params: device, session, place, table, objid.
79     * @return array{errorcode: int, info: array|null} errorcode and row data on success.
80     */
81    public function objidRequest(ServerRequestInterface $request): array
82    {
83        $retval = \ApplicationError::Success;
84        $info = null;
85
86        $queryParams = $request->getQueryParams();
87        $device = $queryParams['device'] ?? null;
88        $session = $queryParams['session'] ?? null;
89        $place = $queryParams['place'] ?? null;
90        $table = $queryParams['table'] ?? null;
91        $objid = $queryParams['objid'] ?? null;
92
93        $conx = null;
94        if (\success($retval)) {
95            require_once __DIR__.'/legacy/ddbb/conx.php';
96            require_once __DIR__.'/legacy/session/session.php';
97            $conx = new \ConxHelper(__FILE__);
98        }
99
100        if (\success($retval) && !$device) {
101            \addlog(__FILE__, \LogLevel::Error, "No device provided on URL. Operation cancelled.");
102            $retval = \ApplicationError::Parameters;
103        }
104
105        if (\success($retval) && !$session) {
106            \addlog(__FILE__, \LogLevel::Error, "No session provided on URL. Operation cancelled.");
107            $retval = \ApplicationError::Parameters;
108        }
109
110        if (\success($retval)) {
111            $userid = null;
112            $sessionObjid = false;
113            $retval = \check_session($conx, $session, $device, $userid, $sessionObjid);
114        }
115
116        if (\success($retval) && ($place === false || $place === null || $place === '')) {
117            \addlog(__FILE__, \LogLevel::Error, "Mandatory argument 'place' not provided in url parameters. Operation cancelled.");
118            $retval = \ApplicationError::Parameters;
119        }
120
121        if (\success($retval)) {
122            $conx->tenant = $place;
123        }
124
125        if (\success($retval) && !$table) {
126            \addlog(__FILE__, \LogLevel::Error, "Mandatory argument 'table' not provided in url parameters.");
127            $retval = \ApplicationError::Parameters;
128        }
129
130        if (\success($retval) && !$objid) {
131            \addlog(__FILE__, \LogLevel::Error, "Mandatory argument 'objid' not provided in url parameters.");
132            $retval = \ApplicationError::Parameters;
133        }
134
135        $conn = \success($retval) ? $conx->for((string) $table) : null;
136        if (\success($retval) && $conn === null) {
137            \addlog(__FILE__, \LogLevel::Error, "No database connection for table ".$table.".");
138            $retval = \ApplicationError::Database;
139        }
140
141        if (\success($retval) && $conn !== null) {
142            $results = [];
143            $res = $conn->query($table, ["objid" => $objid], $results);
144            if ($res) {
145                if (count($results) > 0) {
146                    $info = $results[0];
147                    \addlog(__FILE__, \LogLevel::Debug, "On-demand refreshing entry: ".$table."@".$objid);
148                }
149                else {
150                    \addlog(__FILE__, \LogLevel::Error, "No entry found for ".$table."@".$objid);
151                    $retval = \ApplicationError::NotFound;
152                }
153            }
154            else {
155                \addlog(__FILE__, \LogLevel::Error, "Query failed for table ".$table." objid ".$objid);
156                $retval = \ApplicationError::Database;
157            }
158        }
159
160        if ($conx !== null) {
161            $conx->release();
162        }
163
164        return [
165            'errorcode' => $retval,
166            'info' => \success($retval) ? $info : null,
167        ];
168    }
169}