Lines 97.72% 387 / 396
Methods 92.45% 49 / 53
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 getQueryLastWaitingNumber 100.00% 2 / 2 100.00% 1 / 1 1
 getQueryLastDisplayNumber 0.00% 0 / 2 0.00% 0 / 1 2
 getQueryGivenNumbersInContingent 100.00% 2 / 2 100.00% 1 / 1 1
 getQuerySimpleClusterMatch 100.00% 2 / 2 100.00% 1 / 1 1
 getQuerySimpleDepartmentMatch 100.00% 2 / 2 100.00% 1 / 1 1
 getQueryDepartmentIdByScopeId 100.00% 1 / 1 100.00% 1 / 1 1
 getQueryClusterIdsByScopeId 100.00% 1 / 1 100.00% 1 / 1 1
 getQueryReadImageData 100.00% 2 / 2 100.00% 1 / 1 1
 getQueryWriteImageData 100.00% 2 / 2 100.00% 1 / 1 1
 getQueryDeleteImage 100.00% 2 / 2 100.00% 1 / 1 1
 addJoin 87.50% 7 / 8 0.00% 0 / 1 2.01
 addRequiredJoins 100.00% 19 / 19 100.00% 1 / 1 5
 getEntityMapping 100.00% 83 / 83 100.00% 1 / 1 6
 addConditionScopeId 100.00% 2 / 2 100.00% 1 / 1 1
 addConditionScopeIds 66.66% 4 / 6 0.00% 0 / 1 2.15
 addConditionWithAdminEmail 100.00% 2 / 2 100.00% 1 / 1 1
 addSelectWorkstationCount 100.00% 6 / 6 100.00% 1 / 1 1
 addConditionProviderId 100.00% 2 / 2 100.00% 1 / 1 1
 addConditionDepartmentId 100.00% 2 / 2 100.00% 1 / 1 1
 addConditionClusterId 100.00% 8 / 8 100.00% 1 / 1 1
 reverseEntityMapping 100.00% 71 / 71 100.00% 1 / 1 7
 setEmergencyEntityMapping 100.00% 4 / 4 100.00% 1 / 1 1
 setGhostWorkstationCountEntityMapping 100.00% 3 / 3 100.00% 1 / 1 1
 postProcess 100.00% 3 / 3 100.00% 1 / 1 1
 convertTimestamps 100.00% 10 / 10 100.00% 1 / 1 3
 setDefaultValues 100.00% 32 / 32 100.00% 1 / 1 2
 setIfEmpty 100.00% 3 / 3 100.00% 1 / 1 3
 [BO\Zmsbackend\Query\Base] __construct 88.23% 30 / 34 0.00% 0 / 1 10.16
 [BO\Zmsbackend\Query\Base] __toString n/a 0 / 0 n/a 0 / 0 4
 [BO\Zmsbackend\Query\Base] getName 100.00% 1 / 1 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addSelect 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] setDistinctSelect 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] setResolveLevel 100.00% 3 / 3 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getResolveLevel 100.00% 3 / 3 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getAlias 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getTablename 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addTable 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addTableAlias 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addResolvedReferences 100.00% 11 / 11 100.00% 1 / 1 3
 [BO\Zmsbackend\Query\Base] setWithEntities 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] leftJoin 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] innerJoin 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getSql 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getParameters 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getReferenceMapping 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] expression 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addEntityMapping 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getPrefixed 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getPrefixedList 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addReferenceMapping 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addLimit 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addValues 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] postProcessJoins 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] shouldLoadEntity 100.00% 3 / 3 100.00% 1 / 1 2
5class Scope extends Base implements MappingInterface
6{
7    /**
8     * @var String TABLE mysql table reference
9     */
10    const string TABLE = 'standort';
11
12    const string QUERY_BY_DEPARTMENTID = 'SELECT
13            scope.`StandortID` AS id
14        FROM `standort` scope
15        WHERE
16            scope.`BehoerdenID` = :department_id
17    ';
18
19    public function getQueryLastWaitingNumber(): string
20    {
21        return '
22            SELECT letztewartenr
23            FROM `standort` scope
24            WHERE scope.`StandortID` = :scope_id LIMIT 1 FOR UPDATE';
25    }
26
27    public function getQueryLastDisplayNumber(): string
28    {
29        return '
30            SELECT last_display_number
31            FROM `standort` scope
32            WHERE scope.`StandortID` = :scope_id LIMIT 1 FOR UPDATE';
33    }
34
35    public function getQueryGivenNumbersInContingent(): string
36    {
37        return '
38            SELECT *
39            FROM `standort` scope
40            WHERE
41                scope.`StandortID` = :scope_id AND
42                IF(
43                    scope.`wartenummernkontingent` > 0,
44                    IF(
45                        isNull(scope.`vergebenewartenummern`), 
46                        0, 
47                        scope.`vergebenewartenummern`
48                    ) < scope.`wartenummernkontingent`,
49                    scope.`StandortID`
50                )
51        ';
52    }
53
54    public function getQuerySimpleClusterMatch(): string
55    {
56        return '
57            SELECT s.StandortID AS id, p.name AS contact__name, s.standortkuerzel AS shortName
58            FROM `clusterzuordnung` AS cz
59            INNER JOIN `standort` AS s ON s.StandortID = cz.standortID
60            LEFT JOIN `provider` AS p ON s.InfoDienstleisterID = p.id
61                AND p.source = s.source
62            WHERE
63                cz.clusterID = ?
64        ';
65    }
66
67    public function getQuerySimpleDepartmentMatch(): string
68    {
69        return '
70            SELECT s.StandortID AS id, p.name AS contact__name, s.standortkuerzel AS shortName
71            FROM `standort` AS s
72            LEFT JOIN `provider` AS p ON s.InfoDienstleisterID = p.id
73                AND p.source = s.source
74            WHERE
75                s.BehoerdenID = ?
76        ';
77    }
78
79    public function getQueryDepartmentIdByScopeId(): string
80    {
81        return 'SELECT BehoerdenID FROM standort WHERE StandortID = ?';
82    }
83
84    public function getQueryClusterIdsByScopeId(): string
85    {
86        return 'SELECT clusterID FROM clusterzuordnung WHERE standortID = ?';
87    }
88
89    public function getQueryReadImageData(): string
90    {
91        return '
92            SELECT `imagecontent`, `imagename`
93            FROM `imagedata`
94            WHERE
95                `imagename` LIKE :imagename
96        ';
97    }
98
99    public function getQueryWriteImageData(): string
100    {
101        return '
102            REPLACE INTO `imagedata`
103            SET
104                imagename=:imagename,
105                imagecontent=:imagedata
106        ';
107    }
108
109    public function getQueryDeleteImage(): string
110    {
111        return '
112            DELETE FROM `imagedata`
113            WHERE
114                `imagename` LIKE :imagename
115        ';
116    }
117
118    #[\Override]
119    public function addJoin()
120    {
121        if ($this->shouldLoadEntity('provider')) {
122            $this->leftJoin(
123                new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Provider\Repository\Provider::getTablename(), 'provider'),
124                self::expression('scope.InfoDienstleisterID = provider.id && scope.source = provider.source')
125            );
126            $providerQuery = new \BO\Zmsbackend\Provider\Repository\Provider($this, $this->getPrefixed('provider__'));
127            return [$providerQuery];
128        }
129
130        return [];
131    }
132
133    /**
134     * @return void
135     */
136    #[\Override]
137    protected function addRequiredJoins()
138    {
139
140        if ($this->shouldLoadEntity('scopedepartment')) {
141            $this->leftJoin(
142                new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Department\Repository\Department::TABLE, 'scopedepartment'),
143                'scope.BehoerdenID',
144                '=',
145                'scopedepartment.BehoerdenID'
146            );
147        }
148
149        if ($this->shouldLoadEntity('scopemail') && $this->shouldLoadEntity('scopedepartment')) {
150            $this->leftJoin(
151                new \BO\Zmsbackend\Query\Alias('email', 'scopemail'),
152                'scopedepartment.BehoerdenID',
153                '=',
154                'scopemail.BehoerdenID'
155            );
156        }
157
158        if ($this->shouldLoadEntity('scopeprovider')) {
159            $this->leftJoin(
160                new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Provider\Repository\Provider::getTablename(), 'scopeprovider'),
161                self::expression('scope.InfoDienstleisterID = scopeprovider.id && scope.source = scopeprovider.source')
162            );
163        }
164    }
165
166    //Todo: now() Parameter to enable query cache
167    /**
168     * @return (Builder\Expression|string)[]
169     *
170     */
171    #[\Override]
172    public function getEntityMapping()
173    {
174        return array_filter([
175            'hint' => 'scope.Hinweis',
176            'id' => 'scope.StandortID',
177            'contact__name' => $this->shouldLoadEntity('scopeprovider') ? 'scopeprovider.name' : '',
178            'contact__street' => 'scope.Adresse',
179            'contact__email' => 'scope.emailstandortadmin',
180            'contact__country' => self::expression('"Germany"'),
181            'lastChange' => 'scope.updateTimestamp',
182            'preferences__appointment__deallocationDuration' => 'scope.loeschdauer',
183            'preferences__appointment__infoForAppointment' => 'scope.info_for_appointment',
184            'preferences__appointment__infoForAllAppointments' => 'scope.info_for_all_appointments',
185            'preferences__appointment__endInDaysDefault' => 'scope.Termine_bis',
186            'preferences__appointment__multipleSlotsEnabled' => 'scope.mehrfachtermine',
187            'preferences__appointment__rebookingDisabled' => 'scope.rebooking_disabled',
188            'preferences__appointment__reservationDuration' => 'scope.reservierungsdauer',
189            'preferences__appointment__activationDuration' => 'scope.aktivierungsdauer',
190            'preferences__appointment__startInDaysDefault' => 'scope.Termine_ab',
191            'preferences__client__amendmentActivated' => 'scope.anmerkungPflichtfeld',
192            'preferences__client__amendmentLabel' => 'scope.anmerkungLabel',
193            'preferences__client__emailFrom' => $this->shouldLoadEntity('scopemail')
194                ? 'scopemail.absenderadresse'
195                : '',
196            'preferences__client__emailRequired' => 'scope.emailPflichtfeld',
197            'preferences__client__emailConfirmationActivated' => 'scope.email_confirmation_activated',
198            'preferences__client__telephoneActivated' => 'scope.telefonaktiviert',
199            'preferences__client__telephoneRequired' => 'scope.telefonPflichtfeld',
200            'preferences__client__appointmentsPerMail' => 'scope.appointments_per_mail',
201            'preferences__client__slotsPerAppointment' => 'scope.slots_per_appointment',
202            'preferences__client__whitelistedMails' => 'scope.whitelisted_mails',
203            'preferences__client__customTextfieldActivated' => 'scope.custom_text_field_active',
204            'preferences__client__customTextfieldRequired' => 'scope.custom_text_field_required',
205            'preferences__client__customTextfieldLabel' => 'scope.custom_text_field_label',
206            'preferences__client__customTextfield2Activated' => 'scope.custom_text_field2_active',
207            'preferences__client__customTextfield2Required' => 'scope.custom_text_field2_required',
208            'preferences__client__customTextfield2Label' => 'scope.custom_text_field2_label',
209            'preferences__client__captchaActivatedRequired' => 'scope.captcha_activated_required',
210            'preferences__client__adminMailOnAppointment' => 'scope.admin_mail_on_appointment',
211            'preferences__client__adminMailOnDeleted' => 'scope.admin_mail_on_deleted',
212            'preferences__client__adminMailOnUpdated' => 'scope.admin_mail_on_updated',
213            'preferences__client__adminMailOnMailSent' => 'scope.admin_mail_on_mail_sent',
214            'preferences__queue__callCountMax' => 'scope.anzahlwiederaufruf',
215            'preferences__queue__callDisplayText' => 'scope.aufrufanzeigetext',
216            'preferences__queue__firstNumber' => 'scope.startwartenr',
217            'preferences__queue__lastNumber' => 'scope.endwartenr',
218            'preferences__queue__maxNumberContingent' => 'scope.wartenummernkontingent',
219            'preferences__queue__displayNumberPrefix' => 'scope.display_number_prefix',
220            'preferences__queue__processingTimeAverage' => self::expression(
221                'FLOOR(TIME_TO_SEC(`scope`.`Bearbeitungszeit`) / 60)'
222            ),
223            'preferences__queue__statisticsEnabled' => self::expression('NOT `scope`.`ohnestatistik`'),
224            'preferences__survey__emailContent' => 'scope.kundenbef_emailtext',
225            'preferences__survey__enabled' => 'scope.kundenbefragung',
226            'preferences__survey__label' => 'scope.kundenbef_label',
227            'preferences__ticketprinter__buttonName' => self::expression(
228                'IF(`scope`.`standortinfozeile`!="", `scope`.`standortinfozeile`, `scope`.`Bezeichnung`)'
229            ),
230            'preferences__ticketprinter__deactivatedText' => 'scope.wartenrhinweis',
231            'preferences__workstation__emergencyEnabled' => 'scope.notruffunktion',
232            'preferences__workstation__emergencyRefreshInterval' => self::expression(
233                '(SELECT `value` FROM config WHERE `name`="emergency__refreshInterval")'
234            ),
235            'shortName' => 'scope.standortkuerzel',
236            'status__emergency__acceptedByWorkstation' => 'scope.notrufantwort',
237            'status__emergency__activated' => 'scope.notrufausgeloest',
238            'status__emergency__calledByWorkstation' => 'scope.notrufinitiierung',
239            'status__queue__ghostWorkstationCount' => 'scope.virtuellesachbearbeiterzahl',
240            'status__queue__givenNumberCount' => 'scope.vergebenewartenummern',
241            'status__queue__lastGivenNumber' => 'scope.letztewartenr',
242            'status__queue__lastDisplayNumber' => 'scope.last_display_number',
243            'status__queue__maxDisplayNumber' => 'scope.max_display_number',
244            'status__queue__lastGivenNumberTimestamp' => 'scope.wartenrdatum',
245            'status__ticketprinter__deactivated' => 'scope.wartenrsperre',
246            'provider__id' => $this->shouldLoadEntity('scopeprovider') ? self::expression(
247                'IF(`scopeprovider`.`id`!="", `scopeprovider`.`id`, `scope`.`InfoDienstleisterID`)'
248            ) : '',
249            'provider__source' => $this->shouldLoadEntity('scopeprovider') ? self::expression(
250                'IF(`scopeprovider`.`source`!="", `scopeprovider`.`source`, `scope`.`source`)'
251            ) : '',
252            'provider__data' => $this->shouldLoadEntity('scopeprovider') ? self::expression(
253                'IFNULL(`scopeprovider`.`data`, "{}")'
254            ) : '',
255            'source' => 'scope.source'
256        ], 'strlen');
257    }
258
259    public function addConditionScopeId($scopeId): static
260    {
261        $this->query->where('scope.StandortID', '=', $scopeId);
262        return $this;
263    }
264
265    public function addConditionScopeIds(array $scopeIds): static
266    {
267        $scopeIds = array_values(array_unique(array_map('intval', $scopeIds)));
268        if (!$scopeIds) {
269            $this->query->where(self::expression('1'), '=', 0);
270            return $this;
271        }
272
273        $this->query->whereIn('scope.StandortID', $scopeIds);
274        return $this;
275    }
276
277    public function addConditionWithAdminEmail(): static
278    {
279        $this->query->where('scope.emailstandortadmin', '!=', '');
280        return $this;
281    }
282
283    /**
284     * @psalm-api
285     */
286    public function addSelectWorkstationCount($dateTime): void
287    {
288        $this->query->select(
289            ['status__queue__workstationCount' => self::expression('
290                IF(
291                    `scope`.`virtuellesachbearbeiterzahl` > -1,
292                    `scope`.`virtuellesachbearbeiterzahl`,
293                    (
294                        SELECT COUNT(*)
295                        FROM nutzer
296                        WHERE nutzer.StandortID = scope.StandortID
297                        AND nutzer.Datum = "' . $dateTime->format('Y-m-d') . '"
298                        AND nutzer.Arbeitsplatznr <> 0
299                    )
300                )
301            ')
302            ]
303        );
304    }
305
306    public function addConditionProviderId($providerId): static
307    {
308        $this->query->where('scope.InfoDienstleisterID', '=', $providerId);
309        return $this;
310    }
311
312    public function addConditionDepartmentId($departmentId): static
313    {
314        $this->query->where('scope.BehoerdenID', '=', $departmentId);
315        return $this;
316    }
317
318    public function addConditionClusterId($clusterId): static
319    {
320        $this->leftJoin(
321            new \BO\Zmsbackend\Query\Alias('clusterzuordnung', 'cluster_scope'),
322            'scope.StandortID',
323            '=',
324            'cluster_scope.standortID'
325        );
326        $this->query->where('cluster_scope.clusterID', '=', $clusterId);
327        return $this;
328    }
329
330    /**
331     * @return (int|mixed|string)[]
332     *
333     */
334    public function reverseEntityMapping(\BO\Zmsentities\Scope $entity, $parentId = null): array
335    {
336        $data = array();
337        if ($parentId) {
338            $data['BehoerdenID'] = $parentId;
339        }
340        $data['InfoDienstleisterID'] = $entity->getProviderId();
341        $data['emailstandortadmin'] = $entity->getContactEMail();
342        $data['standortinfozeile'] = $entity->getScopeInfo();
343        $data['Hinweis'] = $entity->getScopeHint();
344        $data['Bezeichnung'] = $entity->getName();
345        $data['standortkuerzel'] = $entity->shortName;
346        $data['Adresse'] = (isset($entity->contact['street'])) ? $entity->contact['street'] : '';
347        $data['loeschdauer'] = $entity->getPreference('appointment', 'deallocationDuration');
348        $data['info_for_appointment'] = $entity->getPreference('appointment', 'infoForAppointment');
349        $data['info_for_all_appointments'] = $entity->getPreference('appointment', 'infoForAllAppointments');
350        $data['Termine_bis'] = $entity->getPreference('appointment', 'endInDaysDefault');
351        $data['Termine_ab'] = $entity->getPreference('appointment', 'startInDaysDefault');
352        $data['mehrfachtermine'] = $entity->getPreference('appointment', 'multipleSlotsEnabled', true);
353        $data['rebooking_disabled'] = $entity->getPreference('appointment', 'rebookingDisabled', true);
354        $data['reservierungsdauer'] = $entity->getPreference('appointment', 'reservationDuration');
355        $data['aktivierungsdauer'] = $entity->getPreference('appointment', 'activationDuration');
356        $data['anmerkungPflichtfeld'] = $entity->getPreference('client', 'amendmentActivated', true);
357        $data['anmerkungLabel'] = $entity->getPreference('client', 'amendmentLabel');
358        $data['emailPflichtfeld'] = $entity->getPreference('client', 'emailRequired', true);
359        $data['email_confirmation_activated'] = $entity->getPreference('client', 'emailConfirmationActivated', true);
360        $data['telefonaktiviert'] = $entity->getPreference('client', 'telephoneActivated', true);
361        $data['telefonPflichtfeld'] = $entity->getPreference('client', 'telephoneRequired', true);
362        $data['custom_text_field_active'] = $entity->getPreference('client', 'customTextfieldActivated', true);
363        $data['custom_text_field_required'] = $entity->getPreference('client', 'customTextfieldRequired', true);
364        $data['custom_text_field_label'] = $entity->getPreference('client', 'customTextfieldLabel');
365        $data['custom_text_field2_active'] = $entity->getPreference('client', 'customTextfield2Activated', true);
366        $data['custom_text_field2_required'] = $entity->getPreference('client', 'customTextfield2Required', true);
367        $data['custom_text_field2_label'] = $entity->getPreference('client', 'customTextfield2Label');
368        $data['captcha_activated_required'] = $entity->getPreference('client', 'captchaActivatedRequired');
369        $data['appointments_per_mail'] = (int) $entity->getPreference('client', 'appointmentsPerMail');
370        $data['slots_per_appointment'] = (int) $entity->getPreference('client', 'slotsPerAppointment');
371        $data['info_for_appointment'] = $entity->getPreference('appointment', 'infoForAppointment');
372        $data['whitelisted_mails'] = $entity->getPreference('client', 'whitelistedMails');
373        $data['admin_mail_on_appointment'] = $entity->getPreference('client', 'adminMailOnAppointment', true);
374        $data['admin_mail_on_deleted'] = $entity->getPreference('client', 'adminMailOnDeleted');
375        $data['admin_mail_on_updated'] = $entity->getPreference('client', 'adminMailOnUpdated', true);
376        $data['admin_mail_on_mail_sent'] = $entity->getPreference('client', 'adminMailOnMailSent', true);
377        $data['anzahlwiederaufruf'] = $entity->getPreference('queue', 'callCountMax');
378        $data['aufrufanzeigetext'] = $entity->getPreference('queue', 'callDisplayText', false, '');
379        $data['startwartenr'] = $entity->getPreference('queue', 'firstNumber');
380        $data['endwartenr'] = $entity->getPreference('queue', 'lastNumber');
381        $data['wartenummernkontingent'] = $entity->getPreference('queue', 'maxNumberContingent');
382        $data['display_number_prefix'] = $entity->getPreference('queue', 'displayNumberPrefix')
383            ? strtoupper($entity->getPreference('queue', 'displayNumberPrefix'))
384            : '';
385        $data['Bearbeitungszeit'] = gmdate("H:i", $entity->getPreference('queue', 'processingTimeAverage') * 60);
386        $data['ohnestatistik'] = (0 == $entity->getPreference('queue', 'statisticsEnabled', true)) ? 1 : 0;
387        $data['kundenbef_emailtext'] = $entity->getPreference('survey', 'emailContent');
388        $data['kundenbefragung'] = $entity->getPreference('survey', 'enabled', true);
389        $data['kundenbef_label'] = $entity->getPreference('survey', 'label');
390        $data['wartenrhinweis'] = $entity->getPreference('ticketprinter', 'deactivatedText', false, '');
391        $data['notruffunktion'] = $entity->getPreference('workstation', 'emergencyEnabled', true);
392        $data['notrufantwort'] = $entity->getStatus('emergency', 'acceptedByWorkstation');
393        $data['notrufausgeloest'] = $entity->getStatus('emergency', 'activated');
394        $data['notrufinitiierung'] = $entity->getStatus('emergency', 'calledByWorkstation');
395        $data['virtuellesachbearbeiterzahl'] = $entity->getStatus('queue', 'ghostWorkstationCount');
396        $data['vergebenewartenummern'] = $entity->getStatus('queue', 'givenNumberCount');
397        $data['letztewartenr'] = $entity->getStatus('queue', 'lastGivenNumber');
398        $data['last_display_number'] = $entity->getStatus('queue', 'lastDisplayNumber');
399        $data['max_display_number'] = $entity->getStatus('queue', 'maxDisplayNumber');
400        $lastGivenTimestamp = $entity->getStatus('queue', 'lastGivenNumberTimestamp');
401        $data['wartenrdatum'] = ($lastGivenTimestamp) ? date('Y-m-d', $lastGivenTimestamp) : null;
402        $data['wartenrsperre'] = $entity->getStatus('ticketprinter', 'deactivated');
403        $data['source'] = $entity->getProvider()->source;
404
405        $data = array_filter($data, function ($value) {
406            return ($value !== null && $value !== false);
407        });
408        return $data;
409    }
410
411    /**
412     * @return (int|mixed)[]
413     *
414     */
415    public function setEmergencyEntityMapping(\BO\Zmsentities\Scope $entity): array
416    {
417        $data['notrufantwort'] = ($entity->toProperty()->status->emergency->acceptedByWorkstation->get(-1));
418        $data['notrufausgeloest'] = intval($entity->toProperty()->status->emergency->activated->get(0));
419        $data['notrufinitiierung'] = ($entity->toProperty()->status->emergency->calledByWorkstation->get(-1));
420        return $data;
421    }
422
423    /**
424     * @return (mixed|string)[]
425     *
426     */
427    public function setGhostWorkstationCountEntityMapping(\BO\Zmsentities\Scope $entity, \DateTimeInterface $dateTime): array
428    {
429        $data['virtuellesachbearbeiterzahl'] = $entity->getStatus('queue', 'ghostWorkstationCount');
430        $data['datumvirtuellesachbearbeiterzahl'] = $dateTime->format('Y-m-d');
431        return $data;
432    }
433
434    #[\Override]
435    public function postProcess($data)
436    {
437        $data = $this->convertTimestamps($data);
438        $data = $this->setDefaultValues($data);
439        return $data;
440    }
441
442
443    private function convertTimestamps($data)
444    {
445        $lastGivenNumberTimestampKey = $this->getPrefixed("status__queue__lastGivenNumberTimestamp");
446        $lastGivenNumberTimestamp = $data[$lastGivenNumberTimestampKey] ?? null;
447        $data[$lastGivenNumberTimestampKey] = $lastGivenNumberTimestamp !== null ? strtotime($lastGivenNumberTimestamp) : null;
448
449        $lastChangeKey = $this->getPrefixed("lastChange");
450        $lastChange = $data[$lastChangeKey] ?? null;
451        if ($lastChange !== null) {
452            $data[$lastChangeKey] = (new \DateTime($lastChange . \BO\Zmsbackend\Connection\Select::$connectionTimezone))
453                ->getTimestamp();
454        } else {
455            $data[$lastChangeKey] = null;
456        }
457
458        return $data;
459    }
460
461    private function setDefaultValues($data)
462    {
463        if ($this->shouldLoadEntity('scopemail')) {
464            $this->setIfEmpty($data, 'preferences__client__emailFrom', [
465                'preferences__client__emailRequired' => 0
466            ]);
467        }
468
469        $this->setIfEmpty($data, 'preferences__client__telephoneActivated', [
470            'preferences__client__telephoneRequired' => 0
471        ]);
472
473        $this->setIfEmpty($data, 'preferences__client__emailConfirmationActivated', [
474            'preferences__client__emailConfirmationActivated' => 0
475        ]);
476
477        $this->setIfEmpty($data, 'contact__email', [
478            'preferences__client__adminMailOnAppointment' => 0,
479            'preferences__client__adminMailOnDeleted' => 0,
480            'preferences__client__adminMailOnUpdated' => 0,
481            'preferences__client__adminMailOnMailSent' => 0,
482        ]);
483
484        $this->setIfEmpty($data, 'preferences__client__customTextfieldActivated', [
485            'preferences__client__customTextfieldRequired' => 0
486        ]);
487
488        $this->setIfEmpty($data, 'preferences__client__customTextfield2Activated', [
489            'preferences__client__customTextfield2Required' => 0
490        ]);
491
492        $this->setIfEmpty($data, 'preferences__client__appointmentsPerMail', [
493            'preferences__client__appointmentsPerMail' => null
494        ]);
495
496        $this->setIfEmpty($data, 'preferences__client__slotsPerAppointment', [
497            'preferences__client__slotsPerAppointment' => null
498        ]);
499
500        $this->setIfEmpty($data, 'preferences__client__whitelistedMails', [
501            'preferences__client__whitelistedMails' => null
502        ]);
503
504        return $data;
505    }
506
507    private function setIfEmpty(&$data, string $checkKey, array $setKeys): void
508    {
509        if (!$data[$this->getPrefixed($checkKey)]) {
510            foreach ($setKeys as $key => $value) {
511                $data[$this->getPrefixed($key)] = $value;
512            }
513        }
514    }
515}

Inherited from BO\Zmsbackend\Query\Base

96    public function __construct(
97        $queryType,
98        $prefix = '',
99        string|false $name = false,
100        mixed $resolveLevel = null,
101        array $withEntities = []
102    ) {
103        $this->prefix = $prefix;
104        $this->name = $name;
105        $this->withEntities = $withEntities;
106        $this->setResolveLevel($resolveLevel);
107        $dialect = new MySQL();
108        if (self::SELECT === $queryType) {
109            $this->query = new Select($dialect);
110            $this->addSelect();
111        } elseif (self::INSERT === $queryType) {
112            $this->query = new Insert($dialect);
113            $this->addTable();
114        } elseif (self::UPDATE === $queryType) {
115            $this->query = new Update($dialect);
116            $this->addTableAlias();
117        } elseif (self::REPLACE === $queryType) {
118            $this->query = new INSERT($dialect);
119            $this->query->queryBaseStatement('REPLACE INTO');
120            $this->addTable();
121        } elseif (self::DELETE === $queryType) {
122            $this->query = new Delete($dialect);
123            $this->query->queryBaseStatement('DELETE ' . $this::getAlias() . ' FROM');
124            $this->addTableAlias();
125        } elseif ($queryType instanceof self) {
126            $this->query = $queryType->query;
127            // Share join-alias state with the parent query (intentional by-ref).
128            /** @psalm-suppress UnsupportedPropertyReferenceUsage */
129            $this->joinedAliasList =& $queryType->joinedAliasList;
130            $this->resolveLevel = $queryType->resolveLevel - 1;
131        } elseif ($queryType instanceof QueryBuilder) {
132            $this->query = $queryType;
133        } else {
134            throw new \InvalidArgumentException(
135                'Unsupported query type for ' . static::class . ': '
136                . (is_object($queryType) ? $queryType::class : gettype($queryType))
137            );
138        }
139        if ($this->query instanceof Select) {
140            $this->addRequiredJoins();
141        }
142    }
147    public function __toString()
148    {
149        if ($this->name) {
150            $name = $this->name . '_' . $this->prefix . (string) $this->resolveLevel;
151            if (!isset(static::$sqlCache[$name])) {
152                static::$sqlCache[$name] = $this->getSql();
153            }
154            return static::$sqlCache[$name];
155        }
156        if ($this->currentSqlString) {
157            $sql = $this->currentSqlString;
158        } else {
159            $sql = $this->getSql();
160        }
161        return $sql;
162    }
164    public function getName()
165    {
166        return $this->name ? $this->name : get_class($this);
167    }
174    protected function addSelect(): static
175    {
176        $table = $this::getTablename();
177        $alias = $this::getAlias();
178        $this->query->from($table, $alias);
179        return $this;
180    }
182    public function setDistinctSelect(): void
183    {
184        $this->query->queryBaseStatement('SELECT DISTINCT');
185    }
187    public function setResolveLevel(int|null $resolveLevel): static
188    {
189        if ($resolveLevel !== null) {
190            $this->resolveLevel = $resolveLevel;
191        }
192        return $this;
193    }
195    public function getResolveLevel()
196    {
197        if (null === $this->resolveLevel) {
198            throw new \Exception("Required setting for resolveReferenceLevel missing in " . get_class($this));
199        }
200        return $this->resolveLevel;
201    }
210    public static function getAlias()
211    {
212        $class = get_called_class();
213        $alias = constant($class . '::ALIAS');
214        if (null === $alias) {
215            $alias = lcfirst(preg_replace('#^.*\\\#', '', $class));
216        }
217        return $alias;
218    }
225    public static function getTablename()
226    {
227        $class = get_called_class();
228        $table = constant($class . '::TABLE');
229        return $table;
230    }
237    protected function addTable(): static
238    {
239        $table = $this::getTablename();
240        $alias = $this::getAlias();
241        $this->query->table($table, $alias);
242        return $this;
243    }
250    protected function addTableAlias(): static
251    {
252        $table = $this::getTablename();
253        $alias = $this::getAlias();
254        $this->query->table(self::expression($table . ' ' . $alias));
255        return $this;
256    }
273    public function addResolvedReferences($depth): static
274    {
275        $this->setResolveLevel($depth);
276        if ($depth > 0) {
277            $queryList = $this->addJoin();
278            foreach ($queryList as $query) {
279                $query->setResolveLevel($depth);
280                $query->setWithEntities($this->withEntities);
281                $query->addResolvedReferences($depth - 1);
282                $query->addEntityMapping();
283            }
284            $this->joinedQueryList = $queryList;
285        } else {
286            $this->addReferenceMapping();
287        }
288        return $this;
289    }
294    public function setWithEntities($withEntities = []): void
295    {
296        $this->withEntities = $withEntities;
297    }
309    protected function leftJoin(Alias $alias, string|Expression|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder
310    {
311        $aliasId = $alias->getAliasIdentifier();
312        if (!in_array($aliasId, $this->joinedAliasList)) {
313            $this->joinedAliasList[] = $aliasId;
314            $this->query->leftJoin($alias, $left, $operator, $right);
315        } else {
316            //throw new \Exception("Tried to add Alias ".$aliasId);
317        }
318        return $this->query;
319    }
321    protected function innerJoin(Alias $alias, string|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder
322    {
323        $aliasId = $alias->getAliasIdentifier();
324        if (!in_array($aliasId, $this->joinedAliasList)) {
325            $this->joinedAliasList[] = $aliasId;
326            $this->query->join($alias, $left, $operator, $right);
327        }
328        return $this->query;
329    }
337    public function getSql()
338    {
339        $this->currentSqlString = (string)$this->query;
340        return $this->currentSqlString;
341    }
348    public function getParameters()
349    {
350        return $this->query->params();
351    }
357    public function getReferenceMapping()
358    {
359        return [
360        ];
361    }
368    protected static function expression(string $string)
369    {
370        return new Expression($string);
371    }
379    public function addEntityMapping(mixed $type = null): static
380    {
381        // Concrete query classes provide getEntityMapping(); not all declare MappingInterface.
382        /** @psalm-suppress UndefinedMethod, TooManyArguments */
383        $entityMapping = $this->getPrefixedList($this->getEntityMapping($type));
384        $this->query->select($entityMapping);
385        return $this;
386    }
388    protected function getPrefixed($prefix): string
389    {
390        return $this->prefix . $prefix;
391    }
393    protected function getPrefixedList(array $unprefixedList): array
394    {
395        $prefixed = [];
396        foreach ($unprefixedList as $key => $value) {
397            $prefixed[$this->getPrefixed($key)] = $value;
398        }
399        return $prefixed;
400    }
405    protected function addReferenceMapping(): static
406    {
407        $referenceMapping = $this->getPrefixedList($this->getReferenceMapping());
408        $this->query->select($referenceMapping);
409        return $this;
410    }
412    public function addLimit(int $count, ?int $offset = null): static
413    {
414        $this->query->limit($count);
415        if ($offset) {
416            $this->query->offset($offset);
417        }
418        return $this;
419    }
424    public function addValues(array $values): static
425    {
426        $this->query->values($values);
427        return $this;
428    }
445    public function postProcessJoins(array $data)
446    {
447        $data = $this->postProcess($data);
448        foreach ($this->joinedQueryList as $query) {
449            $data = $query->postProcess($data);
450        }
451        return $data;
452    }
454    public function shouldLoadEntity(string $name): bool
455    {
456        if (empty($this->withEntities)) {
457            return true;
458        }
459
460        return in_array($name, $this->withEntities);
461    }