Completed
Push — develop ( 3d6b5a...688bc1 )
by Mohamed
07:41
created

IssueController   B

Complexity

Total Complexity 32

Size/Duplication

Total Lines 461
Duplicated Lines 4.56 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 94.56%

Importance

Changes 16
Bugs 5 Features 1
Metric Value
wmc 32
c 16
b 5
f 1
lcom 1
cbo 15
dl 21
loc 461
ccs 139
cts 147
cp 0.9456
rs 8.8

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getEdit() 0 15 2
A getIndex() 0 16 3
A postEditComment() 0 10 2
A getAddComment() 0 10 1
A getDeleteComment() 0 6 1
A getNew() 0 8 1
A postAssign() 0 9 2
A postNew() 0 9 1
A postEdit() 0 17 2
A getClose() 0 14 2
A postRemoveAttachment() 0 6 1
B postUploadAttachment() 0 31 3
A getDeleteAttachment() 0 15 2
A postChangeKanbanTag() 0 9 1
B getDisplayAttachment() 0 33 2
A getDownloadAttachment() 0 9 1
A postChangeProject() 0 6 1
B getIssueComments() 10 28 2
B getIssueActivity() 11 25 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * This file is part of the Tinyissue package.
5
 *
6
 * (c) Mohamed Alsharaf <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tinyissue\Http\Controllers\Project;
13
14
use Illuminate\Http\Request;
15
use Illuminate\Http\Response;
16
use Tinyissue\Form\Comment as CommentForm;
17
use Tinyissue\Form\Issue as IssueForm;
18
use Tinyissue\Http\Controllers\Controller;
19
use Tinyissue\Http\Requests\FormRequest;
20
use Tinyissue\Model\Project;
21
use Tinyissue\Model\Project\Issue;
22
use Tinyissue\Model\Project\Issue\Attachment;
23
use Tinyissue\Model\Project\Issue\Comment;
24
use Tinyissue\Model\Tag;
25
use Tinyissue\Model\User\Activity as UserActivity;
26
27
/**
28
 * IssueController is the controller class for managing request related to projects issues.
29
 *
30
 * @author Mohamed Alsharaf <[email protected]>
31
 */
32
class IssueController extends Controller
33
{
34
    /**
35
     * Project issue index page (List project issues).
36
     *
37
     * @param Project     $project
38
     * @param Issue       $issue
39
     * @param CommentForm $form
40
     *
41
     * @return \Illuminate\View\View
42
     */
43 16
    public function getIndex(Project $project, Issue $issue, CommentForm $form)
44
    {
45
        // Projects should be limited to issue-modify
46 16
        $projects = null;
47 16
        if (!$this->auth->guest() && $this->auth->user()->permission('issue-modify')) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Authenticatable as the method permission() does only exist in the following implementations of said interface: Tinyissue\Model\User.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
48 13
            $projects = $this->auth->user()->projects()->get();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Authenticatable as the method projects() does only exist in the following implementations of said interface: Tinyissue\Model\User.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
49
        }
50
51 16
        return view('project.issue.index', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.issue.inde...ojects' => $projects)); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 51 which is incompatible with the return type documented by Tinyissue\Http\Controlle...sueController::getIndex of type Illuminate\View\View.
Loading history...
52 16
            'issue'       => $issue,
53 16
            'project'     => $project,
54 16
            'commentForm' => $form,
55 16
            'sidebar'     => 'project',
56 16
            'projects'    => $projects,
57
        ]);
58
    }
59
60
    /**
61
     * Ajax: Assign new user to an issue.
62
     *
63
     * @param Issue   $issue
64
     * @param Request $request
65
     *
66
     * @return \Symfony\Component\HttpFoundation\Response
67
     */
68 1
    public function postAssign(Issue $issue, Request $request)
69
    {
70 1
        $response = ['status' => false];
71 1
        if ($issue->reassign((int) $request->input('user_id'), $this->auth->user())) {
0 ignored issues
show
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
72 1
            $response['status'] = true;
73
        }
74
75 1
        return response()->json($response);
76
    }
77
78
    /**
79
     * Ajax: save comment.
80
     *
81
     * @param Comment $comment
82
     * @param Request $request
83
     *
84
     * @return \Symfony\Component\HttpFoundation\Response
85
     */
86 1
    public function postEditComment(Comment $comment, Request $request)
87
    {
88 1
        $body = '';
89 1
        if ($request->has('body')) {
90 1
            $comment->updateBody($request->input('body'), $this->auth->user());
0 ignored issues
show
Bug introduced by
It seems like $request->input('body') targeting Illuminate\Http\Request::input() can also be of type array; however, Tinyissue\Model\Traits\P...CrudTrait::updateBody() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
91 1
            $body = \Html::format($comment->comment);
92
        }
93
94 1
        return response()->json(['text' => $body]);
95
    }
96
97
    /**
98
     * To add new comment to an issue.
99
     *
100
     * @param Project             $project
101
     * @param Issue               $issue
102
     * @param Comment             $comment
103
     * @param FormRequest\Comment $request
104
     *
105
     * @return \Illuminate\Http\RedirectResponse
106
     */
107 4
    public function getAddComment(Project $project, Issue $issue, Comment $comment, FormRequest\Comment $request)
108
    {
109 4
        $comment->setRelation('project', $project);
110 4
        $comment->setRelation('issue', $issue);
111 4
        $comment->setRelation('user', $this->auth->user());
112 4
        $comment->createComment($request->all());
113
114 4
        return redirect($issue->to() . '#comment' . $comment->id)
115 4
            ->with('notice', trans('tinyissue.your_comment_added'));
116
    }
117
118
    /**
119
     * Ajax: to delete a comment.
120
     *
121
     * @param Comment $comment
122
     *
123
     * @return \Symfony\Component\HttpFoundation\Response
124
     */
125 1
    public function getDeleteComment(Comment $comment)
126
    {
127 1
        $comment->deleteComment($this->auth->user());
0 ignored issues
show
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
128
129 1
        return response()->json(['status' => true]);
130
    }
131
132
    /**
133
     * New issue form.
134
     *
135
     * @param Project   $project
136
     * @param IssueForm $form
137
     *
138
     * @return \Illuminate\View\View
139
     */
140 5
    public function getNew(Project $project, IssueForm $form)
141
    {
142 5
        return view('project.issue.new', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.issue.new'...idebar' => 'project')); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 142 which is incompatible with the return type documented by Tinyissue\Http\Controlle...IssueController::getNew of type Illuminate\View\View.
Loading history...
143 5
            'project' => $project,
144 5
            'form'    => $form,
145 5
            'sidebar' => 'project',
146
        ]);
147
    }
148
149
    /**
150
     * To create a new issue.
151
     *
152
     * @param Project           $project
153
     * @param Issue             $issue
154
     * @param FormRequest\Issue $request
155
     *
156
     * @return \Illuminate\Http\RedirectResponse
157
     */
158 2
    public function postNew(Project $project, Issue $issue, FormRequest\Issue $request)
159
    {
160 2
        $issue->setRelation('project', $project);
161 2
        $issue->setRelation('user', $this->auth->user());
162 2
        $issue->createIssue($request->all());
163
164 2
        return redirect($issue->to())
165 2
            ->with('notice', trans('tinyissue.issue_has_been_created'));
166
    }
167
168
    /**
169
     * Edit an existing issue form.
170
     *
171
     * @param Project   $project
172
     * @param Issue     $issue
173
     * @param IssueForm $form
174
     *
175
     * @return \Illuminate\View\View
176
     */
177 2
    public function getEdit(Project $project, Issue $issue, IssueForm $form)
178
    {
179
        // Cannot edit closed issue
180 2
        if ($issue->status == Issue::STATUS_CLOSED) {
181 1
            return redirect($issue->to())
0 ignored issues
show
Bug Best Practice introduced by
The return type of return redirect($issue->...t_edit_closed_issue')); (Illuminate\Http\RedirectResponse) is incompatible with the return type documented by Tinyissue\Http\Controlle...ssueController::getEdit of type Illuminate\View\View.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
182 1
                ->with('notice', trans('tinyissue.cant_edit_closed_issue'));
183
        }
184
185 2
        return view('project.issue.edit', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.issue.edit...idebar' => 'project')); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 185 which is incompatible with the return type documented by Tinyissue\Http\Controlle...ssueController::getEdit of type Illuminate\View\View.
Loading history...
186 2
            'issue'   => $issue,
187 2
            'project' => $project,
188 2
            'form'    => $form,
189 2
            'sidebar' => 'project',
190
        ]);
191
    }
192
193
    /**
194
     * To update an existing issue details.
195
     *
196
     * @param Project           $project
197
     * @param Issue             $issue
198
     * @param FormRequest\Issue $request
199
     *
200
     * @return \Illuminate\Http\RedirectResponse
201
     */
202 1
    public function postEdit(Project $project, Issue $issue, FormRequest\Issue $request)
203
    {
204
        // Delete the issue
205 1
        if ($request->has('delete-issue')) {
206
            $issue->delete();
207
208
            return redirect($project->to())
209
                ->with('notice', trans('tinyissue.issue_has_been_deleted'));
210
        }
211
212 1
        $issue->setRelation('project', $project);
213 1
        $issue->setRelation('updatedBy', $this->auth->user());
214 1
        $issue->updateIssue($request->all());
215
216 1
        return redirect($issue->to())
217 1
            ->with('notice', trans('tinyissue.issue_has_been_updated'));
218
    }
219
220
    /**
221
     * To close or reopen an issue.
222
     *
223
     * @param Project $project
224
     * @param Issue   $issue
225
     * @param int     $status
226
     *
227
     * @return \Illuminate\Http\RedirectResponse
228
     */
229 2
    public function getClose(Project $project, Issue $issue, $status = 0)
230
    {
231 2
        if ($status == 0) {
232 2
            $message = trans('tinyissue.issue_has_been_closed');
233
        } else {
234 1
            $message = trans('tinyissue.issue_has_been_reopened');
235
        }
236
237 2
        $issue->setRelation('project', $project);
238 2
        $issue->changeStatus($status, $this->auth->user());
0 ignored issues
show
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
239
240 2
        return redirect($issue->to())
241 2
            ->with('notice', $message);
242
    }
243
244
    /**
245
     * To upload an attachment file.
246
     *
247
     * @param Project    $project
248
     * @param Attachment $attachment
249
     * @param Request    $request
250
     *
251
     * @return \Symfony\Component\HttpFoundation\Response
252
     */
253 3
    public function postUploadAttachment(Project $project, Attachment $attachment, Request $request)
254
    {
255
        try {
256 3
            if (!$this->auth->user()->permission('project-all')) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Authenticatable as the method permission() does only exist in the following implementations of said interface: Tinyissue\Model\User.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
257
                abort(404);
258
            }
259
260 3
            $attachment->upload($request->all(), $project, $this->auth->user());
0 ignored issues
show
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
261
262
            $response = [
263
                'upload' => [
264
                    [
265 3
                        'name'   => $attachment->filename,
266 3
                        'size'   => $attachment->filesize,
267 3
                        'fileId' => $attachment->id,
268
                    ],
269
                ],
270
            ];
271
        } catch (\Exception $exception) {
272
            $file = $request->file('upload');
273
274
            $response = [
275
                'status' => false,
276
                'name'   => $file->getClientOriginalName(),
277
                'error'  => $exception->getMessage(),
278
                'trace'  => $exception->getTraceAsString(),
279
            ];
280
        }
281
282 3
        return response()->json($response);
283
    }
284
285
    /**
286
     * Ajax: to remove an attachment file.
287
     *
288
     * @param Project    $project
289
     * @param Attachment $attachment
290
     * @param Request    $request
291
     *
292
     * @return \Symfony\Component\HttpFoundation\Response
293
     */
294 1
    public function postRemoveAttachment(Project $project, Attachment $attachment, Request $request)
295
    {
296 1
        $attachment->remove($request->all(), $project, $this->auth->user());
0 ignored issues
show
Documentation introduced by
$this->auth->user() is of type object<Illuminate\Contra...h\Authenticatable>|null, but the function expects a object<Tinyissue\Model\User>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
297
298 1
        return response()->json(['status' => true]);
299
    }
300
301
    /**
302
     * Delete attachment.
303
     *
304
     * @param Project    $project
305
     * @param Issue      $issue
306
     * @param Attachment $attachment
307
     *
308
     * @return \Illuminate\Http\RedirectResponse
309
     */
310
    public function getDeleteAttachment(Project $project, Issue $issue, Attachment $attachment)
311
    {
312
        $path = config('filesystems.disks.local.root')
313
            . '/' . config('tinyissue.uploads_dir')
314
            . '/' . $project->id
315
            . '/' . $attachment->upload_token;
316
        try {
317
            $attachment->deleteFile($path, $attachment->filename);
318
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
319
        }
320
        $attachment->delete();
321
322
        return redirect($issue->to())
323
            ->with('notice', trans('tinyissue.attachment_has_been_deleted'));
324
    }
325
326
    /**
327
     * Display an attachment file such as image.
328
     *
329
     * @param Project    $project
330
     * @param Issue      $issue
331
     * @param Attachment $attachment
332
     * @param Request    $request
333
     *
334
     * @return Response
335
     */
336 2
    public function getDisplayAttachment(Project $project, Issue $issue, Attachment $attachment, Request $request)
337
    {
338 2
        $issue->setRelation('project', $project);
339 2
        $attachment->setRelation('issue', $issue);
340
341 2
        $path    = config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
342 2
        $storage = \Storage::disk('local');
343 2
        $length  = $storage->size($path);
344 2
        $time    = $storage->lastModified($path);
345 2
        $type    = $storage->getDriver()->getMimetype($path);
346
347 2
        $response = new Response();
348 2
        $response->setEtag(md5($time . $path));
349 2
        $response->setExpires(new \DateTime('@' . ($time + 60)));
350 2
        $response->setLastModified(new \DateTime('@' . $time));
351 2
        $response->setPublic();
352 2
        $response->setStatusCode(200);
353
354 2
        $response->header('Content-Type', $type);
355 2
        $response->header('Content-Length', $length);
356 2
        $response->header('Content-Disposition', 'inline; filename="' . $attachment->filename . '"');
357 2
        $response->header('Cache-Control', 'must-revalidate');
358
359 2
        if ($response->isNotModified($request)) {
360
            // Return empty response if not modified
361
            return $response;
362
        }
363
364
        // Return file if first request / modified
365 2
        $response->setContent($storage->get($path));
366
367 2
        return $response;
368
    }
369
370
    /**
371
     * Download an attachment file.
372
     *
373
     * @param Project    $project
374
     * @param Issue      $issue
375
     * @param Attachment $attachment
376
     *
377
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
378
     */
379 1
    public function getDownloadAttachment(Project $project, Issue $issue, Attachment $attachment)
380
    {
381 1
        $issue->setRelation('project', $project);
382 1
        $attachment->setRelation('issue', $issue);
383
384 1
        $path = config('filesystems.disks.local.root') . '/' . config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
385
386 1
        return response()->download($path, $attachment->filename);
387
    }
388
389
    /**
390
     * Ajax: move an issue to another project.
391
     *
392
     * @param Issue   $issue
393
     * @param Request $request
394
     *
395
     * @return \Symfony\Component\HttpFoundation\Response
396
     */
397 1
    public function postChangeProject(Issue $issue, Request $request)
398
    {
399 1
        $issue->changeProject($request->input('project_id'));
0 ignored issues
show
Documentation introduced by
$request->input('project_id') is of type string|array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
400
401 1
        return response()->json(['status' => true, 'url' => $issue->to()]);
402
    }
403
404
    /**
405
     * Ajax: change status of an issue.
406
     *
407
     * @param Issue   $issue
408
     * @param Request $request
409
     *
410
     * @return \Symfony\Component\HttpFoundation\Response
411
     */
412
    public function postChangeKanbanTag(Issue $issue, Request $request)
413
    {
414
        $newTag = Tag::find((int) $request->input('newtag'));
415
        $oldTag = Tag::find((int) $request->input('oldtag'));
416
417
        $issue->changeKanbanTag($newTag, $oldTag);
418
419
        return response()->json(['status' => true, 'issue' => $issue->id]);
420
    }
421
422
    /**
423
     * Ajax: returns comments for an issue.
424
     *
425
     * @param Project $project
426
     * @param Issue   $issue
427
     *
428
     * @return \Symfony\Component\HttpFoundation\Response
429
     */
430 8
    public function getIssueComments(Project $project, Issue $issue)
431
    {
432
        $issue->attachments->each(function (Attachment $attachment) use ($issue) {
0 ignored issues
show
Documentation introduced by
The property attachments does not exist on object<Tinyissue\Model\Project\Issue>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
433
            $attachment->setRelation('issue', $issue);
434 8
        });
435 8
        $activities = $issue->commentActivities()->with('activity', 'user', 'comment', 'assignTo',
436 8
            'comment.attachments')->get();
437
        $activities->each(function (UserActivity $activity) use ($issue) {
438 8
            $activity->setRelation('issue', $issue);
439 8
        });
440
441 View Code Duplication
        $activityString = $activities->map(function (UserActivity $activity) use ($project, $issue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
442 8
            return view('project/issue/activity/' . $activity->activity->activity, [
1 ignored issue
show
Documentation introduced by
The property activity does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
443 8
                'issue'           => $issue,
444 8
                'userActivity'    => $activity,
445 8
                'project'         => $project,
446 8
                'user'            => $activity->user,
0 ignored issues
show
Documentation introduced by
The property user does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
447 8
                'comment'         => $activity->comment,
0 ignored issues
show
Documentation introduced by
The property comment does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
448 8
                'assigned'        => $activity->assignTo,
0 ignored issues
show
Documentation introduced by
The property assignTo does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
449 8
            ])->render();
450 8
        })->implode('');
451
452 8
        if (empty($activityString)) {
453
            $activityString = '<li class="no-records">There are no comments yet on this issue.</li>';
454
        }
455
456 8
        return response()->json(['status' => true, 'activity' => $activityString]);
457
    }
458
459
    /**
460
     * Ajax: returns activities for an issue excluding comments.
461
     *
462
     * @param Project $project
463
     * @param Issue   $issue
464
     *
465
     * @return \Symfony\Component\HttpFoundation\Response
466
     */
467 1
    public function getIssueActivity(Project $project, Issue $issue)
468
    {
469 1
        $activities = $issue->generalActivities()->with('activity', 'user', 'assignTo')->get();
470
        $activities->each(function (UserActivity $activity) use ($issue) {
471 1
            $activity->setRelation('issue', $issue);
472 1
        });
473
474 1 View Code Duplication
        $activityString = $activities->map(function (UserActivity $activity) use ($project, $issue) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
475 1
            return view('project/issue/activity/' . $activity->activity->activity, [
1 ignored issue
show
Documentation introduced by
The property activity does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
476 1
                'issue'           => $issue,
477 1
                'userActivity'    => $activity,
478 1
                'activity'        => $activity,
479 1
                'project'         => $project,
480 1
                'user'            => $activity->user,
0 ignored issues
show
Documentation introduced by
The property user does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
481 1
                'comment'         => $activity->comment,
0 ignored issues
show
Documentation introduced by
The property comment does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
482 1
                'assigned'        => $activity->assignTo,
0 ignored issues
show
Documentation introduced by
The property assignTo does not exist on object<Tinyissue\Model\User\Activity>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
483 1
            ])->render();
484 1
        })->implode('');
485
486 1
        if (empty($activityString)) {
487
            $activityString = '<li class="no-records">There are no activity yet on this issue.</li>';
488
        }
489
490 1
        return response()->json(['status' => true, 'activity' => $activityString]);
491
    }
492
}
493