These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | |||
4 | namespace RexlManu\LaravelTickets\Controllers; |
||
5 | |||
6 | |||
7 | use Illuminate\Http\JsonResponse; |
||
8 | use Illuminate\Http\RedirectResponse; |
||
9 | use Illuminate\Http\Request; |
||
10 | use Illuminate\Validation\Rule; |
||
11 | use Illuminate\View\View; |
||
12 | use RexlManu\LaravelTickets\Events\TicketCloseEvent; |
||
13 | use RexlManu\LaravelTickets\Events\TicketMessageEvent; |
||
14 | use RexlManu\LaravelTickets\Events\TicketOpenEvent; |
||
15 | use RexlManu\LaravelTickets\Models\Ticket; |
||
16 | use RexlManu\LaravelTickets\Models\TicketMessage; |
||
17 | use RexlManu\LaravelTickets\Models\TicketReference; |
||
18 | use RexlManu\LaravelTickets\Models\TicketUpload; |
||
19 | use RexlManu\LaravelTickets\Rule\TicketReferenceRule; |
||
20 | use Symfony\Component\HttpFoundation\BinaryFileResponse; |
||
21 | |||
22 | /** |
||
23 | * Class TicketController |
||
24 | * |
||
25 | * The main logic of the ticket system. All actions are performed here. |
||
26 | * |
||
27 | * If the accept header is json, the response will be a json response |
||
28 | * |
||
29 | * @package RexlManu\LaravelTickets\Controllers |
||
30 | */ |
||
31 | trait TicketControllable |
||
32 | { |
||
33 | |||
34 | /** |
||
35 | * @link TicketControllable constructor |
||
36 | */ |
||
37 | public function __construct() |
||
38 | { |
||
39 | if (! config('laravel-tickets.permission')) { |
||
40 | return; |
||
41 | } |
||
42 | |||
43 | $this->middleware(config('laravel-tickets.permissions.list-ticket'))->only('index'); |
||
0 ignored issues
–
show
|
|||
44 | $this->middleware(config('laravel-tickets.permissions.create-ticket'))->only('store', 'create'); |
||
0 ignored issues
–
show
It seems like
middleware() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the
Loading history...
|
|||
45 | $this->middleware(config('laravel-tickets.permissions.close-ticket'))->only('close'); |
||
0 ignored issues
–
show
It seems like
middleware() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the
Loading history...
|
|||
46 | $this->middleware(config('laravel-tickets.permissions.show-ticket'))->only('show'); |
||
0 ignored issues
–
show
It seems like
middleware() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the
Loading history...
|
|||
47 | $this->middleware(config('laravel-tickets.permissions.message-ticket'))->only('message'); |
||
0 ignored issues
–
show
It seems like
middleware() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the
Loading history...
|
|||
48 | $this->middleware(config('laravel-tickets.permissions.download-ticket'))->only('download'); |
||
0 ignored issues
–
show
It seems like
middleware() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the
Loading history...
|
|||
49 | } |
||
50 | |||
51 | /** |
||
52 | * Show every @return View|JsonResponse |
||
53 | * |
||
54 | * @link Ticket that the user has created |
||
55 | * |
||
56 | * If the accept header is json, the response will be a json response |
||
57 | * |
||
58 | */ |
||
59 | public function index() |
||
60 | { |
||
61 | if (\request()->user()->can(config('laravel-tickets.permissions.all-ticket'))) { |
||
62 | $tickets = Ticket::query(); |
||
63 | } else { |
||
64 | $tickets = request()->user()->tickets(); |
||
65 | } |
||
66 | $tickets = $tickets->orderBy('id', 'desc')->paginate(10); |
||
67 | |||
68 | return request()->wantsJson() ? |
||
69 | response()->json(compact('tickets')) : |
||
70 | view('laravel-tickets::tickets.index', |
||
71 | compact('tickets') |
||
72 | ); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Show the create form |
||
77 | * |
||
78 | * @return View |
||
79 | */ |
||
80 | public function create() |
||
81 | { |
||
82 | return view('laravel-tickets::tickets.create'); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * Creates a @param Request $request the request |
||
87 | * |
||
88 | * @return View|JsonResponse|RedirectResponse |
||
89 | * @link Ticket |
||
90 | * |
||
91 | */ |
||
92 | public function store(Request $request) |
||
93 | { |
||
94 | $rules = [ |
||
95 | 'subject' => [ 'required', 'string', 'max:191' ], |
||
96 | 'priority' => [ 'required', Rule::in(config('laravel-tickets.priorities')) ], |
||
97 | 'message' => [ 'required', 'string' ], |
||
98 | 'files' => [ 'max:' . config('laravel-tickets.file.max-files') ], |
||
99 | 'files.*' => [ |
||
100 | 'sometimes', |
||
101 | 'file', |
||
102 | 'max:' . config('laravel-tickets.file.size-limit'), |
||
103 | 'mimes:' . config('laravel-tickets.file.memes'), |
||
104 | ], |
||
105 | ]; |
||
106 | if (config('laravel-tickets.category')) { |
||
107 | $rules[ 'category_id' ] = [ |
||
108 | 'required', |
||
109 | Rule::exists(config('laravel-tickets.database.ticket-categories-table'), 'id'), |
||
110 | ]; |
||
111 | } |
||
112 | if (config('laravel-tickets.references')) { |
||
113 | $rules[ 'reference' ] = [ |
||
114 | config('laravel-tickets.references-nullable') ? 'nullable' : 'required', |
||
115 | new TicketReferenceRule(), |
||
116 | ]; |
||
117 | } |
||
118 | $data = $request->validate($rules); |
||
119 | if ($request->user()->tickets()->where('state', '!=', 'CLOSED')->count() >= config('laravel-tickets.maximal-open-tickets')) { |
||
120 | $message = trans('You have reached the limit of open tickets'); |
||
121 | return \request()->wantsJson() ? |
||
122 | response()->json(compact('message')) : |
||
123 | back()->with( |
||
124 | 'message', |
||
125 | $message |
||
126 | ); |
||
127 | } |
||
128 | $ticket = $request->user()->tickets()->create( |
||
129 | $data |
||
130 | ); |
||
131 | |||
132 | if (array_key_exists('reference', $data)) { |
||
133 | $reference = explode(',', $data[ 'reference' ]); |
||
134 | $ticketReference = new TicketReference(); |
||
135 | $ticketReference->ticket()->associate($ticket); |
||
136 | $ticketReference->referenceable()->associate( |
||
137 | resolve($reference[ 0 ])->find($reference[ 1 ]) |
||
138 | ); |
||
139 | $ticketReference->save(); |
||
140 | } |
||
141 | |||
142 | $ticketMessage = new TicketMessage($data); |
||
143 | $ticketMessage->user()->associate($request->user()); |
||
144 | $ticketMessage->ticket()->associate($ticket); |
||
145 | $ticketMessage->save(); |
||
146 | |||
147 | $this->handleFiles($data[ 'files' ] ?? [], $ticketMessage); |
||
148 | |||
149 | event(new TicketOpenEvent($ticket)); |
||
150 | |||
151 | $message = trans('The ticket was successfully created'); |
||
152 | return $request->wantsJson() ? |
||
153 | response()->json(compact('message', 'ticket', 'ticketMessage')) : |
||
154 | redirect(route( |
||
155 | 'laravel-tickets.tickets.show', |
||
156 | compact('ticket') |
||
157 | ))->with( |
||
158 | 'message', |
||
159 | $message |
||
160 | ); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Show detailed informations about the @param Ticket $ticket |
||
165 | * |
||
166 | * @return View|JsonResponse|RedirectResponse|void |
||
167 | * @link Ticket and the informations |
||
168 | * |
||
169 | */ |
||
170 | public function show(Ticket $ticket) |
||
171 | { |
||
172 | View Code Duplication | if (! $ticket->user()->get()->contains(\request()->user()) && |
|
173 | ! request()->user()->can(config('laravel-tickets.permissions.all-ticket'))) { |
||
174 | return abort(403); |
||
175 | } |
||
176 | |||
177 | $messages = $ticket->messages()->with('uploads')->orderBy('created_at', 'desc')->paginate(4); |
||
178 | |||
179 | return \request()->wantsJson() ? |
||
180 | response()->json(compact( |
||
181 | 'ticket', |
||
182 | 'messages' |
||
183 | )) : |
||
184 | view('laravel-tickets::tickets.show', |
||
185 | compact( |
||
186 | 'ticket', |
||
187 | 'messages' |
||
188 | ) |
||
189 | ); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Send a message to the @param Request $request |
||
194 | * |
||
195 | * @param Ticket $ticket |
||
196 | * |
||
197 | * @return JsonResponse|RedirectResponse|void |
||
198 | * @link Ticket |
||
199 | * |
||
200 | */ |
||
201 | public function message(Request $request, Ticket $ticket) |
||
202 | { |
||
203 | View Code Duplication | if (! $ticket->user()->get()->contains(\request()->user()) && |
|
204 | ! request()->user()->can(config('laravel-tickets.permissions.all-ticket'))) { |
||
205 | return abort(403); |
||
206 | } |
||
207 | |||
208 | View Code Duplication | if (! config('laravel-tickets.open-ticket-with-answer') && $ticket->state === 'CLOSED') { |
|
209 | $message = trans('You cannot reply to a closed ticket'); |
||
210 | return \request()->wantsJson() ? |
||
211 | response()->json(compact('message')) : |
||
212 | back()->with( |
||
213 | 'message', |
||
214 | $message |
||
215 | ); |
||
216 | } |
||
217 | |||
218 | $data = $request->validate([ |
||
219 | 'message' => [ 'required', 'string' ], |
||
220 | 'files' => [ 'max:' . config('laravel-tickets.file.max-files') ], |
||
221 | 'files.*' => [ |
||
222 | 'sometimes', |
||
223 | 'file', |
||
224 | 'max:' . config('laravel-tickets.file.size-limit'), |
||
225 | 'mimes:' . config('laravel-tickets.file.memes'), |
||
226 | ] |
||
227 | ]); |
||
228 | |||
229 | $ticketMessage = new TicketMessage($data); |
||
230 | $ticketMessage->user()->associate($request->user()); |
||
231 | $ticketMessage->ticket()->associate($ticket); |
||
232 | $ticketMessage->save(); |
||
233 | |||
234 | $this->handleFiles($data[ 'files' ] ?? [], $ticketMessage); |
||
235 | |||
236 | $ticket->update([ 'state' => 'OPEN' ]); |
||
237 | |||
238 | event(new TicketMessageEvent($ticket, $ticketMessage)); |
||
239 | |||
240 | $message = trans('Your answer was sent successfully'); |
||
241 | return $request->wantsJson() ? |
||
242 | response()->json(compact('message')) : |
||
243 | back()->with( |
||
244 | 'message', |
||
245 | $message |
||
246 | ); |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Declare the @param Ticket $ticket |
||
251 | * |
||
252 | * @return JsonResponse|RedirectResponse|void |
||
253 | * @link Ticket as closed. |
||
254 | * |
||
255 | */ |
||
256 | public function close(Ticket $ticket) |
||
257 | { |
||
258 | View Code Duplication | if (! $ticket->user()->get()->contains(\request()->user()) && |
|
259 | ! request()->user()->can(config('laravel-tickets.permissions.all-ticket'))) { |
||
260 | return abort(403); |
||
261 | } |
||
262 | View Code Duplication | if ($ticket->state === 'CLOSED') { |
|
263 | $message = trans('The ticket is already closed'); |
||
264 | return \request()->wantsJson() ? |
||
265 | response()->json(compact('message')) : |
||
266 | back()->with( |
||
267 | 'message', |
||
268 | $message |
||
269 | ); |
||
270 | } |
||
271 | $ticket->update([ 'state' => 'CLOSED' ]); |
||
272 | event(new TicketCloseEvent($ticket)); |
||
273 | |||
274 | $message = trans('The ticket was successfully closed'); |
||
275 | return \request()->wantsJson() ? |
||
276 | response()->json(compact('message')) : |
||
277 | back()->with( |
||
278 | 'message', |
||
279 | $message |
||
280 | ); |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * Downloads the file from @param Ticket $ticket |
||
285 | * |
||
286 | * @param TicketUpload $ticketUpload |
||
287 | * |
||
288 | * @return BinaryFileResponse |
||
289 | * @link TicketUpload |
||
290 | * |
||
291 | */ |
||
292 | public function download(Ticket $ticket, TicketUpload $ticketUpload) |
||
293 | { |
||
294 | View Code Duplication | if (! $ticket->user()->get()->contains(\request()->user()) && |
|
295 | ! request()->user()->can(config('laravel-tickets.permissions.all-ticket'))) { |
||
296 | return abort(403); |
||
297 | } |
||
298 | |||
299 | $storagePath = storage_path('app/' . $ticketUpload->path); |
||
300 | if (config('laravel-tickets.pdf-force-preview') && pathinfo($ticketUpload->path, PATHINFO_EXTENSION) === 'pdf') { |
||
301 | return response()->file($storagePath); |
||
302 | } |
||
303 | |||
304 | return response()->download($storagePath); |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Handles the uploaded files for the @param $files array uploaded files |
||
309 | * |
||
310 | * @param TicketMessage $ticketMessage |
||
311 | * |
||
312 | * @link TicketMessage |
||
313 | * |
||
314 | */ |
||
315 | private function handleFiles($files, TicketMessage $ticketMessage) |
||
316 | { |
||
317 | if (! config('laravel-tickets.files') || $files === null) { |
||
318 | return; |
||
319 | } |
||
320 | foreach ($files as $file) { |
||
321 | $ticketMessage->uploads()->create([ |
||
322 | 'path' => $file->storeAs( |
||
323 | config('laravel-tickets.file.path') . $ticketMessage->id, |
||
324 | $file->getClientOriginalName(), |
||
325 | config('laravel-tickets.file.driver') |
||
326 | ) |
||
327 | ]); |
||
328 | } |
||
329 | } |
||
330 | |||
331 | } |
||
332 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.