Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
74 / 74
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
QuestionsController
100.00% covered (success)
100.00%
74 / 74
100.00% covered (success)
100.00%
6 / 6
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 index
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 delete
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 edit
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 save
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
3
 showEdit
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Engelsystem\Controllers\Admin;
6
7use Carbon\Carbon;
8use Engelsystem\Controllers\BaseController;
9use Engelsystem\Controllers\HasUserNotifications;
10use Engelsystem\Helpers\Authenticator;
11use Engelsystem\Http\Redirector;
12use Engelsystem\Http\Request;
13use Engelsystem\Http\Response;
14use Engelsystem\Models\Question;
15use Psr\Log\LoggerInterface;
16
17class QuestionsController extends BaseController
18{
19    use HasUserNotifications;
20
21    /** @var array<string> */
22    protected array $permissions = [
23        'question.add',
24        'question.edit',
25    ];
26
27    public function __construct(
28        protected Authenticator $auth,
29        protected LoggerInterface $log,
30        protected Question $question,
31        protected Redirector $redirect,
32        protected Response $response
33    ) {
34    }
35
36    public function index(): Response
37    {
38        $questions = $this->question
39            ->orderBy('answered_at')
40            ->orderByDesc('created_at')
41            ->get()
42            ->load(['user.state', 'answerer.state']);
43
44        return $this->response->withView(
45            'pages/questions/index.twig',
46            ['questions' => $questions, 'is_admin' => true]
47        );
48    }
49
50    public function delete(Request $request): Response
51    {
52        $data = $this->validate($request, [
53            'id'     => 'required|int',
54            'delete' => 'checked',
55        ]);
56
57        $question = $this->question->findOrFail($data['id']);
58        $question->delete();
59
60        $this->log->info(
61            'Deleted question "{text}" ({id}) by {user} ({user_id})',
62            [
63                'text' => $question->text,
64                'id' => $question->id,
65                'user' => $question->user->name,
66                'user_id' => $question->user->id,
67            ]
68        );
69        $this->addNotification('question.delete.success');
70
71        return $this->redirect->to('/admin/questions');
72    }
73
74    public function edit(Request $request): Response
75    {
76        $questionId = (int) $request->getAttribute('question_id');
77
78        $questions = $this->question->findOrFail($questionId);
79
80        return $this->showEdit($questions);
81    }
82
83    public function save(Request $request): Response
84    {
85        $questionId = (int) $request->getAttribute('question_id');
86
87        /** @var Question $question */
88        $question = $this->question->findOrFail($questionId);
89
90        $data = $this->validate($request, [
91            'text'    => 'required',
92            'answer'  => 'required',
93            'delete'  => 'optional|checked',
94            'preview' => 'optional|checked',
95        ]);
96
97        if (!is_null($data['delete'])) {
98            $question->delete();
99
100            $this->log->info(
101                'Deleted question "{text}" ({id}) by {user} ({user_id})',
102                [
103                    'text' => $question->text,
104                    'id' => $question->id,
105                    'user' => $question->user->name,
106                    'user_id' => $question->user->id,
107                ]
108            );
109
110            $this->addNotification('question.delete.success');
111
112            return $this->redirect->to('/admin/questions');
113        }
114
115        $question->text = $data['text'];
116        $question->answer = $data['answer'];
117        $question->answered_at = Carbon::now();
118        $question->answerer()->associate($this->auth->user());
119
120        if (!is_null($data['preview'])) {
121            return $this->showEdit($question);
122        }
123
124        $question->save();
125
126        $this->log->info(
127            'Saved questions "{text}" ({id}) by {user} ({user_id}): {answer}',
128            [
129                'text' => $question->text,
130                'answer' => $question->answer,
131                'id' => $question->id,
132                'user' => $question->user->name,
133                'user_id' => $question->user->id,
134            ]
135        );
136
137        $this->addNotification('question.edit.success');
138
139        return $this->redirect->to('/admin/questions');
140    }
141
142    protected function showEdit(?Question $question): Response
143    {
144        return $this->response->withView(
145            'pages/questions/edit.twig',
146            ['question' => $question, 'is_admin' => true]
147        );
148    }
149}