Lines 91.23% 229 / 251
Methods 80.00% 40 / 50
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 getDefaults 100.00% 6 / 6 100.00% 1 / 1 1
 getProcessId 100.00% 1 / 1 100.00% 1 / 1 1
 getProcessAuthKey 100.00% 1 / 1 100.00% 1 / 1 1
 addMultiPart 100.00% 2 / 2 100.00% 1 / 1 1
 hasContent 100.00% 1 / 1 100.00% 1 / 1 2
 hasIcs 100.00% 1 / 1 100.00% 1 / 1 1
 getHtmlPart 100.00% 6 / 6 100.00% 1 / 1 3
 getPlainPart 100.00% 5 / 5 100.00% 1 / 1 3
 getIcsPart 100.00% 5 / 5 100.00% 1 / 1 3
 getClient 0.00% 0 / 3 0.00% 0 / 1 6
 getFirstClient 100.00% 5 / 5 100.00% 1 / 1 2
 toCustomMessageEntity 100.00% 29 / 29 100.00% 1 / 1 6
 toResolvedEntity 97.43% 38 / 39 0.00% 0 / 1 10
 toScopeAdminProcessList 100.00% 14 / 14 100.00% 1 / 1 1
 withDepartment 100.00% 2 / 2 100.00% 1 / 1 1
 getRecipient 100.00% 5 / 5 100.00% 1 / 1 4
 setTemplateProvider 100.00% 2 / 2 100.00% 1 / 1 1
 __toString 0.00% 0 / 5 0.00% 0 / 1 6
 [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] addData 100.00% 14 / 14 100.00% 1 / 1 6
 [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] withLessData 100.00% 1 / 1 100.00% 1 / 1 1
 [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 Mail extends Schema\Entity
15{
16    public const string PRIMARY = 'id';
17
18    public static $schema = "mail.json";
19
20    protected mixed $templateProvider = false;
21
22    /**
23     * @return (Client|Collection\MimepartList|Department|Process)[]
24     *
25     */
26    #[\Override]
27    public function getDefaults()
28    {
29        return [
30            'multipart' => new Collection\MimepartList(),
31            'process' => new Process(),
32            'department' => new Department(),
33            'client' => new Client(),
34        ];
35    }
36
37    public function getProcessId(): mixed
38    {
39        return $this->toProperty()->process->id->get();
40    }
41
42    public function getProcessAuthKey(): mixed
43    {
44        return $this->toProperty()->process->authKey->get();
45    }
46
47    public function addMultiPart(mixed $multiPart): static
48    {
49        $this->multipart = $multiPart;
50        return $this;
51    }
52
53    public function hasContent(): bool
54    {
55        return ($this->getHtmlPart() && $this->getPlainPart());
56    }
57
58    public function hasIcs(): bool
59    {
60        return (null != $this->getIcsPart());
61    }
62
63    public function getHtmlPart(): mixed
64    {
65        $multiPart = $this->toProperty()->multipart->get();
66        foreach ($multiPart as $part) {
67            $mimepart = new Mimepart($part);
68            if ($mimepart->isHtml()) {
69                return $mimepart->getContent();
70            }
71        }
72        return null;
73    }
74
75    public function getPlainPart(): mixed
76    {
77        foreach ($this->multipart as $part) {
78            $mimepart = new Mimepart($part);
79            if ($mimepart->isText()) {
80                return $mimepart->getContent();
81            }
82        }
83        return null;
84    }
85
86    public function getIcsPart(): mixed
87    {
88        foreach ($this->multipart as $part) {
89            $mimepart = new Mimepart($part);
90            if ($mimepart->isIcs()) {
91                return $mimepart->getContent();
92            }
93        }
94        return null;
95    }
96
97    public function getClient(): ?Client
98    {
99        if (isset($this['client'])) {
100            return $this['client'];
101        }
102
103        return $this->getFirstClient();
104    }
105
106    public function getFirstClient(): \BO\Zmsentities\Client|null
107    {
108        $client = null;
109        if ($this->toProperty()->process->isAvailable()) {
110            $process = new Process($this->process);
111            $client = $process->getFirstClient();
112        }
113        return $client;
114    }
115
116    public function toCustomMessageEntity(Process $process, mixed $collection): static
117    {
118        $entity = clone $this;
119        $message = '';
120        if (
121            Property::__keyExists(
122                'message',
123                $collection
124            ) &&
125            '' != $collection['message']->getValue()
126        ) {
127            $message = $collection['message']->getValue();
128        }
129        if (
130            Property::__keyExists(
131                'subject',
132                $collection
133            ) &&
134            '' != $collection['subject']->getValue()
135        ) {
136            $entity->subject = $collection['subject']->getValue();
137        }
138        $entity->process = $process;
139        $entity->createIP = $process->createIP;
140
141        if (! isset($entity['client'])) {
142            $entity['client'] = $entity->getFirstClient();
143        }
144
145        $entity->multipart[] = new Mimepart(array(
146            'mime' => 'text/html',
147            'content' => $message,
148            'base64' => false
149        ));
150        $entity->multipart[] = new Mimepart(array(
151            'mime' => 'text/plain',
152            'content' => Messaging::getPlainText($message),
153            'base64' => false
154        ));
155        return $entity;
156    }
157
158    /**
159     * @param Process|ProcessList Process|ProcessList $processList
160     * @param Config $config
161     * @param $status
162     * @param $initiator
163     * @return Mail
164     * @throws Exception\TemplateNotFound
165     */
166    public function toResolvedEntity(mixed $processList, Config $config, mixed $status, mixed $initiator = null)
167    {
168        $collection = (new ProcessList())->testProcessListLength(
169            $processList,
170            Messaging::isEmptyProcessListAllowed($status)
171        );
172        $mainProcess = $collection->getFirst();
173        $entity = clone $this;
174        $content = Messaging::getMailContent($collection, $config, $initiator, $status, $this->templateProvider);
175
176        $entity->process = ($mainProcess) ? ($mainProcess) : new Process();
177        $entity->subject = ($mainProcess) ?
178            Messaging::getMailSubject($mainProcess, $config, $initiator, $status, $this->templateProvider) :
179            Messaging::getMailSubject((new Process()), $config, $initiator, $status, $this->templateProvider);
180        $entity->createIP = ($mainProcess) ? $mainProcess->createIP : '';
181        $entity['client'] = (! isset($entity['client'])) ? $entity->getFirstClient() : $entity['client'];
182
183        $entity->multipart[] = new Mimepart(array(
184            'mime' => 'text/html',
185            'content' => $content,
186            'base64' => false
187        ));
188        $entity->multipart[] = new Mimepart(array(
189            'mime' => 'text/plain',
190            'content' => Messaging::getPlainText($content),
191            'base64' => false
192        ));
193
194        $firstAppointment = $mainProcess ? $mainProcess->getAppointments()->getFirst() : null;
195        if (
196            $mainProcess && $firstAppointment && $firstAppointment->hasTime() &&
197            Messaging::isIcsRequired($config, $mainProcess, $status)
198        ) {
199            $entity->multipart[] = new Mimepart(array(
200                'mime' => 'text/calendar',
201                'content' => Messaging::getMailIcs(
202                    $mainProcess,
203                    $config,
204                    $status,
205                    $initiator,
206                    false,
207                    $this->templateProvider
208                )->getContent(),
209                'base64' => false
210            ));
211        }
212        return $entity;
213    }
214
215    public function toScopeAdminProcessList(
216        Collection\ProcessList $processList,
217        Scope $scope,
218        \DateTimeInterface $dateTime
219    ): static {
220        $entity = clone $this;
221        $content = Messaging::getScopeAdminProcessListContent($processList, $scope, $dateTime);
222        $entity->subject = 'Termine am ' . $dateTime->format('Y-m-d');
223        $entity->createIP = 0;
224        $entity->client = new Client([
225            'email' => $scope->getContactEmail(),
226            'familyName' => $scope->getName()
227        ]);
228        $entity->multipart[] = new Mimepart(array(
229            'mime' => 'text/html',
230            'content' => $content,
231            'base64' => false
232        ));
233        /*
234        $entity->multipart[] = new Mimepart(array(
235            'mime' => 'text/plain',
236            'content' => Messaging::getPlainText($content),
237            'base64' => false
238        ));
239        */
240        return $entity;
241    }
242
243    public function withDepartment(mixed $department): static
244    {
245        $this->department = $department;
246        return $this;
247    }
248
249    public function getRecipient(): mixed
250    {
251        if (! isset($this['client'])) {
252            $this['client'] = $this->getFirstClient();
253        }
254        if (! isset($this['client']['email']) || "" == $this['client']['email']) {
255            throw new Exception\MailMissedAddress();
256        }
257        return $this['client']['email'];
258    }
259
260    public function setTemplateProvider(mixed $templateProvider): static
261    {
262        $this->templateProvider = $templateProvider;
263        return $this;
264    }
265
266    public function __toString()
267    {
268        $string = "mail#";
269        $string .= ($this->hasId()) ? $this->getId() : 0;
270        $string .= " recipient:" . $this->getRecipient();
271        $string .= " process:" . $this->getProcessId();
272        return $string;
273    }
274}

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    }
268    public function addData(array|object $mergeData): static
269    {
270        foreach ($mergeData as $key => $item) {
271            if (isset($this[$key])) {
272                if ($this[$key] instanceof Entity) {
273                    $this[$key]->setResolveLevel(($this->getResolveLevel() ?? 0) - 1);
274                    $this[$key]->addData($item);
275                } elseif ($this[$key] instanceof \BO\Zmsentities\Collection\Base) {
276                    $this[$key]->exchangeArray([]);
277                    $this[$key]->setResolveLevel(($this->getResolveLevel() ?? 0) - 1);
278                    $this[$key]->addData($item);
279                } elseif (is_array($this[$key])) {
280                    $this[$key] = array_replace_recursive($this[$key], $item);
281                } else {
282                    $this[$key] = $item;
283                }
284            } else {
285                $this[$key] = $item;
286            }
287        }
288        return $this;
289    }
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    }
347    public function withLessData()
348    {
349        return clone $this;
350    }
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    }