Completed
Push — develop ( b779dc...323e79 )
by Mohamed
06:59
created

IssueController::getDisplayAttachment()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 2.0003

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 33
ccs 21
cts 22
cp 0.9545
rs 8.8571
cc 2
eloc 22
nc 2
nop 4
crap 2.0003
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 integer|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 View Code Duplication
        if ($request->has('body')) {
1 ignored issue
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...
90 1
            $comment->setRelation('user', $this->auth->user());
91 1
            $comment->updateBody($request->input('body'));
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...
92 1
            $body = \Html::format($comment->comment);
93
        }
94
95 1
        return response()->json(['text' => $body]);
96
    }
97
98
    /**
99
     * To add new comment to an issue.
100
     *
101
     * @param Project             $project
102
     * @param Issue               $issue
103
     * @param Comment             $comment
104
     * @param FormRequest\Comment $request
105
     *
106
     * @return \Illuminate\Http\RedirectResponse
107
     */
108 4
    public function getAddComment(Project $project, Issue $issue, Comment $comment, FormRequest\Comment $request)
109
    {
110 4
        $comment->setRelation('project', $project);
111 4
        $comment->setRelation('issue', $issue);
112 4
        $comment->setRelation('user', $this->auth->user());
113 4
        $comment->createComment($request->all());
114
115 4
        return redirect($issue->to() . '#comment' . $comment->id)
116 4
            ->with('notice', trans('tinyissue.your_comment_added'));
117
    }
118
119
    /**
120
     * Ajax: to delete a comment.
121
     *
122
     * @param Comment $comment
123
     *
124
     * @return \Symfony\Component\HttpFoundation\Response
125
     */
126 1
    public function getDeleteComment(Comment $comment)
127
    {
128 1
        $comment->setRelation('user', $this->auth->user());
129 1
        $comment->deleteComment();
130
131 1
        return response()->json(['status' => true]);
132
    }
133
134
    /**
135
     * New issue form.
136
     *
137
     * @param Project   $project
138
     * @param IssueForm $form
139
     *
140
     * @return \Illuminate\View\View
141
     */
142 5
    public function getNew(Project $project, IssueForm $form)
143
    {
144 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 144 which is incompatible with the return type documented by Tinyissue\Http\Controlle...IssueController::getNew of type Illuminate\View\View.
Loading history...
145 5
            'project' => $project,
146 5
            'form'    => $form,
147 5
            'sidebar' => 'project',
148
        ]);
149
    }
150
151
    /**
152
     * To create a new issue.
153
     *
154
     * @param Project           $project
155
     * @param Issue             $issue
156
     * @param FormRequest\Issue $request
157
     *
158
     * @return \Illuminate\Http\RedirectResponse
159
     */
160 2 View Code Duplication
    public function postNew(Project $project, Issue $issue, FormRequest\Issue $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
161
    {
162 2
        $issue->setRelation('project', $project);
163 2
        $issue->setRelation('user', $this->auth->user());
164 2
        $issue->createIssue($request->all());
165
166 2
        return redirect($issue->to())
167 2
            ->with('notice', trans('tinyissue.issue_has_been_created'));
168
    }
169
170
    /**
171
     * Edit an existing issue form.
172
     *
173
     * @param Project   $project
174
     * @param Issue     $issue
175
     * @param IssueForm $form
176
     *
177
     * @return \Illuminate\View\View
178
     */
179 2
    public function getEdit(Project $project, Issue $issue, IssueForm $form)
180
    {
181
        // Cannot edit closed issue
182 2
        if ($issue->status == Issue::STATUS_CLOSED) {
183 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...
184 1
                ->with('notice', trans('tinyissue.cant_edit_closed_issue'));
185
        }
186
187 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 187 which is incompatible with the return type documented by Tinyissue\Http\Controlle...ssueController::getEdit of type Illuminate\View\View.
Loading history...
188 2
            'issue'   => $issue,
189 2
            'project' => $project,
190 2
            'form'    => $form,
191 2
            'sidebar' => 'project',
192
        ]);
193
    }
194
195
    /**
196
     * To update an existing issue details.
197
     *
198
     * @param Project           $project
199
     * @param Issue             $issue
200
     * @param FormRequest\Issue $request
201
     *
202
     * @return \Illuminate\Http\RedirectResponse
203
     */
204 1 View Code Duplication
    public function postEdit(Project $project, Issue $issue, FormRequest\Issue $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
205
    {
206 1
        $issue->setRelation('project', $project);
207 1
        $issue->setRelation('updatedBy', $this->auth->user());
208 1
        $issue->updateIssue($request->all());
209
210 1
        return redirect($issue->to())
211 1
            ->with('notice', trans('tinyissue.issue_has_been_updated'));
212
    }
213
214
    /**
215
     * To close or reopen an issue.
216
     *
217
     * @param Project $project
218
     * @param Issue   $issue
219
     * @param int     $status
220
     *
221
     * @return \Illuminate\Http\RedirectResponse
222
     */
223 2
    public function getClose(Project $project, Issue $issue, $status = 0)
224
    {
225 2
        if ($status == 0) {
226 2
            $message = trans('tinyissue.issue_has_been_closed');
227
        } else {
228 1
            $message = trans('tinyissue.issue_has_been_reopened');
229
        }
230
231 2
        $issue->setRelation('project', $project);
232 2
        $issue->changeStatus($status, $this->auth->user()->id);
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
233
234 2
        return redirect($issue->to())
235 2
            ->with('notice', $message);
236
    }
237
238
    /**
239
     * To upload an attachment file.
240
     *
241
     * @param Project    $project
242
     * @param Attachment $attachment
243
     * @param Request    $request
244
     *
245
     * @return \Symfony\Component\HttpFoundation\Response
246
     */
247 3
    public function postUploadAttachment(Project $project, Attachment $attachment, Request $request)
248
    {
249
        try {
250 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...
251
                abort(404);
252
            }
253
254 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...
255
256
            $response = [
257
                'upload' => [
258
                    [
259 3
                        'name'   => $attachment->filename,
260 3
                        'size'   => $attachment->filesize,
261 3
                        'fileId' => $attachment->id,
262
                    ],
263
                ],
264
            ];
265
        } catch (\Exception $exception) {
266
            $file = $request->file('upload');
267
268
            $response = [
269
                'status' => false,
270
                'name'   => $file->getClientOriginalName(),
271
                'error'  => $exception->getMessage(),
272
                'trace'  => $exception->getTraceAsString(),
273
            ];
274
        }
275
276 3
        return response()->json($response);
277
    }
278
279
    /**
280
     * Ajax: to remove an attachment file.
281
     *
282
     * @param Project    $project
283
     * @param Attachment $attachment
284
     * @param Request    $request
285
     *
286
     * @return \Symfony\Component\HttpFoundation\Response
287
     */
288 1
    public function postRemoveAttachment(Project $project, Attachment $attachment, Request $request)
289
    {
290 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...
291
292 1
        return response()->json(['status' => true]);
293
    }
294
295
    /**
296
     * Display an attachment file such as image.
297
     *
298
     * @param Project    $project
299
     * @param Issue      $issue
300
     * @param Attachment $attachment
301
     * @param Request    $request
302
     *
303
     * @return Response
304
     */
305 2
    public function getDisplayAttachment(Project $project, Issue $issue, Attachment $attachment, Request $request)
306
    {
307 2
        $issue->setRelation('project', $project);
308 2
        $attachment->setRelation('issue', $issue);
309
310 2
        $path    = config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
311 2
        $storage = \Storage::disk('local');
312 2
        $length  = $storage->size($path);
313 2
        $time    = $storage->lastModified($path);
314 2
        $type    = $storage->getDriver()->getMimetype($path);
315
316 2
        $response = new Response();
317 2
        $response->setEtag(md5($time . $path));
318 2
        $response->setExpires(new \DateTime('@' . ($time + 60)));
319 2
        $response->setLastModified(new \DateTime('@' . $time));
320 2
        $response->setPublic();
321 2
        $response->setStatusCode(200);
322
323 2
        $response->header('Content-Type', $type);
324 2
        $response->header('Content-Length', $length);
325 2
        $response->header('Content-Disposition', 'inline; filename="' . $attachment->filename . '"');
326 2
        $response->header('Cache-Control', 'must-revalidate');
327
328 2
        if ($response->isNotModified($request)) {
329
            // Return empty response if not modified
330
            return $response;
331
        }
332
333
        // Return file if first request / modified
334 2
        $response->setContent($storage->get($path));
335
336 2
        return $response;
337
    }
338
339
    /**
340
     * Download an attachment file.
341
     *
342
     * @param Project    $project
343
     * @param Issue      $issue
344
     * @param Attachment $attachment
345
     *
346
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
347
     */
348 1
    public function getDownloadAttachment(Project $project, Issue $issue, Attachment $attachment)
349
    {
350 1
        $issue->setRelation('project', $project);
351 1
        $attachment->setRelation('issue', $issue);
352
353 1
        $path = config('filesystems.disks.local.root') . '/' . config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
354
355 1
        return response()->download($path, $attachment->filename);
356
    }
357
358
    /**
359
     * Ajax: move an issue to another project.
360
     *
361
     * @param Issue   $issue
362
     * @param Request $request
363
     *
364
     * @return \Symfony\Component\HttpFoundation\Response
365
     */
366 1
    public function postChangeProject(Issue $issue, Request $request)
367
    {
368 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...
369
370 1
        return response()->json(['status' => true, 'url' => $issue->to()]);
371
    }
372
373
    /**
374
     * Ajax: change status of an issue.
375
     *
376
     * @param Issue   $issue
377
     * @param Request $request
378
     *
379
     * @return \Symfony\Component\HttpFoundation\Response
380
     */
381
    public function postChangeKanbanTag(Issue $issue, Request $request)
382
    {
383
        $newTag = Tag::find((int) $request->input('newtag'));
384
        $oldTag = Tag::find((int) $request->input('oldtag'));
385
386
        $issue->changeKanbanTag($newTag, $oldTag);
387
388
        return response()->json(['status' => true, 'issue' => $issue->id]);
389
    }
390
391
    /**
392
     * Ajax: returns comments for an issue.
393
     *
394
     * @param Project $project
395
     * @param Issue   $issue
396
     *
397
     * @return \Symfony\Component\HttpFoundation\Response
398
     */
399 8
    public function getIssueComments(Project $project, Issue $issue)
400
    {
401
        $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...
402
            $attachment->setRelation('issue', $issue);
403 8
        });
404 8
        $activities = $issue->commentActivities()->with('activity', 'user', 'comment', 'assignTo',
405 8
            'comment.attachments')->get();
406
        $activities->each(function (UserActivity $activity) use ($issue) {
407 8
            $activity->setRelation('issue', $issue);
408 8
        });
409
410 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...
411 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...
412 8
                'issue'           => $issue,
413 8
                'userActivity'    => $activity,
414 8
                'project'         => $project,
415 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...
416 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...
417 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...
418 8
            ])->render();
419 8
        })->implode('');
420
421 8
        if (empty($activityString)) {
422
            $activityString = '<li class="no-records">There are no comments yet on this issue.</li>';
423
        }
424
425 8
        return response()->json(['status' => true, 'activity' => $activityString]);
426
    }
427
428
    /**
429
     * Ajax: returns activities for an issue excluding comments.
430
     *
431
     * @param Project $project
432
     * @param Issue   $issue
433
     *
434
     * @return \Symfony\Component\HttpFoundation\Response
435
     */
436 1
    public function getIssueActivity(Project $project, Issue $issue)
437
    {
438 1
        $activities = $issue->generalActivities()->with('activity', 'user', 'assignTo')->get();
439
        $activities->each(function (UserActivity $activity) use ($issue) {
440 1
            $activity->setRelation('issue', $issue);
441 1
        });
442
443 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...
444 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...
445 1
                'issue'           => $issue,
446 1
                'userActivity'    => $activity,
447 1
                'activity'        => $activity,
448 1
                'project'         => $project,
449 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...
450 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...
451 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...
452 1
            ])->render();
453 1
        })->implode('');
454
455 1
        if (empty($activityString)) {
456
            $activityString = '<li class="no-records">There are no activity yet on this issue.</li>';
457
        }
458
459 1
        return response()->json(['status' => true, 'activity' => $activityString]);
460
    }
461
}
462