Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.77% covered (success)
96.77%
150 / 155
66.67% covered (warning)
66.67%
8 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Search
96.77% covered (success)
96.77%
150 / 155
66.67% covered (warning)
66.67%
8 / 12
52
0.00% covered (danger)
0.00%
0 / 1
 readResponse
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
2
 readSearchParameters
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
12
 readProcessSearchResults
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
5.01
 shouldRunProcessSearch
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 hasStructuredSearchFilters
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 buildProcessSearchParameters
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
6.06
 readLogSearchResults
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
5
 splitProcessListsByScope
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 filterProcessListForUserRights
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 filterLogListForUserRights
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
7.07
 readStringParameter
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 readNumberParameter
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @package Zmsadmin
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsadmin;
9
10use BO\Slim\Render;
11use BO\Zmsentities\Collection\LogList;
12use BO\Zmsentities\Log as LogEntity;
13use BO\Zmsentities\Collection\ProcessList;
14
15class Search extends BaseController
16{
17    private const DEFAULT_RESULTS_PER_PAGE = 100;
18
19    private const MAX_RESULTS_PER_PAGE = 1000;
20
21    /**
22     * @SuppressWarnings(Param)
23     * @return \Psr\Http\Message\ResponseInterface
24     */
25    #[\Override]
26    public function readResponse(
27        \Psr\Http\Message\RequestInterface $request,
28        \Psr\Http\Message\ResponseInterface $response,
29        array $args
30    ): \Psr\Http\Message\ResponseInterface {
31        $workstation = \App::$http->readGetResult('/workstation/', ['resolveReferences' => 2])->getEntity();
32        $parameters = $this->readSearchParameters($request->getAttribute('validator'));
33        if ($workstation->getUseraccount()->hasRole('audit_viewer')) {
34            $parameters['hideNavigation'] = 1;
35        }
36        $scopeIds = $workstation->getUseraccount()->getDepartmentList()->getUniqueScopeList()->getIds();
37
38        [$processList, $processSearchTotal] = $this->readProcessSearchResults(
39            $workstation,
40            $parameters,
41            $scopeIds
42        );
43        $logList = $this->readLogSearchResults($workstation, $parameters, $scopeIds);
44        [$processList, $processListOther] = $this->splitProcessListsByScope($workstation, $processList);
45
46        return Render::withHtml(
47            $response,
48            'page/search.twig',
49            array(
50                'title' => 'Suche',
51                'hideNavigation' => (bool) $parameters['hideNavigation'],
52                'service' => $parameters['service'],
53                'provider' => $parameters['provider'],
54                'userAction' => $parameters['userAction'],
55                'date' => $parameters['date'],
56                'page' => $parameters['page'],
57                'perPage' => $parameters['perPage'],
58                'workstation' => $workstation,
59                'processList' => $processList,
60                'processListOther' => $processListOther,
61                'logList' => $logList ?? [],
62                'searchProcessQuery' => $parameters['queryString'],
63                'processSearchTotal' => $processSearchTotal,
64                'menuActive' => 'search'
65            )
66        );
67    }
68
69    private function readSearchParameters($validator): array
70    {
71        $queryString = $validator->getParameter('query')
72            ->isString('', false)
73            ->getValue();
74        if ($queryString !== null && $queryString !== '') {
75            $queryString = html_entity_decode((string) $queryString, ENT_QUOTES | ENT_HTML5, 'UTF-8');
76        } else {
77            $queryString = $queryString ?? '';
78        }
79
80        $service = $this->readStringParameter($validator, 'service');
81        $provider = $this->readStringParameter($validator, 'provider');
82        $date = $validator->getParameter('date')->isString()->setDefault(null)->getValue();
83        $page = $this->readNumberParameter($validator, 'page', 1);
84        $userAction = $this->readNumberParameter($validator, 'user', 0);
85        $requestedResultsPerPage = $this->readNumberParameter($validator, 'perPage', self::DEFAULT_RESULTS_PER_PAGE);
86        $resultsPerPage = min($requestedResultsPerPage, self::MAX_RESULTS_PER_PAGE);
87        $hideNavigation = $this->readNumberParameter($validator, 'hideNavigation', 0);
88
89        return [
90            'queryString' => $queryString,
91            'page' => $page,
92            'service' => $service ? trim($service) : null,
93            'provider' => $provider ? trim($provider) : null,
94            'date' => $date !== null && trim($date) !== '' ? trim($date) : null,
95            'userAction' => $userAction,
96            'perPage' => $resultsPerPage,
97            'hideNavigation' => $hideNavigation,
98            'isSearchRequested' => (
99                trim((string) $queryString) !== ''
100                || trim($service) !== ''
101                || trim($provider) !== ''
102                || ($date !== null && trim($date) !== '')
103                || $userAction !== 0
104            ),
105        ];
106    }
107
108    private function readProcessSearchResults($workstation, array $parameters, array $scopeIds): array
109    {
110        if (!$this->shouldRunProcessSearch($workstation, $parameters)) {
111            return [new ProcessList(), 0];
112        }
113
114        $searchParameters = $this->buildProcessSearchParameters($workstation, $parameters, $scopeIds);
115        $searchResult = \App::$http->readGetResult('/process/search/', $searchParameters);
116        $processList = $searchResult->getCollection();
117        $searchMeta = $searchResult->getMeta();
118        $processSearchTotal = isset($searchMeta->totalCount)
119            ? (int) $searchMeta->totalCount
120            : $processList->count();
121
122        if (!empty($processList) && !$workstation->getUseraccount()->isSuperUser()) {
123            $processList = $this->filterProcessListForUserRights($processList, $scopeIds);
124        }
125
126        return [$processList, $processSearchTotal];
127    }
128
129    private function shouldRunProcessSearch($workstation, array $parameters): bool
130    {
131        if (!$parameters['isSearchRequested']) {
132            return false;
133        }
134
135        if (!$workstation->getUseraccount()->hasPermissions(['customersearch'])) {
136            return false;
137        }
138
139        $queryString = trim((string) $parameters['queryString']);
140
141        return $queryString !== '' || $this->hasStructuredSearchFilters($parameters);
142    }
143
144    private function hasStructuredSearchFilters(array $parameters): bool
145    {
146        return $parameters['service'] !== null
147            || $parameters['provider'] !== null
148            || $parameters['date'] !== null;
149    }
150
151    private function buildProcessSearchParameters($workstation, array $parameters, array $scopeIds): array
152    {
153        $queryString = trim((string) $parameters['queryString']);
154        $searchParameters = [
155            'resolveReferences' => 1,
156            'page' => $parameters['page'],
157            'limit' => $parameters['perPage'],
158        ];
159        if ($queryString !== '') {
160            $searchParameters['query'] = $queryString;
161        }
162        if ($parameters['service'] !== null) {
163            $searchParameters['service'] = $parameters['service'];
164        }
165        if ($parameters['provider'] !== null) {
166            $searchParameters['provider'] = $parameters['provider'];
167        }
168        if ($parameters['date'] !== null) {
169            $searchParameters['date'] = $parameters['date'];
170        }
171        if (!$workstation->getUseraccount()->isSuperUser()) {
172            $searchParameters['scopeIds'] = implode(',', $scopeIds);
173        }
174
175        return $searchParameters;
176    }
177
178    private function readLogSearchResults($workstation, array $parameters, array $scopeIds): ?LogList
179    {
180        if (!$workstation->getUseraccount()->hasPermissions(['logs'])) {
181            return null;
182        }
183
184        if (!$parameters['isSearchRequested'] && !$workstation->getUseraccount()->isSuperUser()) {
185            return null;
186        }
187
188        $logParameters = [
189            'searchQuery' => urlencode((string) $parameters['queryString']),
190            'page' => $parameters['page'],
191            'perPage' => $parameters['perPage'],
192            'service' => $parameters['service'],
193            'provider' => $parameters['provider'],
194            'userAction' => $parameters['userAction'],
195            'date' => $parameters['date'],
196        ];
197        if (!$workstation->getUseraccount()->isSuperUser()) {
198            $logParameters['scopeIds'] = implode(',', $scopeIds);
199        }
200
201        $logList = \App::$http
202            ->readGetResult("/log/process/", $logParameters)
203            ->getCollection();
204
205        return $this->filterLogListForUserRights(
206            $logList,
207            $scopeIds,
208            $workstation->getUseraccount()->isSuperUser()
209        );
210    }
211
212    private function splitProcessListsByScope($workstation, ?ProcessList $processList): array
213    {
214        $processList = $processList ?? new ProcessList();
215        $processListOther = new ProcessList();
216        if (!$workstation->getUseraccount()->isSuperUser()) {
217            $processListOther = $processList->withOutScopeId($workstation->scope['id']);
218            $processList = $processList->withScopeId($workstation->scope['id']);
219        }
220
221        return [$processList, $processListOther];
222    }
223
224    private function filterProcessListForUserRights(?ProcessList $processList, array $scopeIds)
225    {
226        if (empty($processList)) {
227            return new ProcessList();
228        }
229
230        $list = new ProcessList();
231
232        foreach ($processList as $process) {
233            if (in_array($process->scope->id, $scopeIds)) {
234                $list->addEntity(clone $process);
235            }
236        }
237
238        return $list;
239    }
240
241    private function filterLogListForUserRights(
242        ?LogList $logList,
243        array $scopeIds,
244        bool $bypassScopeFilter = false
245    ) {
246        if (!isset($logList) || !$logList) {
247            $logList = new LogList();
248        }
249
250        $list = new LogList();
251
252        foreach ($logList as $log) {
253            $log->display = LogEntity::formatDisplayFields($log->getArrayCopy());
254
255            if (
256                $bypassScopeFilter
257                || (isset($log->scope_id) && in_array($log->scope_id, $scopeIds))
258            ) {
259                $list->addEntity(clone $log);
260            }
261        }
262
263        return $list;
264    }
265
266    private function readStringParameter($validator, string $name, string $default = ''): string
267    {
268        return $validator->getParameter($name)
269            ->isString()
270            ->setDefault($default)
271            ->getValue() ?? $default;
272    }
273
274    private function readNumberParameter($validator, string $name, int $default): int
275    {
276        return (int) $validator->getParameter($name)
277            ->isNumber()
278            ->setDefault($default)
279            ->getValue();
280    }
281}