Lines 93.91% 108 / 115
Methods 66.66% 6 / 9
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 readResponse 97.36% 37 / 38 0.00% 0 / 1 5
 getSuccessMessage 100.00% 1 / 1 100.00% 1 / 1 2
 getConflictList 100.00% 9 / 9 100.00% 1 / 1 5
 writeUpdatedProcess 100.00% 13 / 13 100.00% 1 / 1 4
 shouldSendNotifications 92.30% 12 / 13 0.00% 0 / 1 5.01
 [BO\Zmsadmin\BaseController] __invoke 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsadmin\BaseController] getSchemaConstraintList 100.00% 8 / 8 100.00% 1 / 1 4
 [BO\Zmsadmin\BaseController] transformValidationErrors 61.53% 8 / 13 0.00% 0 / 1 15.69
 [BO\Zmsadmin\BaseController] handleEntityWrite 100.00% 17 / 17 100.00% 1 / 1 5
21class ProcessSave extends BaseController
22{
23    /**
24     * @SuppressWarnings(Param)
25     * @return \Psr\Http\Message\ResponseInterface
26     */
27    #[\Override]
28    public function readResponse(
29        \Psr\Http\Message\RequestInterface $request,
30        \Psr\Http\Message\ResponseInterface $response,
31        array $args
32    ): \Psr\Http\Message\ResponseInterface {
33        $workstation = \App::$http->readGetResult('/workstation/', ['resolveReferences' => 2])->getEntity();
34
35        $validator = $request->getAttribute('validator');
36        $input = $request->getParams();
37
38        $scope = Helper\AppointmentFormHelper::readSelectedScope($request, $workstation);
39        $processId = $validator->value($args['id'])->isNumber()->getValue();
40        $process = \App::$http->readGetResult('/process/' . $processId . '/')->getEntity();
41        $dateTime = ($process->isWithAppointment()) ?
42            (new \DateTime())->setTimestamp($process->getFirstAppointment()->date) :
43            \App::$now;
44        $shouldNotify = $this->shouldSendNotifications($input, $process);
45        $process->withUpdatedData($input, $dateTime, $scope);
46
47        $validatedForm = ($process->isWithAppointment()) ?
48            ProcessReserve::getValidatedForm($validator, $process) :
49            ProcessQueue::getValidatedForm($validator, $process);
50
51        if ($validatedForm['failed']) {
52            return \BO\Slim\Render::withJson(
53                $response,
54                $validatedForm
55            );
56        }
57
58        $process = $this->writeUpdatedProcess(
59            $input,
60            $process,
61            $validator,
62            $shouldNotify
63        );
64        $appointment = $process->getFirstAppointment();
65        $conflictList = ($process->isWithAppointment()) ?
66            static::getConflictList($scope->getId(), $appointment) :
67            null;
68        return \BO\Slim\Render::withHtml(
69            $response,
70            'element/helper/messageHandler.twig',
71            array(
72                'selectedprocess' => $process,
73                'success' => $this->getSuccessMessage($process),
74                'conflictlist' => $conflictList
75            )
76        );
77    }
78
79    protected function getSuccessMessage(Process $process): string
80    {
81        return ($process->isWithAppointment()) ? 'process_updated' : 'process_withoutappointment_updated';
82    }
83
84    public static function getConflictList($scopeId, $appointment)
85    {
86        $conflictList = ScopeAvailabilityDay::readConflictList($scopeId, $appointment->getStartTime());
87        $conflictList = ($conflictList && $conflictList->count()) ?
88            $conflictList
89                ->withTimeRangeByAppointment($appointment)
90                ->setConflictAmendment()
91                ->toConflictListByDay() :
92            null;
93        $dayKey = $appointment->getStartTime()->format('Y-m-d');
94        return ($conflictList && isset($conflictList[$dayKey])) ? $conflictList[$dayKey] : null;
95    }
96
97    protected function writeUpdatedProcess($input, Process $process, $validator, bool $notify = true)
98    {
99        $initiator = $validator->getParameter('initiator')->isString()->getValue();
100        $process = \App::$http->readPostResult(
101            '/process/' . $process->id . '/' . $process->authKey . '/',
102            $process,
103            [
104                'initiator' => $initiator ?? 'admin',
105                'slotType' => 'intern',
106                'slotsRequired' => (isset($input['slotCount']) && 1 < $input['slotCount']) ? $input['slotCount'] : 0
107            ]
108        )->getEntity();
109
110        if ($notify) {
111            AppointmentFormHelper::updateMail($input, $process);
112        }
113
114        return $process;
115    }
116
117    private function shouldSendNotifications($requestData, Process $process): bool
118    {
119        $requestIds = $requestData['requests'] ?? [];
120        $currentRequestIds = [];
121        foreach ($process->getRequests() as $request) {
122            $currentRequestIds[] = $request['id'];
123        }
124
125        if (array_merge(array_diff($requestIds, $currentRequestIds), array_diff($currentRequestIds, $requestIds))) {
126            return true;
127        }
128
129        if ($process->getFirstClient()['familyName'] !== $requestData['familyName']) {
130            return true;
131        }
132
133        $newDate = $requestData['selecteddate'] . ' '
134            . str_replace('-', ':', $requestData['selectedtime']);
135
136        if ($process->getFirstAppointment()->toDateTime()->format('Y-m-d H:i') !== $newDate) {
137            return true;
138        }
139
140        return false;
141    }
142}

Inherited from BO\Zmsadmin\BaseController

21    public function __invoke(RequestInterface $request, ResponseInterface $response, array $args)
22    {
23        $request = $this->initRequest($request);
24        $noCacheResponse = \BO\Slim\Render::withLastModified($response, time(), '0');
25        return $this->readResponse($request, $noCacheResponse, $args);
26    }
41    public function getSchemaConstraintList($schema): array
42    {
43        $list = [];
44        $locale = \App::$language->getLocale();
45        foreach ($schema->properties as $key => $property) {
46            if (isset($property['x-locale'])) {
47                $constraints = $property['x-locale'][$locale];
48                if ($constraints) {
49                    $list[$key]['description'] = $constraints['messages'];
50                }
51            }
52        }
53        return $list;
54    }
65    protected function transformValidationErrors($errorData)
66    {
67        if (!is_array($errorData) && !($errorData instanceof \Traversable)) {
68            return [];
69        }
70        $transformed = [];
71        foreach ($errorData as $pointer => $item) {
72            // Extract field name from JSON pointer (e.g., "/id" -> "id", "/contact/email" -> "contact/email")
73            // If the key doesn't start with "/", it's already a field name, so use it as-is
74            $fieldName = (strpos($pointer, '/') === 0) ? ltrim($pointer, '/') : $pointer;
75            // Handle root level errors
76            if ($fieldName === '' || $fieldName === null) {
77                $fieldName = '_root';
78            }
79            // Ensure the item structure is correct (has 'messages' array)
80            if (is_array($item) && isset($item['messages'])) {
81                $transformed[$fieldName] = $item;
82            } elseif (is_array($item)) {
83                // If item is an array but doesn't have 'messages', wrap it
84                $transformed[$fieldName] = $item;
85            } else {
86                $transformed[$fieldName] = $item;
87            }
88        }
89        return $transformed;
90    }
99    protected function handleEntityWrite(callable $httpCall)
100    {
101        try {
102            return $httpCall();
103        } catch (\BO\Zmsclient\Exception $exception) {
104            if ('BO\Zmsentities\Exception\SchemaValidation' == $exception->template) {
105                return [
106                    'template' => 'exception/bo/zmsentities/exception/schemavalidation.twig',
107                    'include' => true,
108                    'data' => $this->transformValidationErrors($exception->data)
109                ];
110            }
111
112            $template = TwigExceptionHandler::getExceptionTemplate($exception);
113            if (
114                '' != $exception->template
115                && \App::$slim->getContainer()->get('view')->getLoader()->exists($template)
116            ) {
117                return [
118                    'template' => $template,
119                    'include' => true,
120                    'data' => $this->transformValidationErrors($exception->data)
121                ];
122            }
123
124            throw $exception;
125        }
126    }