Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
88.08% |
303 / 344 |
|
35.71% |
5 / 14 |
CRAP | |
0.00% |
0 / 1 |
MapperService | |
88.08% |
303 / 344 |
|
35.71% |
5 / 14 |
241.32 | |
0.00% |
0 / 1 |
mapScopeForProvider | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
10.24 | |||
extractReservationDuration | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
5.07 | |||
extractActivationDuration | |
81.82% |
9 / 11 |
|
0.00% |
0 / 1 |
7.29 | |||
mapOfficesWithScope | |
91.38% |
53 / 58 |
|
0.00% |
0 / 1 |
48.42 | |||
mapCombinable | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
mapServicesWithCombinations | |
96.55% |
28 / 29 |
|
0.00% |
0 / 1 |
15 | |||
mapRelations | |
91.67% |
11 / 12 |
|
0.00% |
0 / 1 |
4.01 | |||
scopeToThinnedScope | |
76.47% |
39 / 51 |
|
0.00% |
0 / 1 |
39.96 | |||
processToThinnedProcess | |
81.40% |
35 / 43 |
|
0.00% |
0 / 1 |
45.82 | |||
thinnedProcessToProcess | |
100.00% |
27 / 27 |
|
100.00% |
1 / 1 |
4 | |||
createScope | |
100.00% |
40 / 40 |
|
100.00% |
1 / 1 |
6 | |||
createRequests | |
59.09% |
13 / 22 |
|
0.00% |
0 / 1 |
5.10 | |||
contactToThinnedContact | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
6 | |||
providerToThinnedProvider | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
8 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace BO\Zmscitizenapi\Services\Core; |
6 | |
7 | use BO\Zmscitizenapi\Utils\ClientIpHelper; |
8 | use BO\Zmscitizenapi\Models\Office; |
9 | use BO\Zmscitizenapi\Models\Combinable; |
10 | use BO\Zmscitizenapi\Models\OfficeServiceRelation; |
11 | use BO\Zmscitizenapi\Models\Service; |
12 | use BO\Zmscitizenapi\Models\ThinnedContact; |
13 | use BO\Zmscitizenapi\Models\ThinnedProcess; |
14 | use BO\Zmscitizenapi\Models\ThinnedProvider; |
15 | use BO\Zmscitizenapi\Models\ThinnedScope; |
16 | use BO\Zmscitizenapi\Models\Collections\OfficeList; |
17 | use BO\Zmscitizenapi\Models\Collections\OfficeServiceRelationList; |
18 | use BO\Zmscitizenapi\Models\Collections\ServiceList; |
19 | use BO\Zmscitizenapi\Models\Collections\ThinnedScopeList; |
20 | use BO\Zmsentities\Appointment; |
21 | use BO\Zmsentities\Client; |
22 | use BO\Zmsentities\Contact; |
23 | use BO\Zmsentities\Process; |
24 | use BO\Zmsentities\Provider; |
25 | use BO\Zmsentities\Request; |
26 | use BO\Zmsentities\Scope; |
27 | use BO\Zmsentities\Collection\ProviderList; |
28 | use BO\Zmsentities\Collection\RequestList; |
29 | use BO\Zmsentities\Collection\RequestRelationList; |
30 | |
31 | /** |
32 | * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
33 | * @TODO: Extract class has ExcessiveClassComplexity 101 vs 100 |
34 | */ |
35 | class MapperService |
36 | { |
37 | public static function mapScopeForProvider( |
38 | int $providerId, |
39 | ThinnedScopeList $scopes, |
40 | ?string $providerSource = null |
41 | ): ?ThinnedScope { |
42 | foreach ($scopes->getScopes() as $scope) { |
43 | if (!$scope instanceof ThinnedScope) { |
44 | continue; |
45 | } |
46 | |
47 | $prov = $scope->provider ?? null; |
48 | if (!$prov) { |
49 | continue; |
50 | } |
51 | |
52 | $provId = is_object($prov) ? ($prov->id ?? null) : ($prov['id'] ?? null); |
53 | $provSrc = is_object($prov) ? ($prov->source ?? null) : ($prov['source'] ?? null); |
54 | |
55 | if ((string)$provId !== (string)$providerId) { |
56 | continue; |
57 | } |
58 | |
59 | if ($providerSource === null || $providerSource === '') { |
60 | return $scope; |
61 | } |
62 | |
63 | if ((string)$provSrc === (string)$providerSource) { |
64 | return $scope; |
65 | } |
66 | } |
67 | |
68 | return null; |
69 | } |
70 | |
71 | public static function extractReservationDuration(Scope|ThinnedScope|null $scope): ?int |
72 | { |
73 | if ($scope === null) { |
74 | return null; |
75 | } |
76 | if ($scope instanceof ThinnedScope) { |
77 | $reservationDuration = $scope->getReservationDuration(); |
78 | return $reservationDuration !== null ? (int) $reservationDuration : null; |
79 | } |
80 | $reservationDuration = $scope?->toProperty()?->preferences?->appointment?->reservationDuration?->get(); |
81 | return $reservationDuration !== null ? (int) $reservationDuration : null; |
82 | } |
83 | |
84 | public static function extractActivationDuration(Scope|ThinnedScope|null $scope): ?int |
85 | { |
86 | if ($scope === null) { |
87 | return null; |
88 | } |
89 | |
90 | if ($scope instanceof ThinnedScope) { |
91 | $activationDuration = $scope->getActivationDuration(); |
92 | if ($activationDuration === null || $activationDuration === '') { |
93 | return null; |
94 | } |
95 | return (int) $activationDuration; |
96 | } |
97 | |
98 | $activationDuration = $scope?->toProperty()?->preferences?->appointment?->activationDuration?->get(); |
99 | if ($activationDuration === null || $activationDuration === '') { |
100 | return null; |
101 | } |
102 | return (int) $activationDuration; |
103 | } |
104 | |
105 | /** |
106 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
107 | * @SuppressWarnings(PHPMD.NPathComplexity) |
108 | * @TODO: Extract mapping logic into specialized mapper classes for each entity type |
109 | * |
110 | */ |
111 | public static function mapOfficesWithScope(ProviderList $providerList, bool $showUnpublished = false): OfficeList |
112 | { |
113 | $offices = []; |
114 | $scopes = ZmsApiFacadeService::getScopes(); |
115 | if (!$scopes instanceof ThinnedScopeList) { |
116 | return new OfficeList(); |
117 | } |
118 | |
119 | foreach ($providerList as $provider) { |
120 | // ✅ Source normalisieren: leerer String -> Fallback auf App::$source_name |
121 | $providerSource = isset($provider->source) && $provider->source !== '' |
122 | ? (string)$provider->source |
123 | : (string)\App::$source_name; |
124 | |
125 | $providerScope = self::mapScopeForProvider( |
126 | (int) $provider->id, |
127 | $scopes, |
128 | $providerSource |
129 | ); |
130 | |
131 | if (!$showUnpublished && isset($provider->data['public']) && !(bool) $provider->data['public']) { |
132 | continue; |
133 | } |
134 | |
135 | $offices[] = new Office( |
136 | id: isset($provider->id) ? (int) $provider->id : 0, |
137 | name: isset($provider->displayName) ? $provider->displayName : (isset($provider->name) ? $provider->name : null), |
138 | address: isset($provider->data['address']) ? $provider->data['address'] : null, |
139 | showAlternativeLocations: isset($provider->data['showAlternativeLocations']) ? $provider->data['showAlternativeLocations'] : null, |
140 | displayNameAlternatives: $provider->data['displayNameAlternatives'] ?? [], |
141 | organization: $provider->data['organization'] ?? null, |
142 | organizationUnit: $provider->data['organizationUnit'] ?? null, |
143 | slotTimeInMinutes: $provider->data['slotTimeInMinutes'] ?? null, |
144 | geo: isset($provider->data['geo']) ? $provider->data['geo'] : null, |
145 | disabledByServices: isset($provider->data['dontShowByServices']) ? $provider->data['dontShowByServices'] : [], |
146 | priority: isset($provider->data['prio']) ? $provider->data['prio'] : 1, |
147 | scope: isset($providerScope) && !isset($providerScope['errors']) ? new ThinnedScope( |
148 | id: isset($providerScope->id) ? (int) $providerScope->id : 0, |
149 | provider: isset($providerScope->provider) ? $providerScope->provider : null, |
150 | shortName: isset($providerScope->shortName) ? (string) $providerScope->shortName : null, |
151 | emailFrom: isset($providerScope->emailFrom) ? (string) $providerScope->emailFrom : null, |
152 | emailRequired: isset($providerScope->emailRequired) ? (bool) $providerScope->emailRequired : null, |
153 | telephoneActivated: isset($providerScope->telephoneActivated) ? (bool) $providerScope->telephoneActivated : null, |
154 | telephoneRequired: isset($providerScope->telephoneRequired) ? (bool) $providerScope->telephoneRequired : null, |
155 | customTextfieldActivated: isset($providerScope->customTextfieldActivated) ? (bool) $providerScope->customTextfieldActivated : null, |
156 | customTextfieldRequired: isset($providerScope->customTextfieldRequired) ? (bool) $providerScope->customTextfieldRequired : null, |
157 | customTextfieldLabel: isset($providerScope->customTextfieldLabel) ? (string) $providerScope->customTextfieldLabel : null, |
158 | customTextfield2Activated: isset($providerScope->customTextfield2Activated) ? (bool) $providerScope->customTextfield2Activated : null, |
159 | customTextfield2Required: isset($providerScope->customTextfield2Required) ? (bool) $providerScope->customTextfield2Required : null, |
160 | customTextfield2Label: isset($providerScope->customTextfield2Label) ? (string) $providerScope->customTextfield2Label : null, |
161 | captchaActivatedRequired: isset($providerScope->captchaActivatedRequired) ? (bool) $providerScope->captchaActivatedRequired : null, |
162 | infoForAppointment: isset($providerScope->infoForAppointment) |
163 | ? ((string) $providerScope->infoForAppointment === '' ? null : (string) $providerScope->infoForAppointment) |
164 | : null, |
165 | infoForAllAppointments: isset($providerScope->infoForAllAppointments) |
166 | ? ((string) $providerScope->infoForAllAppointments === '' ? null : (string) $providerScope->infoForAllAppointments) |
167 | : null, |
168 | appointmentsPerMail: isset($providerScope->appointmentsPerMail) ? ((string) $providerScope->appointmentsPerMail === '' ? null : (string) $providerScope->appointmentsPerMail) : null, |
169 | whitelistedMails: isset($providerScope->whitelistedMails) ? ((string) $providerScope->whitelistedMails === '' ? null : (string) $providerScope->whitelistedMails) : null, |
170 | reservationDuration: (int) self::extractReservationDuration($providerScope), |
171 | activationDuration: self::extractActivationDuration($providerScope), |
172 | hint: isset($providerScope->hint) ? (trim((string) $providerScope->hint) === '' ? null : (string) $providerScope->hint) : null |
173 | ) : null, |
174 | maxSlotsPerAppointment: isset($providerScope) && !isset($providerScope['errors']) && isset($providerScope->slotsPerAppointment) ? ((string) $providerScope->slotsPerAppointment === '' ? null : (string) $providerScope->slotsPerAppointment) : null, |
175 | parentId: isset($provider->parent_id) ? (int) $provider->parent_id : null |
176 | ); |
177 | } |
178 | |
179 | return new OfficeList($offices); |
180 | } |
181 | |
182 | public static function mapCombinable(array $serviceCombinations): ?Combinable |
183 | { |
184 | return !empty($serviceCombinations) ? new Combinable($serviceCombinations) : null; |
185 | } |
186 | |
187 | /** |
188 | * Map services with combinations based on request and relation lists. |
189 | * |
190 | * @param RequestList $requestList |
191 | * @param RequestRelationList $relationList |
192 | * @return ServiceList |
193 | * @SuppressWarnings(PHPMD.NPathComplexity) |
194 | */ |
195 | public static function mapServicesWithCombinations( |
196 | RequestList $requestList, |
197 | RequestRelationList $relationList, |
198 | bool $showUnpublished = false |
199 | ): ServiceList { |
200 | /** @var array<string, array<int>> $servicesProviderIds */ |
201 | $servicesProviderIds = []; |
202 | foreach ($relationList as $relation) { |
203 | if (!$showUnpublished && !$relation->isPublic()) { |
204 | continue; |
205 | } |
206 | |
207 | $serviceId = $relation->request->id; |
208 | $servicesProviderIds[$serviceId] ??= []; |
209 | $servicesProviderIds[$serviceId][] = $relation->provider->id; |
210 | } |
211 | |
212 | /** @var Service[] $services */ |
213 | $services = []; |
214 | $requestArray = iterator_to_array($requestList); |
215 | usort($requestArray, function ($a, $b) { |
216 | |
217 | return $a->getId() <=> $b->getId(); |
218 | // Sorting by service ID (ascending order) |
219 | }); |
220 | foreach ($requestArray as $service) { |
221 | if ( |
222 | !$showUnpublished |
223 | && isset($service->getAdditionalData()['public']) |
224 | && !$service->getAdditionalData()['public'] |
225 | ) { |
226 | continue; |
227 | } |
228 | |
229 | /** @var array<string, array<int>> $serviceCombinations */ |
230 | $serviceCombinations = []; |
231 | $combinableData = $service->getAdditionalData()['combinable'] ?? []; |
232 | foreach ($combinableData as $combinationServiceId) { |
233 | $commonProviders = array_intersect($servicesProviderIds[$service->getId()] ?? [], $servicesProviderIds[$combinationServiceId] ?? []); |
234 | $serviceCombinations[$combinationServiceId] = !empty($commonProviders) ? array_values($commonProviders) : []; |
235 | } |
236 | |
237 | $combinable = self::mapCombinable($serviceCombinations); |
238 | |
239 | $extra = $service->getAdditionalData() ?? []; |
240 | $parentId = isset($service->parent_id) ? (int)$service->parent_id : (isset($extra['parent_id']) ? (int)$extra['parent_id'] : null); |
241 | $variantId = isset($service->variant_id) ? (int)$service->variant_id : (isset($extra['variant_id']) ? (int)$extra['variant_id'] : null); |
242 | |
243 | if (!empty($servicesProviderIds[$service->getId()])) { |
244 | $services[] = new Service(id: (int) $service->getId(), name: $service->getName(), maxQuantity: $service->getAdditionalData()['maxQuantity'] ?? 1, combinable: $combinable ?? new Combinable(), parentId: $parentId, variantId: $variantId); |
245 | } |
246 | } |
247 | |
248 | return new ServiceList($services); |
249 | } |
250 | |
251 | |
252 | public static function mapRelations( |
253 | RequestRelationList $relationList, |
254 | bool $showUnpublished = false |
255 | ): OfficeServiceRelationList { |
256 | $relations = []; |
257 | foreach ($relationList as $relation) { |
258 | if (!$showUnpublished && !$relation->isPublic()) { |
259 | continue; |
260 | } |
261 | |
262 | $relations[] = new OfficeServiceRelation( |
263 | officeId: (int) $relation->provider->id, |
264 | serviceId: (int) $relation->request->id, |
265 | slots: intval($relation->slots), |
266 | public: (bool) $relation->isPublic(), |
267 | maxQuantity: (int) $relation->maxQuantity |
268 | ); |
269 | } |
270 | |
271 | return new OfficeServiceRelationList($relations); |
272 | } |
273 | |
274 | /** |
275 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
276 | * @SuppressWarnings(PHPMD.NPathComplexity) |
277 | */ |
278 | public static function scopeToThinnedScope(Scope $scope): ThinnedScope |
279 | { |
280 | if (!$scope || !isset($scope->id)) { |
281 | return new ThinnedScope(); |
282 | } |
283 | |
284 | $thinnedProvider = null; |
285 | try { |
286 | if (isset($scope->provider)) { |
287 | $provider = $scope->provider; |
288 | $contact = $provider->contact ?? null; |
289 | $thinnedProvider = new ThinnedProvider( |
290 | id: isset($provider->id) ? (int)$provider->id : null, |
291 | name: $provider->name ?? null, |
292 | displayName: $provider->displayName ?? null, |
293 | source: $provider->source ?? null, |
294 | contact: $contact ? self::contactToThinnedContact($contact) : null |
295 | ); |
296 | } |
297 | } catch (\BO\Zmsentities\Exception\ScopeMissingProvider $e) { |
298 | $thinnedProvider = null; |
299 | } |
300 | |
301 | return new ThinnedScope( |
302 | id: (int) ($scope->id ?? 0), |
303 | provider: $thinnedProvider, |
304 | shortName: isset($scope->shortName) ? (string) $scope->shortName : null, |
305 | emailFrom: (string) $scope->getEmailFrom() ?? null, |
306 | emailRequired: isset($scope->data['emailRequired']) ? (bool) $scope->data['emailRequired'] : null, |
307 | telephoneActivated: isset($scope->data['telephoneActivated']) ? (bool) $scope->data['telephoneActivated'] : null, |
308 | telephoneRequired: isset($scope->data['telephoneRequired']) ? (bool) $scope->data['telephoneRequired'] : null, |
309 | customTextfieldActivated: isset($scope->data['customTextfieldActivated']) ? (bool) $scope->data['customTextfieldActivated'] : null, |
310 | customTextfieldRequired: isset($scope->data['customTextfieldRequired']) ? (bool) $scope->data['customTextfieldRequired'] : null, |
311 | customTextfieldLabel: isset($scope->data['customTextfieldLabel']) ? (string) $scope->data['customTextfieldLabel'] : null, |
312 | customTextfield2Activated: isset($scope->data['customTextfield2Activated']) ? (bool) $scope->data['customTextfield2Activated'] : null, |
313 | customTextfield2Required: isset($scope->data['customTextfield2Required']) ? (bool) $scope->data['customTextfield2Required'] : null, |
314 | customTextfield2Label: isset($scope->data['customTextfield2Label']) ? (string) $scope->data['customTextfield2Label'] : null, |
315 | captchaActivatedRequired: isset($scope->data['captchaActivatedRequired']) ? (bool) $scope->data['captchaActivatedRequired'] : null, |
316 | infoForAppointment: isset($scope->data['infoForAppointment']) |
317 | ? ((string) $scope->data['infoForAppointment'] === '' |
318 | ? null |
319 | : (string) $scope->data['infoForAppointment']) |
320 | : null, |
321 | infoForAllAppointments: isset($scope->data['infoForAllAppointments']) |
322 | ? ((string) $scope->data['infoForAllAppointments'] === '' |
323 | ? null |
324 | : (string) $scope->data['infoForAllAppointments']) |
325 | : null, |
326 | slotsPerAppointment: isset($scope->data['slotsPerAppointment']) |
327 | ? ((string) $scope->data['slotsPerAppointment'] === '' |
328 | ? null |
329 | : (string) $scope->data['slotsPerAppointment']) |
330 | : null, |
331 | appointmentsPerMail: isset($scope->data['appointmentsPerMail']) ? ((string) $scope->data['appointmentsPerMail'] === '' ? null : (string) $scope->data['appointmentsPerMail']) : null, |
332 | whitelistedMails: isset($scope->data['whitelistedMails']) ? ((string) $scope->data['whitelistedMails'] === '' ? null : (string) $scope->data['whitelistedMails']) : null, |
333 | reservationDuration: MapperService::extractReservationDuration($scope), |
334 | activationDuration: MapperService::extractActivationDuration($scope), |
335 | hint: (trim((string) ($scope->getScopeHint() ?? '')) === '') ? null : (string) $scope->getScopeHint() |
336 | ); |
337 | } |
338 | |
339 | /** |
340 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
341 | * @SuppressWarnings(PHPMD.NPathComplexity) |
342 | * @TODO: Break down process mapping into smaller, focused methods |
343 | */ |
344 | public static function processToThinnedProcess(Process $myProcess): ThinnedProcess |
345 | { |
346 | if (!$myProcess || !isset($myProcess->id)) { |
347 | return new ThinnedProcess(); |
348 | } |
349 | |
350 | $subRequestCounts = []; |
351 | $mainServiceId = null; |
352 | $mainServiceName = null; |
353 | $mainServiceCount = 0; |
354 | $requests = $myProcess->getRequests() ?? []; |
355 | if ($requests) { |
356 | $requests = is_array($requests) ? $requests : iterator_to_array($requests); |
357 | if (count($requests) > 0) { |
358 | $mainServiceId = $requests[0]->id; |
359 | foreach ($requests as $request) { |
360 | if ($request->id === $mainServiceId) { |
361 | $mainServiceCount++; |
362 | if (!$mainServiceName && isset($request->name)) { |
363 | $mainServiceName = $request->name; |
364 | } |
365 | } else { |
366 | if (!isset($subRequestCounts[$request->id])) { |
367 | $subRequestCounts[$request->id] = [ |
368 | 'id' => (int) $request->id, |
369 | 'name' => $request->name, |
370 | 'count' => 0, |
371 | ]; |
372 | } |
373 | $subRequestCounts[$request->id]['count']++; |
374 | } |
375 | } |
376 | } |
377 | } |
378 | |
379 | return new ThinnedProcess( |
380 | processId: isset($myProcess->id) ? (int) $myProcess->id : 0, |
381 | timestamp: (isset($myProcess->appointments[0]) && isset($myProcess->appointments[0]->date)) ? strval($myProcess->appointments[0]->date) : null, |
382 | authKey: isset($myProcess->authKey) ? $myProcess->authKey : null, |
383 | captchaToken: isset($myProcess->captchaToken) ? $myProcess->captchaToken : null, |
384 | familyName: (isset($myProcess->clients[0]) && isset($myProcess->clients[0]->familyName)) ? $myProcess->clients[0]->familyName : null, |
385 | customTextfield: isset($myProcess->customTextfield) ? $myProcess->customTextfield : null, |
386 | customTextfield2: isset($myProcess->customTextfield2) ? $myProcess->customTextfield2 : null, |
387 | email: (isset($myProcess->clients[0]) && isset($myProcess->clients[0]->email)) ? $myProcess->clients[0]->email : null, |
388 | telephone: (isset($myProcess->clients[0]) && isset($myProcess->clients[0]->telephone)) ? $myProcess->clients[0]->telephone : null, |
389 | officeName: (isset($myProcess->scope->contact) && isset($myProcess->scope->contact->name)) ? $myProcess->scope->contact->name : null, |
390 | officeId: (isset($myProcess->scope->provider) && isset($myProcess->scope->provider->id)) ? (int) $myProcess->scope->provider->id : 0, |
391 | scope: isset($myProcess->scope) ? self::scopeToThinnedScope($myProcess->scope) : null, |
392 | subRequestCounts: isset($subRequestCounts) ? array_values($subRequestCounts) : [], |
393 | serviceId: isset($mainServiceId) ? (int) $mainServiceId : 0, |
394 | serviceName: isset($mainServiceName) ? $mainServiceName : null, |
395 | serviceCount: isset($mainServiceCount) ? $mainServiceCount : 0, |
396 | status: (isset($myProcess->queue) && isset($myProcess->queue->status)) ? $myProcess->queue->status : null, |
397 | slotCount: (isset($myProcess->appointments[0]) && isset($myProcess->appointments[0]->slotCount)) ? (int) $myProcess->appointments[0]->slotCount : null |
398 | ); |
399 | } |
400 | |
401 | public static function thinnedProcessToProcess(ThinnedProcess $thinnedProcess): Process |
402 | { |
403 | if (!$thinnedProcess || !isset($thinnedProcess->processId)) { |
404 | return new Process(); |
405 | } |
406 | |
407 | $processEntity = new Process(); |
408 | $processEntity->id = $thinnedProcess->processId; |
409 | $processEntity->authKey = $thinnedProcess->authKey ?? null; |
410 | $processEntity->customTextfield = $thinnedProcess->customTextfield ?? null; |
411 | $processEntity->customTextfield2 = $thinnedProcess->customTextfield2 ?? null; |
412 | $processEntity->captchaToken = $thinnedProcess->captchaToken ?? null; |
413 | |
414 | $client = new Client(); |
415 | $client->familyName = $thinnedProcess->familyName ?? null; |
416 | $client->email = $thinnedProcess->email ?? null; |
417 | $client->telephone = $thinnedProcess->telephone ?? null; |
418 | $processEntity->clients = [$client]; |
419 | |
420 | $appointment = new Appointment(); |
421 | $appointment->slotCount = $thinnedProcess->slotCount ?? null; |
422 | $appointment->date = $thinnedProcess->timestamp ?? null; |
423 | $processEntity->appointments = [$appointment]; |
424 | $processEntity->scope = self::createScope($thinnedProcess); |
425 | $processEntity->requests = self::createRequests($thinnedProcess); |
426 | |
427 | if (isset($thinnedProcess->status)) { |
428 | $processEntity->queue = new \stdClass(); |
429 | $processEntity->queue->status = $thinnedProcess->status; |
430 | $processEntity->status = $thinnedProcess->status; |
431 | } |
432 | |
433 | $processEntity->lastChange = time(); |
434 | $processEntity->createIP = ClientIpHelper::getClientIp(); |
435 | $processEntity->createTimestamp = time(); |
436 | return $processEntity; |
437 | } |
438 | |
439 | private static function createScope(ThinnedProcess $thinnedProcess): Scope |
440 | { |
441 | $scope = new Scope(); |
442 | if ($thinnedProcess->scope) { |
443 | $providerSource = $thinnedProcess->scope->provider->source ?? 'dldb'; |
444 | |
445 | $scope->id = $thinnedProcess->scope->id; |
446 | $scope->source = $providerSource; |
447 | |
448 | $scope->preferences = [ |
449 | 'client' => [ |
450 | 'appointmentsPerMail' => $thinnedProcess->scope->getAppointmentsPerMail() ?? null, |
451 | "whitelistedMails" => $thinnedProcess->scope->getWhitelistedMails() ?? null, |
452 | 'emailFrom' => $thinnedProcess->scope->getEmailFrom() ?? null, |
453 | 'emailRequired' => $thinnedProcess->scope->getEmailRequired() ?? false, |
454 | 'telephoneActivated' => $thinnedProcess->scope->getTelephoneActivated() ?? false, |
455 | 'telephoneRequired' => $thinnedProcess->scope->getTelephoneRequired() ?? false, |
456 | 'customTextfieldActivated' => $thinnedProcess->scope->getCustomTextfieldActivated() ?? false, |
457 | 'customTextfieldRequired' => $thinnedProcess->scope->getCustomTextfieldRequired() ?? false, |
458 | 'customTextfieldLabel' => $thinnedProcess->scope->getCustomTextfieldLabel() ?? null, |
459 | 'customTextfield2Activated' => $thinnedProcess->scope->getCustomTextfield2Activated() ?? false, |
460 | 'customTextfield2Required' => $thinnedProcess->scope->getCustomTextfield2Required() ?? false, |
461 | 'customTextfield2Label' => $thinnedProcess->scope->getCustomTextfield2Label() ?? null |
462 | ], |
463 | 'notifications' => [ |
464 | 'enabled' => true |
465 | ] |
466 | ]; |
467 | } |
468 | if (isset($thinnedProcess->officeName)) { |
469 | $scope->contact = new Contact(); |
470 | $scope->contact->name = $thinnedProcess->officeName; |
471 | } |
472 | if (isset($thinnedProcess->officeId)) { |
473 | $scope->provider = new Provider(); |
474 | $scope->provider->id = $thinnedProcess->officeId; |
475 | if (isset($thinnedProcess->scope->provider)) { |
476 | $provider = $thinnedProcess->scope->provider; |
477 | $scope->provider->name = $provider->name ?? null; |
478 | $scope->provider->displayName = $provider->displayName ?? null; |
479 | |
480 | if (isset($provider->contact)) { |
481 | $scope->provider->contact = new Contact(); |
482 | $scope->provider->contact->street = $provider->contact->street ?? null; |
483 | $scope->provider->contact->streetNumber = $provider->contact->streetNumber ?? null; |
484 | } |
485 | } |
486 | |
487 | $scope->provider->source = $thinnedProcess->scope->provider->source ?? null; |
488 | } |
489 | |
490 | return $scope; |
491 | } |
492 | |
493 | private static function createRequests(ThinnedProcess $thinnedProcess): array |
494 | { |
495 | $providerSource = $thinnedProcess->scope->provider->source ?? 'dldb'; |
496 | |
497 | $requests = []; |
498 | $mainServiceId = $thinnedProcess->serviceId ?? null; |
499 | $mainServiceName = $thinnedProcess->serviceName ?? null; |
500 | $mainServiceCount = $thinnedProcess->serviceCount ?? 0; |
501 | |
502 | for ($i = 0; $i < $mainServiceCount; $i++) { |
503 | $request = new Request(); |
504 | $request->id = $mainServiceId; |
505 | $request->name = $mainServiceName; |
506 | $request->source = $providerSource; |
507 | $requests[] = $request; |
508 | } |
509 | |
510 | foreach ($thinnedProcess->subRequestCounts ?? [] as $subRequest) { |
511 | $subId = $subRequest['id'] ?? null; |
512 | $subName = $subRequest['name'] ?? null; |
513 | $count = (int)($subRequest['count'] ?? 0); |
514 | |
515 | for ($i = 0; $i < $count; $i++) { |
516 | $request = new Request(); |
517 | $request->id = $subId; |
518 | $request->name = $subName; |
519 | $request->source = $providerSource; |
520 | $requests[] = $request; |
521 | } |
522 | } |
523 | |
524 | return $requests; |
525 | } |
526 | |
527 | /** |
528 | * Converts a raw or existing contact object/array into a ThinnedContact model. |
529 | * |
530 | * @param object|array $contact |
531 | * @return ThinnedContact |
532 | */ |
533 | public static function contactToThinnedContact($contact): ThinnedContact |
534 | { |
535 | if (is_array($contact)) { |
536 | return new ThinnedContact( |
537 | city: $contact['city'] ?? null, |
538 | country: $contact['country'] ?? null, |
539 | name: $contact['name'] ?? null, |
540 | postalCode: isset($contact['postalCode']) ? (is_null($contact['postalCode']) ? null : (string)$contact['postalCode']) : null, |
541 | region: $contact['region'] ?? null, |
542 | street: $contact['street'] ?? null, |
543 | streetNumber: $contact['streetNumber'] ?? null |
544 | ); |
545 | } |
546 | |
547 | return new ThinnedContact( |
548 | city: $contact->city ?? null, |
549 | country: $contact->country ?? null, |
550 | name: $contact->name ?? null, |
551 | postalCode: isset($contact->postalCode) ? (is_null($contact->postalCode) ? null : (string)$contact->postalCode) : null, |
552 | region: $contact->region ?? null, |
553 | street: $contact->street ?? null, |
554 | streetNumber: $contact->streetNumber ?? null |
555 | ); |
556 | } |
557 | |
558 | /** |
559 | * Convert a Provider object to a ThinnedProvider. |
560 | * |
561 | * @param Provider $provider |
562 | * @return ThinnedProvider |
563 | */ |
564 | public static function providerToThinnedProvider(Provider $provider): ThinnedProvider |
565 | { |
566 | return new ThinnedProvider( |
567 | id: isset($provider->id) ? (int) $provider->id : null, |
568 | name: isset($provider->name) ? $provider->name : null, |
569 | displayName: isset($provider->displayName) ? $provider->displayName : null, |
570 | source: isset($provider->source) ? $provider->source : null, |
571 | lon: isset($provider->data['geo']['lon']) ? (float) $provider->data['geo']['lon'] : null, |
572 | lat: isset($provider->data['geo']['lat']) ? (float) $provider->data['geo']['lat'] : null, |
573 | contact: isset($provider->contact) ? self::contactToThinnedContact($provider->contact) : null |
574 | ); |
575 | } |
576 | } |