Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.92% covered (warning)
72.92%
35 / 48
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CommentsController
72.92% covered (warning)
72.92%
35 / 48
50.00% covered (danger)
50.00%
3 / 6
17.89
0.00% covered (danger)
0.00%
0 / 1
 initialize
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 clearContentCache
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 index
68.18% covered (warning)
68.18%
15 / 22
0.00% covered (danger)
0.00%
0 / 1
4.52
 view
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 edit
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
4.47
 delete
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
3.14
1<?php
2declare(strict_types=1);
3
4namespace App\Controller\Admin;
5
6use App\Controller\AppController;
7use App\Model\Table\ArticlesTable;
8use Cake\Cache\Cache;
9use Cake\Http\Response;
10use Cake\ORM\Query;
11
12/**
13 * Comments Controller
14 *
15 * Manages CRUD operations for comments in the admin area.
16 *
17 * @property \App\Model\Table\CommentsTable $Comments
18 * @property \App\Model\Table\ArticlesTable $Articles
19 */
20class CommentsController extends AppController
21{
22    protected ArticlesTable $Articles;
23
24    /**
25     * Initializes the controller and loads the Articles table.
26     *
27     * @return void
28     */
29    public function initialize(): void
30    {
31        parent::initialize();
32        $this->Articles = $this->fetchTable('Articles');
33    }
34
35    /**
36     * Clears the content cache (used for both articles and tags)
37     *
38     * @return void
39     */
40    private function clearContentCache(): void
41    {
42        Cache::clear('content');
43    }
44
45    /**
46     * Displays a paginated list of comments with search functionality.
47     *
48     * @return \Cake\Http\Response|null Renders view or returns search results for AJAX requests.
49     */
50    public function index(): ?Response
51    {
52        $statusFilter = $this->request->getQuery('status');
53        $query = $this->Comments->find()
54            ->contain([
55                'Users',
56                'Articles' => function (Query $q) {
57                    return $q->select(['Articles.id', 'Articles.title', 'Articles.slug', 'Articles.kind']);
58                },
59            ]);
60
61        if ($statusFilter !== null) {
62            $query->where(['Comments.display' => (int)$statusFilter]);
63        }
64
65        $search = $this->request->getQuery('search');
66        if (!empty($search)) {
67            $query->where([
68                'content LIKE' => '%' . $search . '%',
69            ]);
70        }
71        $comments = $this->paginate($query);
72        if ($this->request->is('ajax')) {
73            $this->set(compact('comments'));
74            $this->viewBuilder()->setLayout('ajax');
75
76            return $this->render('search_results');
77        }
78        $this->set(compact('comments'));
79
80        return null;
81    }
82
83    /**
84     * Displays details of a specific comment.
85     *
86     * @param string|null $id Comment id.
87     * @return void
88     * @throws \Cake\Datasource\Exception\RecordNotFoundException When comment is not found.
89     */
90    public function view(?string $id = null): void
91    {
92        $comment = $this->Comments->get($id, contain: ['Users', 'Articles']);
93        $this->set(compact('comment'));
94    }
95
96    /**
97     * Edits an existing comment and clears the cache for the associated article.
98     *
99     * @param string|null $id Comment id.
100     * @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise.
101     * @throws \Cake\Datasource\Exception\RecordNotFoundException When comment is not found.
102     */
103    public function edit(?string $id = null): ?Response
104    {
105        $comment = $this->Comments->get($id, contain: ['Articles']);
106        if ($this->request->is(['patch', 'post', 'put'])) {
107            $comment->setAccess('is_inappropriate', true);
108            $comment = $this->Comments->patchEntity($comment, $this->request->getData());
109            if ($this->Comments->save($comment)) {
110                if ($comment->article) {
111                    $this->clearContentCache();
112                }
113                $this->Flash->success(__('The comment has been saved.'));
114
115                return $this->redirect(['action' => 'index']);
116            }
117            $this->Flash->error(__('The comment could not be saved. Please, try again.'));
118        }
119        $users = $this->Comments->Users->find('list', limit: 200)->all();
120        $this->set(compact('comment', 'users'));
121
122        return null;
123    }
124
125    /**
126     * Deletes a comment and clears the cache for the associated article.
127     *
128     * @param string|null $id Comment id.
129     * @return \Cake\Http\Response Redirects to index.
130     * @throws \Cake\Datasource\Exception\RecordNotFoundException When comment is not found.
131     */
132    public function delete(?string $id = null): Response
133    {
134        $this->request->allowMethod(['post', 'delete']);
135        $comment = $this->Comments->get($id);
136
137        if ($this->Comments->delete($comment)) {
138            if ($comment->article) {
139                $this->clearContentCache();
140            }
141
142            $this->Flash->success(__('The comment has been deleted.'));
143        } else {
144            $this->Flash->error(__('The comment could not be deleted. Please, try again.'));
145        }
146
147        return $this->redirect($this->referer());
148    }
149}