Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.61% covered (warning)
82.61%
57 / 69
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SystemLogsController
82.61% covered (warning)
82.61%
57 / 69
33.33% covered (danger)
33.33%
1 / 3
17.35
0.00% covered (danger)
0.00%
0 / 1
 index
95.92% covered (success)
95.92%
47 / 49
0.00% covered (danger)
0.00%
0 / 1
5
 view
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 delete
44.44% covered (danger)
44.44%
8 / 18
0.00% covered (danger)
0.00%
0 / 1
27.15
1<?php
2declare(strict_types=1);
3
4namespace App\Controller\Admin;
5
6use App\Controller\AppController;
7use Cake\Http\Response;
8
9/**
10 * SystemLogs Controller
11 *
12 * Manages system logs, providing functionalities to view, filter, search, and delete logs.
13 *
14 * @property \App\Model\Table\SystemLogsTable $SystemLogs
15 */
16class SystemLogsController extends AppController
17{
18    /**
19     * Index method for SystemLogs.
20     *
21     * Retrieves and displays a list of system logs. Supports filtering by log level and group name,
22     * and allows for searching within the logs when accessed via AJAX. The logs are ordered by creation date in
23     * descending order. Also retrieves distinct log levels and group names for filtering options.
24     *
25     * @return \Cake\Http\Response|null Returns null to render the view, or a Response object for AJAX requests.
26     * @throws \Cake\Http\Exception\NotFoundException If the page is not found.
27     * @throws \Cake\Database\Exception\DatabaseException If there's an issue with the database query.
28     */
29    public function index(): ?Response
30    {
31        $query = $this->SystemLogs->find()
32            ->select([
33                'SystemLogs.id',
34                'SystemLogs.level',
35                'SystemLogs.message',
36                'SystemLogs.context',
37                'SystemLogs.group_name',
38                'SystemLogs.created',
39            ])
40            ->orderBy(['SystemLogs.created' => 'DESC']);
41
42        $levels = $this->SystemLogs->find()
43            ->select(['level'])
44            ->distinct(['level'])
45            ->orderBy(['level' => 'ASC'])
46            ->all()
47            ->extract('level')
48            ->toArray();
49
50        $groupNames = $this->SystemLogs->find()
51            ->select(['group_name'])
52            ->distinct(['group_name'])
53            ->orderBy(['group_name' => 'ASC'])
54            ->all()
55            ->extract('group_name')
56            ->toArray();
57
58        $selectedLevel = $this->request->getQuery('level');
59        $selectedGroup = $this->request->getQuery('group');
60
61        if ($selectedLevel) {
62            $query->where(['SystemLogs.level' => $selectedLevel]);
63        }
64
65        if ($selectedGroup) {
66            $query->where(['SystemLogs.group_name' => $selectedGroup]);
67        }
68
69        if ($this->request->is('ajax')) {
70            $search = $this->request->getQuery('search');
71            if (!empty($search)) {
72                $query->where([
73                    'OR' => [
74                        'SystemLogs.level LIKE' => '%' . $search . '%',
75                        'SystemLogs.message LIKE' => '%' . $search . '%',
76                        'SystemLogs.context LIKE' => '%' . $search . '%',
77                        'SystemLogs.group_name LIKE' => '%' . $search . '%',
78                        'DATE(SystemLogs.created) LIKE' => '%' . $search . '%',
79                    ],
80                ]);
81            }
82            $systemLogs = $query->all();
83            $this->set(compact('systemLogs'));
84            $this->viewBuilder()->setLayout('ajax');
85
86            return $this->render('search_results');
87        }
88
89        $systemLogs = $this->paginate($query);
90        $this->set(compact('systemLogs', 'levels', 'groupNames', 'selectedLevel', 'selectedGroup'));
91
92        return null;
93    }
94
95    /**
96     * View method for displaying a specific system log.
97     *
98     * @param string|null $id System Log id.
99     * @return void
100     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
101     */
102    public function view(?string $id = null): void
103    {
104        $systemLog = $this->SystemLogs->get($id, contain: []);
105        $this->set(compact('systemLog'));
106    }
107
108    /**
109     * Delete system logs based on specified criteria.
110     *
111     * Handles various deletion scenarios:
112     * - Delete all logs
113     * - Delete logs by level
114     * - Delete logs by group
115     * - Delete a single log by ID
116     *
117     * @param string|null $type The type of deletion ('all', 'level', 'group') or log ID for single deletion
118     * @param string|null $value The value associated with the deletion type (level or group name)
119     * @return \Cake\Http\Response|null Redirects to the index action after deletion attempt
120     * @throws \Cake\Http\Exception\MethodNotAllowedException When the request method is not POST or DELETE
121     * @throws \Cake\Datasource\Exception\RecordNotFoundException When a single log for deletion is not found
122     */
123    public function delete(?string $type = null, ?string $value = null): ?Response
124    {
125        $this->request->allowMethod(['post', 'delete']);
126
127        if ($type === 'all') {
128            // Delete all logs
129            if ($this->SystemLogs->deleteAll([])) {
130                $this->Flash->success(__('All logs have been deleted.'));
131            } else {
132                $this->Flash->error(__('Unable to delete all logs.'));
133            }
134        } elseif ($type === 'level' && $value) {
135            // Delete logs by level
136            if ($this->SystemLogs->deleteAll(['level' => $value])) {
137                $this->Flash->success(__('All logs with level {0} have been deleted.', $value));
138            } else {
139                $this->Flash->error(__('Unable to delete logs with level {0}.', $value));
140            }
141        } elseif ($type === 'group' && $value) {
142            // Delete logs by group
143            if ($this->SystemLogs->deleteAll(['group_name' => $value])) {
144                $this->Flash->success(__('All logs in group {0} have been deleted.', $value));
145            } else {
146                $this->Flash->error(__('Unable to delete logs in group {0}.', $value));
147            }
148        } else {
149            // Delete a single log by ID
150            $log = $this->SystemLogs->get($type);
151            if ($this->SystemLogs->delete($log)) {
152                $this->Flash->success(__('The log has been deleted.'));
153            } else {
154                $this->Flash->error(__('Unable to delete the log.'));
155            }
156        }
157
158        return $this->redirect(['action' => 'index']);
159    }
160}