Lines 80.00% 104 / 130
Methods 64.28% 9 / 14
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 100.00% 2 / 2 100.00% 1 / 1 1
 getCollection 100.00% 1 / 1 100.00% 1 / 1 1
 getProcess 100.00% 1 / 1 100.00% 1 / 1 1
 getDelegatedProcess 100.00% 3 / 3 100.00% 1 / 1 1
 validateId 100.00% 11 / 11 100.00% 1 / 1 4
 validateAuthKey 92.85% 13 / 14 0.00% 0 / 1 5.01
 validateMail 100.00% 22 / 22 100.00% 1 / 1 8
 validateName 100.00% 8 / 8 100.00% 1 / 1 3
 validateCustomTextfield 0.00% 0 / 17 0.00% 0 / 1 30
 validateTelephone 85.18% 23 / 27 0.00% 0 / 1 8.21
 validateSurvey 100.00% 3 / 3 100.00% 1 / 1 1
 validateText 75.00% 9 / 12 0.00% 0 / 1 3.14
 validateReminderTimestamp 80.00% 4 / 5 0.00% 0 / 1 3.07
 validateRequests 100.00% 4 / 4 100.00% 1 / 1 2
14class ProcessValidator
15{
16    protected Process $process;
17
18    protected Collection $collection;
19
20    public function __construct(Process $process)
21    {
22        $this->process = $process;
23        $this->collection = new Collection([]);
24    }
25
26    public function getCollection(): Collection
27    {
28        return $this->collection;
29    }
30
31    public function getProcess(): Process
32    {
33        return $this->process;
34    }
35
36    public function getDelegatedProcess(): Delegate
37    {
38        $process = $this->getProcess();
39        $delegatedProcess = new Delegate($process);
40        return $delegatedProcess;
41    }
42
43    public function validateId(Unvalidated $unvalid, callable $setter, ?callable $isRequiredCallback = null): self
44    {
45        $valid = $unvalid->isNumber(
46            "Eine gültige Vorgangsnummer ist in der Regel eine sechsstellige Nummer wie '123456'"
47        );
48        $length = strlen((string)$valid->getValue());
49        if ($length) {
50            $valid->isGreaterThan(100000, "Eine Vorgangsnummer besteht aus mindestens 6 Ziffern");
51            $valid->isLowerEqualThan(99999999999, "Eine Vorgangsnummer besteht aus maximal 11 Ziffern");
52        } elseif ($isRequiredCallback !== null && $isRequiredCallback()) {
53            $valid->isRequired("Eine Vorgangsnummer wird benötigt.");
54        }
55        $this->getCollection()->validatedAction($valid, $setter);
56        return $this;
57    }
58
59    public function validateAuthKey(Unvalidated $unvalid, callable $setter, ?callable $isRequiredCallback = null): self
60    {
61        $trimmed = trim((string) $unvalid->getUnvalidated());
62        $valid = (new Unvalidated($trimmed, $unvalid->getName()))->isString();
63        $length = strlen($trimmed);
64        if ($length || ($isRequiredCallback !== null && $isRequiredCallback())) {
65            if ($length) {
66                $valid
67                ->isMatchOf(
68                    '/^(?:[a-f0-9]{4}|[a-f0-9]{64})$/i',
69                    "Der Absagecode ist nicht korrekt"
70                );
71            } else {
72                $valid->isRequired("Ein Absagecode wird benötigt");
73            }
74            $this->getCollection()->validatedAction($valid, $setter);
75            return $this;
76        }
77        return $this;
78    }
79
80    public function validateMail(Unvalidated $unvalid, callable $setter, ?callable $isRequiredCallback = null): self
81    {
82        $valid = $unvalid->isString();
83        $length = strlen((string)$valid->getUnvalidated());
84        $process = $this->getProcess();
85
86        if (!$length && $process->getCurrentScope()->isEmailRequired() && $process->isWithAppointment()) {
87            $valid->isBiggerThan(
88                6,
89                "Für den Standort muss eine gültige E-Mail Adresse eingetragen werden"
90            );
91        } elseif (!$length && $isRequiredCallback !== null && $isRequiredCallback()) {
92            $valid->isBiggerThan(
93                6,
94                "Für den Email-Versand muss eine gültige E-Mail Adresse angegeben werden"
95            );
96        } elseif ($length) {
97            $valid = $unvalid
98                ->isMail("Die E-Mail Adresse muss im Format max@mustermann.de eingeben werden.")
99                ->hasDNS(
100                    "Zu der angegebenen E-Mail-Adresse können keine Mails verschickt werden. " .
101                    "Der Host zur Domain nach dem '@' ist nicht erreichbar. "
102                );
103        }
104        $this->getCollection()->validatedAction($valid, $setter);
105        return $this;
106    }
107
108    public function validateName(Unvalidated $unvalid, callable $setter): self
109    {
110        $valid = $unvalid->isString();
111        $length = strlen((string)$valid->getValue());
112        if ($length || $this->getProcess()->isWithAppointment()) {
113            $valid
114                ->isBiggerThan(2, "Es muss ein aussagekräftiger Name eingegeben werden")
115                ->isSmallerThan(50, "Der Name sollte 50 Zeichen nicht überschreiten");
116        }
117        $this->getCollection()->validatedAction($valid, $setter);
118        return $this;
119    }
120
121    /**
122     * Validates a scope custom text field (max 250 chars), with optional HTML stripped to plain text.
123     */
124    public function validateCustomTextfield(Unvalidated $unvalid, callable $setter, bool $required): self
125    {
126        $valid = $unvalid->isString('Ungültige Zeichenkette', false);
127        if ($valid->hasFailed()) {
128            $this->getCollection()->validatedAction($valid, $setter);
129            return $this;
130        }
131        $normalized = ProcessPlainText::normalize($valid->getValue());
132        if ($required && trim($normalized) === '') {
133            $valid->setFailure('Dieses Feld darf nicht leer sein');
134        } elseif (mb_strlen($normalized, 'UTF-8') > ProcessPlainText::MAX_CUSTOM_TEXTFIELD_CHARS) {
135            $valid->setFailure(
136                'Der Eintrag überschreitet die maximal erlaubte Länge von ' .
137                ProcessPlainText::MAX_CUSTOM_TEXTFIELD_CHARS .
138                ' Zeichen'
139            );
140        }
141        $this->getCollection()->validatedAction($valid, function (mixed $raw) use ($setter) {
142            $setter(ProcessPlainText::normalize($raw));
143        });
144        return $this;
145    }
146
147    public function validateTelephone(Unvalidated $unvalid, callable $setter): self
148    {
149        $valid = $unvalid->isString();
150        $rawTelephone = $valid->getValue();
151        $length = strlen((string)$rawTelephone);
152        $telephone = $rawTelephone;
153
154        if (is_string($rawTelephone) && $rawTelephone !== '') {
155            try {
156                $phoneNumberUtil = \libphonenumber\PhoneNumberUtil::getInstance();
157                $phoneNumberObject = $phoneNumberUtil->parse($rawTelephone, 'DE');
158                $telephone = '+' . (string) $phoneNumberObject->getCountryCode()
159                    . (string) $phoneNumberObject->getNationalNumber();
160            } catch (\Exception $exception) {
161                $telephone = $rawTelephone;
162            }
163        }
164        $valid = (new \BO\Mellon\Unvalidated($telephone, 'telephone'))->isString();
165
166        if (
167            !$length
168            && $this->getProcess()->getCurrentScope()->isTelephoneRequired()
169            && $this->getProcess()->isWithAppointment()
170        ) {
171            $valid
172                ->isBiggerThan(10, "Für den Standort muss eine gültige Telefonnummer eingetragen werden");
173        } elseif ($length) {
174            $valid
175                ->isSmallerThan(
176                    15,
177                    "Die Telefonnummer ist zu lang, bitte prüfen Sie Ihre Eingabe"
178                )
179                ->isBiggerThan(10, "Für den Standort muss eine gültige Telefonnummer eingetragen werden")
180                ->isMatchOf("/^\+?[\d\s]*$/", "Die Telefonnummer muss im Format 0170 1234567 eingegeben werden");
181        }
182        $this->getCollection()->validatedAction($valid, $setter);
183        return $this;
184    }
185
186    public function validateSurvey(Unvalidated $unvalid, callable $setter): self
187    {
188        $valid = $unvalid->isNumber("Bitte wählen Sie eine Option");
189        $this->getCollection()->validatedAction($valid, $setter);
190        return $this;
191    }
192
193    public function validateText(Unvalidated $unvalid, callable $setter): self
194    {
195        $valid = $unvalid->isString('Ungültige Zeichenkette', false);
196        if ($valid->hasFailed()) {
197            $this->getCollection()->validatedAction($valid, $setter);
198            return $this;
199        }
200        $normalized = ProcessPlainText::normalize($valid->getValue());
201        $length = mb_strlen($normalized, 'UTF-8');
202        if ($length > ProcessPlainText::MAX_AMENDMENT_CHARS) {
203            $valid->setFailure('Die Anmerkung sollte 500 Zeichen nicht überschreiten');
204        }
205        $this->getCollection()->validatedAction($valid, function () use ($setter, $normalized) {
206            $setter($normalized);
207        });
208        return $this;
209    }
210
211    public function validateReminderTimestamp(Unvalidated $unvalid, callable $setter, callable $conditionCallback): self
212    {
213        $valid = $unvalid->isNumber();
214        if ($conditionCallback && $conditionCallback()) {
215            $this->getCollection()->validatedAction($valid, $setter);
216        } else {
217            $this->getCollection()->addValid($valid);
218        }
219        return $this;
220    }
221
222    public function validateRequests(Unvalidated $unvalid, callable $setter): self
223    {
224        if ($this->getProcess()->isWithAppointment()) {
225             $valid = $unvalid->isArray("Es muss mindestens eine Dienstleistung ausgewählt werden!");
226             $this->getCollection()->validatedAction($valid, $setter);
227        }
228        return $this;
229    }
230}