Lines 85.62% 393 / 459
Methods 69.44% 75 / 108
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 [BO\Zmsentities\Process] getDefaults 100.00% 26 / 26 100.00% 1 / 1 1
 [BO\Zmsentities\Process] createFromScope 100.00% 9 / 9 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getRequests 100.00% 7 / 7 100.00% 1 / 1 4
 [BO\Zmsentities\Process] getRequestIds 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getDisplayNumber 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getRequestCSV 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] addScope 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Process] addQueue 100.00% 6 / 6 100.00% 1 / 1 1
 [BO\Zmsentities\Process] addRequests 100.00% 8 / 8 100.00% 1 / 1 3
 [BO\Zmsentities\Process] updateRequests 100.00% 8 / 8 100.00% 1 / 1 3
 [BO\Zmsentities\Process] hasScopeAdmin 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] sendAdminMailOnConfirmation 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] sendAdminMailOnDeleted 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] sendAdminMailOnUpdated 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] shouldSendAdminMailOnClerkMail 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] withUpdatedData 100.00% 11 / 11 100.00% 1 / 1 3
 [BO\Zmsentities\Process] addAppointmentFromRequest 100.00% 14 / 14 100.00% 1 / 1 4
 [BO\Zmsentities\Process] addClientFromForm 100.00% 7 / 7 100.00% 1 / 1 5
 [BO\Zmsentities\Process] setStatus 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getStatus 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getReminderTimestamp 100.00% 2 / 2 100.00% 1 / 1 2
 [BO\Zmsentities\Process] addReminderTimestamp 100.00% 5 / 5 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getAppointments 100.00% 8 / 8 100.00% 1 / 1 4
 [BO\Zmsentities\Process] getClients 87.50% 7 / 8 0.00% 0 / 1 4.03
 [BO\Zmsentities\Process] hasAppointment 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] isWithAppointment 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsentities\Process] hasProcessCredentials 100.00% 1 / 1 100.00% 1 / 1 4
 [BO\Zmsentities\Process] withReassignedCredentials 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsentities\Process] hasQueueNumber 100.00% 1 / 1 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getQueueNumber 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] addAppointment 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getScopeId 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] isDereferenced 0.00% 0 / 4 0.00% 0 / 1 12
 [BO\Zmsentities\Process] getCurrentScope 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getAmendment 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getShowUpTime 0.00% 0 / 6 0.00% 0 / 1 6
 [BO\Zmsentities\Process] getWaitingTime 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] getProcessingTime 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] getFinishTime 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] addData 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Process] normalizePlainTextFields 92.30% 12 / 13 0.00% 0 / 1 8.03
 [BO\Zmsentities\Process] addAmendment 100.00% 4 / 4 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getCustomTextfield 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] addCustomTextfield 100.00% 5 / 5 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getCustomTextfield2 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] addCustomTextfield2 100.00% 5 / 5 100.00% 1 / 1 3
 [BO\Zmsentities\Process] addPriority 100.00% 2 / 2 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getAuthKey 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getPriority 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] setRandomAuthKey 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] setCallTime 100.00% 2 / 2 100.00% 1 / 1 2
 [BO\Zmsentities\Process] getCallTimeString 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getCallTime 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsentities\Process] getFirstClient 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsentities\Process] getFirstAppointment 100.00% 6 / 6 100.00% 1 / 1 2
 [BO\Zmsentities\Process] setStatusBySettings 85.71% 6 / 7 0.00% 0 / 1 4.05
 [BO\Zmsentities\Process] setClientsCount 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsentities\Process] withoutPersonalData 100.00% 6 / 6 100.00% 1 / 1 2
 [BO\Zmsentities\Process] withLessData 100.00% 31 / 31 100.00% 1 / 1 21
 [BO\Zmsentities\Process] toCalendar 100.00% 9 / 9 100.00% 1 / 1 1
 [BO\Zmsentities\Process] toQueue 92.30% 12 / 13 0.00% 0 / 1 6.02
 [BO\Zmsentities\Process] hasArrivalTime 100.00% 4 / 4 100.00% 1 / 1 3
 [BO\Zmsentities\Process] getArrivalTime 72.72% 8 / 11 0.00% 0 / 1 4.32
 [BO\Zmsentities\Process] setArrivalTime 0.00% 0 / 2 0.00% 0 / 1 6
 [BO\Zmsentities\Process] getWaitedSeconds 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getWaitedMinutes 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getWaySeconds 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] getWayMinutes 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] setWasMissed 0.00% 0 / 3 0.00% 0 / 1 2
 [BO\Zmsentities\Process] isWasMissed 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] toDerefencedAmendment 100.00% 8 / 8 100.00% 1 / 1 1
 [BO\Zmsentities\Process] toDerefencedCustomTextfield 0.00% 0 / 8 0.00% 0 / 1 2
 [BO\Zmsentities\Process] toDerefencedCustomTextfield2 0.00% 0 / 8 0.00% 0 / 1 2
 [BO\Zmsentities\Process] __toString 100.00% 15 / 15 100.00% 1 / 1 5
 [BO\Zmsentities\Process] getExternalUserId 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Process] setExternalUserId 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Process] getParkedBy 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Process] setParkedBy 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] __construct 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] exchangeArray 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] offsetSet 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] getUnflattenedArray 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] getValidator 100.00% 6 / 6 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] isValid 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] testValid 100.00% 7 / 7 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] createExample 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] getExample 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] readJsonSchema 66.66% 6 / 9 0.00% 0 / 1 3.33
 [BO\Zmsentities\Schema\Entity] getEntityName 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] setJsonCompressLevel 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] jsonSerialize 100.00% 11 / 11 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] __get 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] __isset 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] __set 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] __unset 0.00% 0 / 1 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] __clone 100.00% 3 / 3 100.00% 1 / 1 3
 [BO\Zmsentities\Schema\Entity] withData 0.00% 0 / 3 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] hasId 100.00% 1 / 1 100.00% 1 / 1 2
 [BO\Zmsentities\Schema\Entity] getId 100.00% 2 / 2 100.00% 1 / 1 3
 [BO\Zmsentities\Schema\Entity] toProperty 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] hasProperty 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] getProperty 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] withProperty 0.00% 0 / 3 0.00% 0 / 1 2
 [BO\Zmsentities\Schema\Entity] withCleanedUpFormData 100.00% 6 / 6 100.00% 1 / 1 3
 [BO\Zmsentities\Schema\Entity] getResolveLevel 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] setResolveLevel 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsentities\Schema\Entity] withResolveLevel 100.00% 9 / 9 100.00% 1 / 1 5
 [BO\Zmsentities\Schema\Entity] withReference 100.00% 5 / 5 100.00% 1 / 1 2
14class Processarchived extends Process
15{
16    public static $schema = "processarchived.json";
17}

Inherited from BO\Zmsentities\Process

50    public function getDefaults()
51    {
52        return [
53            'amendment' => '',
54            'customTextfield' => '',
55            'customTextfield2' => '',
56            'appointments' => new Collection\AppointmentList(),
57            'apiclient' => new Apiclient(),
58            'authKey' => '',
59            'captchaToken' => '',
60            'clients' => new Collection\ClientList(),
61            'createIP' => '',
62            'createTimestamp' => time(),
63            'id' => 0,
64            'archiveId' => 0,
65            'queue' => new Queue(),
66            'reminderTimestamp' => 0,
67            'requests' => new Collection\RequestList(),
68            'scope' => new Scope(),
69            'status' => 'free',
70            'displayNumber' => '',
71            'dbstatus' => 'free',
72            'lastChange' => time(),
73            'wasMissed' => false,
74            'priority' => null,
75            'externalUserId' => null,
76            'parkedBy' => null,
77        ];
78    }
80    public static function createFromScope(Scope $scope, \DateTimeInterface $dateTime): static
81    {
82        $appointment = new Appointment();
83        $appointment->addScope($scope->id);
84        $appointment->addSlotCount(0);
85        $appointment->addDate(Helper\DateTime::create($dateTime)->modify('00:00:00')->getTimestamp());
86        $process = new static();
87        $process->scope = $scope;
88        $process->setStatus('queued');
89        $process->addAppointment($appointment);
90        return $process;
91    }
97    public function getRequests()
98    {
99        if (!$this->requests instanceof Collection\RequestList) {
100            $requestList = new Collection\RequestList();
101            foreach ($this->requests as $request) {
102                $request = ($request instanceof Request) ? $request : new Request($request);
103                $requestList->addEntity($request);
104            }
105            $this->requests = $requestList;
106        }
107        return $this->requests;
108    }
110    public function getRequestIds(): mixed
111    {
112        return $this->getRequests()->getIds();
113    }
115    public function getDisplayNumber(): mixed
116    {
117        return $this->displayNumber;
118    }
120    public function getRequestCSV(): string
121    {
122        return $this->getRequests()->getIdsCsv();
123    }
125    public function addScope(mixed $scopeId): static
126    {
127        $this->scope = new Scope(array('id' => $scopeId));
128        return $this;
129    }
131    public function addQueue(mixed $number, \DateTimeInterface $dateTime): static
132    {
133        $this->queue = new Queue(array(
134            'number' => $number,
135            'arrivalTime' => $dateTime->getTimestamp(),
136            'priority' => $this->getPriority()
137        ));
138        return $this;
139    }
141    public function addRequests(mixed $source, mixed $requestCSV): static
142    {
143        $requestList = $this->getRequests();
144        foreach (explode(',', $requestCSV) as $id) {
145            if (!$requestList->hasRequests($id)) {
146                $this->requests[] = new Request(array(
147                    'source' => $source,
148                    'id' => $id
149                ));
150            }
151        }
152        return $this;
153    }
155    public function updateRequests(mixed $source, int|string $requestCSV = ''): static
156    {
157        $this->requests = new Collection\RequestList();
158        if ($requestCSV) {
159            foreach (explode(',', (string) $requestCSV) as $id) {
160                $this->requests->addEntity(new Request(array(
161                            'source' => $source,
162                            'id' => $id
163                        )));
164            }
165        }
166        return $this;
167    }
169    public function hasScopeAdmin(): bool
170    {
171        return ('' != $this->toProperty()->scope->contact->email->get());
172    }
174    public function sendAdminMailOnConfirmation(): bool
175    {
176        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnAppointment->get());
177    }
179    public function sendAdminMailOnDeleted(): bool
180    {
181        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnDeleted->get());
182    }
184    public function sendAdminMailOnUpdated(): bool
185    {
186        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnUpdated->get());
187    }
189    public function shouldSendAdminMailOnClerkMail(): bool
190    {
191        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnMailSent->get());
192    }
194    public function withUpdatedData(mixed $requestData, \DateTimeInterface $dateTime, mixed $scope = null, string $notice = ''): static
195    {
196        $this->scope = ($scope) ? $scope : $this->scope;
197        $this->addAppointmentFromRequest($requestData, $dateTime);
198        $requestCsv = isset($requestData['requests']) ? implode(',', $requestData['requests']) : 0;
199        $this->updateRequests($scope->getSource(), $requestCsv);
200        $this->addClientFromForm($requestData);
201        $this->addReminderTimestamp($requestData, $dateTime);
202        $this->addAmendment($requestData, $notice);
203        $this->addCustomTextfield($requestData);
204        $this->addCustomTextfield2($requestData);
205        $this->addPriority($requestData);
206        return $this;
207    }
209    public function addAppointmentFromRequest(mixed $requestData, \DateTimeInterface $dateTime): static
210    {
211        $this->appointments = null;
212        if (isset($requestData['selecteddate'])) {
213            $dateTime = new \DateTime($requestData['selecteddate']);
214        }
215        $dateTime = Helper\DateTime::create($dateTime);
216        if (isset($requestData['selectedtime'])) {
217            $time = explode('-', $requestData['selectedtime']);
218            $dateTime = $dateTime->setTime((int) $time[0], (int) $time[1]);
219        }
220
221        $appointment = (new Appointment())
222            ->addDate($dateTime->getTimestamp())
223            ->addScope($this->scope['id']);
224        if (isset($requestData['slotCount'])) {
225            $appointment->addSlotCount($requestData['slotCount']);
226        }
227        $this->addAppointment($appointment);
228        return $this;
229    }
231    public function addClientFromForm(mixed $requestData): static
232    {
233        $client = new Client();
234        foreach ($requestData as $key => $value) {
235            if (null !== $value && $client->offsetExists($key)) {
236                $client[$key] = (isset($value['value'])) ? $value['value'] : $value;
237            }
238        }
239        $this->clients = array();
240        $this->clients[] = $client;
241        return $this;
242    }
244    public function setStatus(string $status): static
245    {
246        $this->status = $status;
247        return $this;
248    }
250    public function getStatus(): mixed
251    {
252        return $this->status;
253    }
255    public function getReminderTimestamp(): mixed
256    {
257        $timestamp = $this->toProperty()->reminderTimestamp->get();
258        return ($timestamp) ? $timestamp : 0;
259    }
261    public function addReminderTimestamp(mixed $input, \DateTimeInterface $dateTime): static
262    {
263        $this->reminderTimestamp = (
264            Property::__keyExists('headsUpTime', $input) &&
265            $input['headsUpTime'] > 0
266        ) ? $dateTime->getTimestamp() - $input['headsUpTime'] : 0;
267        return $this;
268    }
274    public function getAppointments()
275    {
276        $appointments = $this['appointments'];
277        if (!$appointments instanceof Collection\AppointmentList) {
278            $appointments = new Collection\AppointmentList($appointments);
279            foreach ($appointments as $index => $appointment) {
280                if (!$appointment instanceof Appointment) {
281                    $appointments[$index] = new Appointment($appointment);
282                }
283            }
284            $this['appointments'] = $appointments;
285        }
286        return $appointments;
287    }
293    public function getClients()
294    {
295        $clients = $this['clients'];
296        if (!$clients instanceof Collection\ClientList) {
297            $clients = new Collection\ClientList($clients);
298            foreach ($clients as $index => $client) {
299                if (!$client instanceof Client) {
300                    $clients[$index] = new Client($client);
301                }
302            }
303            $this['clients'] = $clients;
304        }
305        return $clients;
306    }
308    public function hasAppointment(mixed $date, mixed $scopeId): bool
309    {
310        return $this->getAppointments()->hasDateScope($date, $scopeId);
311    }
317    public function isWithAppointment(): bool
318    {
319        $appointment = $this->getFirstAppointment();
320        if ($appointment->hasTime()) {
321            return true;
322        }
323        return (1 == $this->toProperty()->queue->withAppointment->get());
324    }
326    public function hasProcessCredentials(): bool
327    {
328        return (isset($this['id']) && isset($this['authKey']) && $this['id'] && $this['authKey']);
329    }
331    public function withReassignedCredentials(mixed $process): static
332    {
333        $this->id = $process->getId();
334        $this->authKey = $process->getAuthKey();
335        return $this;
336    }
338    public function hasQueueNumber(): bool
339    {
340        return (isset($this['queue']) && isset($this['queue']['number']) && $this['queue']['number']);
341    }
343    public function getQueueNumber(): mixed
344    {
345        return $this['queue']['number'];
346    }
348    public function addAppointment(Appointment $newappointment): static
349    {
350        $this->appointments[] = $newappointment;
351        return $this;
352    }
361    public function getScopeId(): mixed
362    {
363        //as current scope - see zmsbackend Query/Process EntityMapping
364        return $this->toProperty()->scope->id->get();
365    }
367    public function isDereferenced(): bool
368    {
369        if ($this->authKey === 'deref!0') {
370            return true;
371        }
372        $client = $this->getFirstClient();
373        return isset($client->familyName) && $client->familyName === 'dereferenced';
374    }
376    public function getCurrentScope(): Scope
377    {
378        return $this->getProperty('scope');
379    }
381    public function getAmendment(): mixed
382    {
383        return $this->toProperty()->amendment->get();
384    }
391    public function getShowUpTime(string|\DateTimeInterface $default = 'now', mixed $timezone = null): \BO\Zmsentities\Helper\DateTime
392    {
393        $showUpTime = $this->toProperty()->showUpTime->get();
394        $showDateTime = Helper\DateTime::create($default, $timezone);
395        if ($showUpTime) {
396            list($hours, $minutes, $seconds) = explode(':', $showUpTime);
397            $showDateTime = $showDateTime->setTime(intval($hours), intval($minutes), intval($seconds));
398        }
399        return $showDateTime;
400    }
402    public function getWaitingTime(): mixed
403    {
404        return $this->toProperty()->queue->waitingTime->get();
405    }
407    public function getProcessingTime(): mixed
408    {
409        return $this->toProperty()->processingTime->get();
410    }
412    public function getFinishTime(): mixed
413    {
414        return $this->toProperty()->finishTime->get();
415    }
425    public function addData(array|object $mergeData): static
426    {
427        parent::addData($mergeData);
428        return $this->normalizePlainTextFields($mergeData);
429    }
434    public function normalizePlainTextFields(array|object|null $mergeData = null): static
435    {
436        $mergeKeys = null;
437        if ($mergeData !== null) {
438            $keys = is_array($mergeData)
439                ? array_keys($mergeData)
440                : array_keys(get_object_vars($mergeData));
441            $mergeKeys = array_fill_keys($keys, true);
442        }
443        foreach (['amendment', 'customTextfield', 'customTextfield2'] as $field) {
444            if ($mergeKeys !== null && !isset($mergeKeys[$field])) {
445                continue;
446            }
447            if (!isset($this[$field]) || !is_string($this[$field])) {
448                continue;
449            }
450            // Do not trim here: DB/cron amendments may keep trailing spaces; mutators trim on write.
451            $this[$field] = ProcessPlainText::normalize($this[$field]);
452        }
453        return $this;
454    }
456    public function addAmendment(mixed $input, string $notice = ''): static
457    {
458        $this->amendment = $notice;
459        $this->amendment .= (isset($input['amendment']) && $input['amendment']) ? $input['amendment'] : '';
460        $this->amendment = trim(ProcessPlainText::normalize($this->amendment));
461        return $this;
462    }
464    public function getCustomTextfield(): mixed
465    {
466        return $this->toProperty()->customTextfield->get();
467    }
469    public function addCustomTextfield(mixed $input): static
470    {
471        $this->customTextfield = (
472            isset($input['customTextfield']) && $input['customTextfield']
473        ) ? $input['customTextfield'] : '';
474        $this->customTextfield = trim(ProcessPlainText::normalize($this->customTextfield));
475        return $this;
476    }
478    public function getCustomTextfield2(): mixed
479    {
480        return $this->toProperty()->customTextfield2->get();
481    }
483    public function addCustomTextfield2(mixed $input): static
484    {
485        $this->customTextfield2 = (
486            isset($input['customTextfield2']) && $input['customTextfield2']
487        ) ? $input['customTextfield2'] : '';
488        $this->customTextfield2 = trim(ProcessPlainText::normalize($this->customTextfield2));
489        return $this;
490    }
492    public function addPriority(mixed $input): static
493    {
494        $this->priority = isset($input['priority']) && $input['priority'] ? $input['priority'] : null;
495
496        return $this;
497    }
499    public function getAuthKey(): mixed
500    {
501        return $this->toProperty()->authKey->get();
502    }
504    public function getPriority(): int
505    {
506        return (int) $this->toProperty()->priority->get();
507    }
509    public function setRandomAuthKey(): void
510    {
511        $this->authKey = bin2hex(random_bytes(32));
512    }
514    public function setCallTime(mixed $dateTime = null): static
515    {
516        $this->queue['callTime'] = ($dateTime) ? $dateTime->getTimestamp() : 0;
517        return $this;
518    }
520    public function getCallTimeString(): mixed
521    {
522        return $this->getCallTime()->format('H:i:s');
523    }
525    public function getCallTime(string|\DateTimeInterface $default = 'now', mixed $timezone = null): \BO\Zmsentities\Helper\DateTime
526    {
527        $callTime = $this->toProperty()->queue->callTime->get();
528        $callDateTime = Helper\DateTime::create($default, $timezone);
529        if ($callTime) {
530            $callDateTime = $callDateTime->setTimestamp($callTime);
531        }
532        return $callDateTime;
533    }
535    public function getFirstClient(): Client
536    {
537        $client = $this->getClients()->getFirst();
538        if (!$client) {
539            $client = new Client();
540            $this->clients->addEntity($client);
541        }
542        return $client;
543    }
545    public function getFirstAppointment(): Appointment
546    {
547        $appointment = $this->getAppointments()->getFirst();
548        if (!$appointment) {
549            $appointment = new Appointment();
550            $appointment->scope = $this->scope;
551            $this->appointments->addEntity($appointment);
552        }
553        return $appointment;
554    }
556    public function setStatusBySettings(): static
557    {
558        $scope = new Scope($this->scope);
559        if ('called' == $this->status && $this->queue['callCount'] > $scope->getPreference('queue', 'callCountMax')) {
560            $this->status = 'missed';
561        } elseif ('parked' == $this->status) {
562            $this->status = 'parked';
563        } else {
564            $this->status = 'confirmed';
565        }
566        return $this;
567    }
569    public function setClientsCount(mixed $count): static
570    {
571        $clientList = $this->getClients();
572        while ($clientList->count() < $count) {
573            $clientList->addEntity(new Client());
574        }
575        return $this;
576    }
579    public function withoutPersonalData(): static
580    {
581        $entity = clone $this;
582        if ($this->toProperty()->clients->isAvailable()) {
583            $client = $entity->getFirstClient();
584            unset($client['familyName']);
585            unset($client['email']);
586        }
587        return $entity;
588    }
596    public function withLessData(array $keepArray = [])
597    {
598        $entity = clone $this;
599        if (!in_array('availability', $keepArray)) {
600            foreach ($entity['appointments'] as $appointment) {
601                if ($appointment->toProperty()->scope->isAvailable()) {
602                    $scopeId = $appointment['scope']['id'];
603                    $appointment['scope'] = [
604                        'id' => $scopeId,
605                        'provider' => $appointment['scope']['provider'] ?? [],
606                        'shortName' => $appointment['scope']['shortName'] ?? ''
607                    ];
608                }
609                if ($appointment->toProperty()->availability->isAvailable()) {
610                    unset($appointment['availability']);
611                }
612            }
613        }
614
615        if (!in_array('createTimestamp', $keepArray)) {
616            unset($entity['createTimestamp']);
617        }
618        unset($entity['createIP']);
619        if ($entity->toProperty()->scope->status->isAvailable()) {
620            unset($entity['scope']['status']);
621        }
622
623        if ($entity->status == 'free') {
624// delete keys
625            foreach (['authKey', 'queue', 'requests',] as $key) {
626                if (!in_array($key, $keepArray) && $entity->toProperty()->$key->isAvailable()) {
627                    unset($entity[$key]);
628                }
629            }
630            // delete if empty
631            foreach (['amendment', 'id', 'authKey', 'archiveId', 'reminderTimestamp',] as $key) {
632                if (!in_array($key, $keepArray) && $entity->toProperty()->$key->isAvailable() && !$entity[$key]) {
633                    unset($entity[$key]);
634                }
635            }
636            if (!in_array('provider', $keepArray) && $entity->toProperty()->scope->provider->data->isAvailable()) {
637                unset($entity['scope']['provider']['data']);
638            }
639        }
640
641        if (!in_array('dayoff', $keepArray) && $entity->toProperty()->scope->dayoff->isAvailable()) {
642            unset($entity['scope']['dayoff']);
643        }
644        if (!in_array('scope', $keepArray) && $entity->toProperty()->scope->preferences->isAvailable()) {
645            unset($entity['scope']['preferences']);
646        }
647        return $entity;
648    }
650    public function toCalendar(): Calendar
651    {
652        $calendar = new Calendar();
653        $dateTime = $this->getFirstAppointment()->toDateTime();
654        $day = new Day();
655        $day->setDateTime($dateTime);
656        $calendar->firstDay = $day;
657        $calendar->lastDay = $day;
658        $calendar->requests = clone $this->getRequests();
659        $calendar->scopes = new Collection\ScopeList([$this->scope]);
660        return $calendar;
661    }
663    public function toQueue(\DateTimeInterface $dateTime): mixed
664    {
665        $queue = new Queue($this->queue);
666        $queue->withAppointment = ($this->getFirstAppointment()->hasTime()) ? true : false;
667        $queue->waitingTime = ($queue->waitingTime) ? $queue->waitingTime : 0;
668        $queue->wayTime = ($queue->wayTime) ? $queue->wayTime : 0;
669        if ($queue->withAppointment) {
670            $queue->number = !empty($this->getDisplayNumber())
671                ? $this->getDisplayNumber()
672                : $this->id;
673        } else {
674            $queue->number = $this->toProperty()->queue->number->get();
675        }
676        $queue->displayNumber = $this->getDisplayNumber();
677        $queue->arrivalTime = $this->getArrivalTime($dateTime)->getTimestamp();
678        $queue->priority = $this->priority;
679        return $queue->setProcess($this);
680    }
682    public function hasArrivalTime(): bool
683    {
684        if ($this->isWithAppointment()) {
685            $arrivalTime = $this->getFirstAppointment()->date;
686        } else {
687            $arrivalTime = $this->toProperty()->queue->arrivalTime->get();
688        }
689        return ($arrivalTime) ? true : false;
690    }
696    public function getArrivalTime(string|\DateTimeInterface $default = 'now', mixed $timezone = null): \BO\Zmsentities\Helper\DateTime
697    {
698        $queueArrivalTime = $this->toProperty()->queue->arrivalTime->get();
699
700        if ($queueArrivalTime) {
701            // Falls der Queue-Wert vorhanden ist â€“ auch wenn ein Termin existiert â€“ verwende diesen (dabei ist handelt es sich, um verpasste Termine)
702            $arrivalTime = $queueArrivalTime;
703        } elseif ($this->isWithAppointment()) {
704            $arrivalTime = $this->getFirstAppointment()->date;
705        } else {
706            $arrivalTime = 0;
707        }
708
709        $arrivalTime = (int)$arrivalTime;
710        $arrivalDateTime = Helper\DateTime::create($default, $timezone);
711        if ($arrivalTime) {
712            $arrivalDateTime = $arrivalDateTime->setTimestamp($arrivalTime);
713        }
714        return $arrivalDateTime;
715    }
717    public function setArrivalTime(?\DateTimeInterface $dateTime = null): static
718    {
719        $this->queue['arrivalTime'] = ($dateTime) ? $dateTime->getTimestamp() : 0;
720        return $this;
721    }
726    public function getWaitedSeconds(string|\DateTimeInterface $defaultTime = 'now'): mixed
727    {
728        return $this->getCallTime($defaultTime)->getTimestamp() - $this->getArrivalTime($defaultTime)->getTimestamp();
729    }
731    public function getWaitedMinutes(string|\DateTimeInterface $defaultTime = 'now'): mixed
732    {
733        return $this->getWaitedSeconds($defaultTime) / 60;
734    }
736    public function getWaySeconds(string|\DateTimeInterface $defaultTime = 'now'): mixed
737    {
738        return $this->getShowUpTime($defaultTime)->getTimestamp() - $this->getCallTime($defaultTime)->getTimestamp();
739    }
741    public function getWayMinutes(string|\DateTimeInterface $defaultTime = 'now'): mixed
742    {
743        return $this->getWaySeconds($defaultTime) / 60;
744    }
746    public function setWasMissed(bool $bool): static
747    {
748        $this->wasMissed = $bool;
749        $this->status = self::STATUS_MISSED;
750        return $this;
751    }
753    public function isWasMissed(): bool
754    {
755        return (bool) $this->wasMissed;
756    }
758    public function toDerefencedAmendment(): string|null
759    {
760        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
761        return var_export(array(
762                'BuergerID' => $this->id,
763                'StandortID' => $this->scope['id'],
764                'Anmerkung' => null,
765                'IPTimeStamp' => $this->createTimestamp,
766                'LastChange' => $lastChange,
767            ), true);
768    }
770    public function toDerefencedCustomTextfield(): string|null
771    {
772        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
773        return var_export(array(
774                'BuergerID' => $this->id,
775                'StandortID' => $this->scope['id'],
776                'CustomTextfield' => null,
777                'IPTimeStamp' => $this->createTimestamp,
778                'LastChange' => $lastChange,
779            ), true);
780    }
782    public function toDerefencedCustomTextfield2(): string|null
783    {
784        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
785        return var_export(array(
786                'BuergerID' => $this->id,
787                'StandortID' => $this->scope['id'],
788                'CustomTextfield2' => null,
789                'IPTimeStamp' => $this->createTimestamp,
790                'LastChange' => $lastChange,
791            ), true);
792    }
794    public function __toString()
795    {
796        $string = "process#";
797        $string .= $this->getDisplayNumber() ?: $this->id ?: $this->archiveId;
798        $string .= ":" . $this->authKey;
799        $string .= " (" . $this->status . ")";
800        $string .= " " . $this->getFirstAppointment()->toDateTime()->format('c');
801        $string .= " " . ($this->isWithAppointment() ? "appoint" : "arrival:" . $this->getArrivalTime()->format('c'));
802        $string .= " " . $this->getFirstAppointment()->slotCount . "slots";
803        $string .= "*" . count($this->appointments);
804        foreach ($this->getRequests() as $request) {
805            $string .= " " . $request['source'] . "." . $request['id'];
806        }
807        $string .= " scope." . $this['scope']['id'];
808        $string .= " ~" . base_convert($this['lastChange'], 10, 35);
809        $string .= " client:" . $this['apiclient']['shortname'];
810        $string .= " token:" . ($this['captchaToken'] ?? '(none)');
811        return $string;
812    }
814    public function getExternalUserId(): mixed
815    {
816        return $this->toProperty()->externalUserId->get();
817    }
819    public function setExternalUserId(mixed $externalUserId): static
820    {
821        $this->externalUserId = $externalUserId;
822        return $this;
823    }
825    public function getParkedBy(): mixed
826    {
827        return $this->toProperty()->parkedBy->get();
828    }
830    public function setParkedBy(mixed $name): void
831    {
832        $this->parkedBy = $name;
833    }

Inherited from BO\Zmsentities\Schema\Entity

59    public function __construct(mixed $input = null, int $flags = \ArrayObject::ARRAY_AS_PROPS, string $iterator_class = "ArrayIterator")
60    {
61        /** @var class-string<\ArrayIterator> $iterator_class */
62        parent::__construct($this->getDefaults(), $flags, $iterator_class);
63        if ($input) {
64            $input = $this->getUnflattenedArray($input);
65            $this->addData($input);
66        }
67    }
70    public function exchangeArray(object|array $input): array
71    {
72        parent::exchangeArray($this->getDefaults());
73        $input = $this->getUnflattenedArray($input);
74        $this->addData($input);
75        return $this->getArrayCopy();
76    }
82    public function offsetSet(mixed $key, mixed $value): void
83    {
84        /** @psalm-suppress PossiblyNullArgument */
85        parent::offsetSet($key, $value);
86    }
88    public function getUnflattenedArray(mixed $input): mixed
89    {
90        if (!$input instanceof UnflattedArray) {
91            $input = new UnflattedArray($input);
92            $input->getUnflattenedArray();
93        }
94        $input = $input->getValue();
95        return $input;
96    }
112    public function getValidator(string $locale = 'de_DE', int $resolveLevel = 0): Validator
113    {
114        $jsonSchema = self::readJsonSchema()->withResolvedReferences($resolveLevel);
115        $data = (new Schema($this))->withoutRefs();
116        if (Property::__keyExists('$schema', $data)) {
117            unset($data['$schema']);
118        }
119        $validator = new Validator($data->toJsonObject(true), $jsonSchema, $locale);
120        return $validator;
121    }
128    public function isValid(int $resolveLevel = 0): bool
129    {
130        $validator = $this->getValidator('de_DE', $resolveLevel = 0);
131        return $validator->isValid();
132    }
140    public function testValid(string $locale = 'de_DE', int $resolveLevel = 0): bool
141    {
142        $validator = $this->getValidator($locale, $resolveLevel);
143        if (!$validator->isValid()) {
144            $exception = new \BO\Zmsentities\Exception\SchemaValidation();
145            $exception->setSchemaName($this->getEntityName());
146            $exception->setValidationError($validator->getErrors());
147            throw $exception;
148        }
149        return true;
150    }
157    public static function createExample()
158    {
159        $object = new static();
160        return $object->getExample();
161    }
168    public static function getExample()
169    {
170        $class = get_called_class();
171        $jsonSchema = self::readJsonSchema();
172        if ($jsonSchema->offsetExists('example')) {
173            return new $class($jsonSchema['example']);
174        }
175        return new $class();
176    }
178    protected static function readJsonSchema(): mixed
179    {
180        $class = get_called_class();
181        if (!array_key_exists($class, self::$schemaCache)) {
182            $schemaFile = $class::$schema;
183            if (!is_string($schemaFile)) {
184                throw new \BO\Zmsentities\Exception\SchemaMissingJsonFile(
185                    'Missing JSON-Schema file for ' . $class
186                );
187            }
188            self::$schemaCache[$class] = Loader::asArray($schemaFile);
189        }
190        return self::$schemaCache[$class];
191    }
193    public function getEntityName(): string
194    {
195        $entity = get_class($this);
196        $entity = preg_replace('#.*[\\\]#', '', $entity) ?? '';
197        $entity = strtolower($entity);
198        return $entity;
199    }
201    public function setJsonCompressLevel(mixed $jsonCompressLevel): static
202    {
203        $this->jsonCompressLevel = $jsonCompressLevel;
204        return $this;
205    }
208    public function jsonSerialize(): mixed
209    {
210        $schema = array(
211            '$schema' => 'https://schema.berlin.de/queuemanagement/' . $this->getEntityName() . '.json'
212        );
213        $schema = array_merge($schema, $this->getArrayCopy());
214        if ($this instanceof \BO\Zmsentities\Helper\NoSanitize) {
215            $serialize = $schema;
216        } else {
217            $schema = new Schema($schema);
218            $schema->setDefaults($this->getDefaults());
219            $schema->setJsonCompressLevel($this->jsonCompressLevel);
220            $serialize = $schema->toJsonObject();
221        }
222        return $serialize;
223    }
235    public function __get(string $name): mixed
236    {
237        return $this->offsetGet($name);
238    }
240    public function __isset(string $name): bool
241    {
242        return $this->offsetExists($name);
243    }
245    public function __set(string $name, mixed $value): void
246    {
247        $this->offsetSet($name, $value);
248    }
250    public function __unset(string $name): void
251    {
252        $this->offsetUnset($name);
253    }
255    public function __clone()
256    {
257        foreach ($this as $key => $property) {
258            if (is_object($property)) {
259                $this[$key] = clone $property;
260            }
261        }
262    }
294    public function withData(mixed $mergeData): static
295    {
296        $entity = clone $this;
297        $entity->addData($mergeData);
298        return $entity;
299    }
301    public function hasId(): bool
302    {
303        return (false !== $this->getId()) ? true : false;
304    }
306    public function getId(): mixed
307    {
308        $idName = $this::PRIMARY;
309        return ($this->offsetExists($idName) && $this[$idName]) ? $this[$idName] : false;
310    }
317    public function toProperty()
318    {
319        return new \BO\Zmsentities\Helper\Property($this);
320    }
322    public function hasProperty(mixed $propertyName): mixed
323    {
324        return $this->toProperty()->{$propertyName}->isAvailable();
325    }
327    public function getProperty(string $propertyName, mixed $default = ''): mixed
328    {
329        return $this->toProperty()->{$propertyName}->get($default);
330    }
335    public function withProperty(mixed $propertyName, mixed $newValue): static
336    {
337        $entity = clone $this;
338        $entity[$propertyName] = $newValue;
339        return $entity;
340    }
357    public function withCleanedUpFormData()
358    {
359        $entity = clone $this;
360        if (isset($entity['save'])) {
361            unset($entity['save']);
362        }
363        if (isset($entity['removeImage'])) {
364            unset($entity['removeImage']);
365        }
366        return $entity;
367    }
372    public function getResolveLevel()
373    {
374        return $this->resolveLevel;
375    }
381    public function setResolveLevel($resolveLevel)
382    {
383        $this->resolveLevel = $resolveLevel;
384        return $this;
385    }
393    public function withResolveLevel($resolveLevel): self|array
394    {
395        if ($resolveLevel >= 0) {
396            $entity = clone $this;
397            foreach ($entity as $key => $value) {
398                if ($value instanceof Entity || $value instanceof \BO\Zmsentities\Collection\Base) {
399                    $entity[$key] = $value->withResolveLevel($resolveLevel - 1);
400                } else {
401                    $entity[$key] = $value;
402                }
403            }
404            $entity->setResolveLevel($resolveLevel);
405            return $entity;
406        } else {
407            return $this->withReference();
408        }
409    }
417    public function withReference($additionalData = []): self|array
418    {
419        if (isset($this[$this::PRIMARY])) {
420            $additionalData['$ref'] =
421                $this::$schemaRefPrefix . $this->getEntityName() . '/' . $this[$this::PRIMARY] . '/';
422            return $additionalData;
423        } else {
424            return $this->withResolveLevel(0);
425        }
426    }