Completed
Push — develop ( e210c1...b7d5d2 )
by Mohamed
07:16 queued 59s
created

ProjectController::projectMainViewTabs()   B

Complexity

Conditions 8
Paths 36

Size

Total Lines 54
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 8

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 54
ccs 37
cts 37
cp 1
rs 7.4119
cc 8
eloc 39
nc 36
nop 4
crap 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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;
13
14
use Illuminate\Http\Request;
15
use Tinyissue\Form\FilterIssue as FilterForm;
16
use Tinyissue\Form\Note as NoteForm;
17
use Tinyissue\Form\Project as Form;
18
use Tinyissue\Http\Requests\FormRequest;
19
use Tinyissue\Model\Project;
20
use Tinyissue\Model\Project\Issue;
21
use Tinyissue\Model\Project\Note;
22
use Tinyissue\Services\Exporter;
23
24
/**
25
 * ProjectController is the controller class for managing request related to a project.
26
 *
27
 * @author Mohamed Alsharaf <[email protected]>
28
 */
29
class ProjectController extends Controller
30
{
31
    /**
32
     * Display activity for a project.
33
     *
34
     * @param Project $project
35
     *
36
     * @return \Illuminate\View\View
37
     */
38 5
    public function getIndex(Project $project)
39
    {
40 5
        $activities = $project->activities()
41 5
            ->with('activity', 'issue', 'user', 'assignTo', 'comment', 'note')
42 5
            ->orderBy('created_at', 'DESC')
43 5
            ->take(10)
44 5
            ->get();
45
46 5
        return view('project.index', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.index', ar...idebar' => 'project')); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 46 which is incompatible with the return type documented by Tinyissue\Http\Controlle...ectController::getIndex of type Illuminate\View\View.
Loading history...
47 5
            'tabs'       => $this->projectMainViewTabs($project, 'index'),
48 5
            'project'    => $project,
49 5
            'active'     => 'activity',
50 5
            'activities' => $activities,
51 5
            'sidebar'    => 'project',
52
        ]);
53
    }
54
55
    /**
56
     * Display issues for a project.
57
     *
58
     * @param FilterForm $filterForm
59
     * @param Request    $request
60
     * @param Project    $project
61
     * @param int        $status
62
     *
63
     * @return \Illuminate\View\View
64
     */
65 2
    public function getIssues(FilterForm $filterForm, Request $request, Project $project, $status = Issue::STATUS_OPEN)
66
    {
67 2
        $active = $status == Issue::STATUS_OPEN ? 'open_issue' : 'closed_issue';
68 2
        $issues = $project->listIssues($status, $request->all());
69
70 2
        return view('project.index', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.index', ar...Form' => $filterForm)); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 70 which is incompatible with the return type documented by Tinyissue\Http\Controlle...ctController::getIssues of type Illuminate\View\View.
Loading history...
71 2
            'tabs'       => $this->projectMainViewTabs($project, 'issues', $issues, $status),
0 ignored issues
show
Documentation introduced by
$status is of type integer, but the function expects a boolean.

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 2
            'project'    => $project,
73 2
            'active'     => $active,
74 2
            'issues'     => $issues,
75 2
            'sidebar'    => 'project',
76 2
            'filterForm' => $filterForm,
77
        ]);
78
    }
79
80
    /**
81
     * Display issues assigned to current user for a project.
82
     *
83
     * @param Project $project
84
     *
85
     * @return \Illuminate\View\View
86
     */
87 1
    public function getAssigned(Project $project)
88
    {
89 1
        $issues = $project->listAssignedIssues($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...
90
91 1
        return view('project.index', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.index', ar...idebar' => 'project')); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 91 which is incompatible with the return type documented by Tinyissue\Http\Controlle...Controller::getAssigned of type Illuminate\View\View.
Loading history...
92 1
            'tabs'    => $this->projectMainViewTabs($project, 'assigned', $issues),
93 1
            'project' => $project,
94 1
            'active'  => 'issue_assigned_to_you',
95 1
            'issues'  => $issues,
96 1
            'sidebar' => 'project',
97
        ]);
98
    }
99
100
    /**
101
     * Display notes for a project.
102
     *
103
     * @param Project  $project
104
     * @param NoteForm $form
105
     *
106
     * @return \Illuminate\View\View
107
     */
108 7
    public function getNotes(Project $project, NoteForm $form)
109
    {
110 7
        $notes = $project->notes()->with('createdBy')->get();
111
112 7
        return view('project.index', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.index', ar... 'noteForm' => $form)); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 112 which is incompatible with the return type documented by Tinyissue\Http\Controlle...ectController::getNotes of type Illuminate\View\View.
Loading history...
113 7
            'tabs'     => $this->projectMainViewTabs($project, 'notes', $notes),
114 7
            'project'  => $project,
115 7
            'active'   => 'notes',
116 7
            'notes'    => $notes,
117 7
            'sidebar'  => 'project',
118 7
            'noteForm' => $form,
119
        ]);
120
    }
121
122
    /**
123
     * @param Project $project
124
     * @param $view
125
     * @param null $data
126
     * @param bool $status
127
     *
128
     * @return array
129
     */
130 15
    protected function projectMainViewTabs(Project $project, $view, $data = null, $status = false)
131
    {
132 15
        $notesCount = $view === 'note' ? $data->count() : $project->notes()->count();
0 ignored issues
show
Bug introduced by
The method count cannot be called on $data (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
133
134 15
        $assignedIssuesCount = 0;
135 15
        if ($view !== 'assigned' && !$this->auth->guest()) {
136 14
            $assignedIssuesCount = $this->auth->user()->assignedIssuesCount($project->id);
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 assignedIssuesCount() 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...
137 1
        } elseif ($view === 'assigned') {
138 1
            $assignedIssuesCount = $data->count();
0 ignored issues
show
Bug introduced by
The method count cannot be called on $data (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
139
        }
140
141 15
        if ($view === 'issues') {
142 2
            if ($status == Issue::STATUS_OPEN) {
143 2
                $closedIssuesCount = $project->closedIssuesCount()->count();
144 2
                $openIssuesCount   = $data->count();
0 ignored issues
show
Bug introduced by
The method count cannot be called on $data (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
145
            } else {
146 1
                $closedIssuesCount = $data->count();
0 ignored issues
show
Bug introduced by
The method count cannot be called on $data (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
147 2
                $openIssuesCount   = $project->openIssuesCount()->count();
148
            }
149
        } else {
150 13
            $openIssuesCount   = $project->openIssuesCount()->count();
151 13
            $closedIssuesCount = $project->closedIssuesCount()->count();
152
        }
153
154 15
        $tabs   = [];
155 15
        $tabs[] = [
156 15
            'url'  => $project->to(),
157 15
            'page' => 'activity',
158
        ];
159 15
        $tabs[] = [
160 15
            'url'    => $project->to('issues'),
161 15
            'page'   => 'open_issue',
162 15
            'prefix' => $openIssuesCount,
163
        ];
164 15
        $tabs[] = [
165 15
            'url'    => $project->to('issues') . '/0',
166 15
            'page'   => 'closed_issue',
167 15
            'prefix' => $closedIssuesCount,
168
        ];
169 15
        if (!$this->auth->guest()) {
170 15
            $tabs[] = [
171 15
                'url'    => $project->to('assigned'),
172 15
                'page'   => 'issue_assigned_to_you',
173 15
                'prefix' => $assignedIssuesCount,
174
            ];
175
        }
176 15
        $tabs[] = [
177 15
            'url'    => $project->to('notes'),
178 15
            'page'   => 'notes',
179 15
            'prefix' => $notesCount,
180
        ];
181
182 15
        return $tabs;
183
    }
184
185
    /**
186
     * Edit the project.
187
     *
188
     * @param Project $project
189
     * @param Form    $form
190
     *
191
     * @return \Illuminate\View\View
192
     */
193 2
    public function getEdit(Project $project, Form $form)
194
    {
195 2
        return view('project.edit', [
0 ignored issues
show
Bug Compatibility introduced by
The expression view('project.edit', arr...idebar' => 'project')); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 195 which is incompatible with the return type documented by Tinyissue\Http\Controlle...jectController::getEdit of type Illuminate\View\View.
Loading history...
196 2
            'form'    => $form,
197 2
            'project' => $project,
198 2
            'sidebar' => 'project',
199
        ]);
200
    }
201
202
    /**
203
     * To update project details.
204
     *
205
     * @param Project             $project
206
     * @param FormRequest\Project $request
207
     *
208
     * @return \Illuminate\Http\RedirectResponse
209
     */
210 2
    public function postEdit(Project $project, FormRequest\Project $request)
211
    {
212
        // Delete the project
213 2
        if ($request->has('delete-project')) {
214 1
            $project->delete();
215
216 1
            return redirect('projects')
217 1
                ->with('notice', trans('tinyissue.project_has_been_deleted'));
218
        }
219
220 1
        $project->update($request->all());
221
222 1
        return redirect($project->to())
223 1
            ->with('notice', trans('tinyissue.project_has_been_updated'));
224
    }
225
226
    /**
227
     * Ajax: returns list of users that are not in the project.
228
     *
229
     * @param Project $project
230
     *
231
     * @return \Symfony\Component\HttpFoundation\Response
232
     */
233 1
    public function getInactiveUsers(Project $project = null)
234
    {
235 1
        $users = $project->usersNotIn();
0 ignored issues
show
Bug introduced by
It seems like $project is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
236
237 1
        return response()->json($users);
238
    }
239
240
    /**
241
     * Ajax: add user to the project.
242
     *
243
     * @param Project $project
244
     * @param Request $request
245
     *
246
     * @return \Symfony\Component\HttpFoundation\Response
247
     */
248 1 View Code Duplication
    public function postAssign(Project $project, Request $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...
249
    {
250 1
        $status = false;
251 1
        if ($request->has('user_id')) {
252 1
            $project->assignUser((int) $request->input('user_id'));
253 1
            $status = true;
254
        }
255
256 1
        return response()->json(['status' => $status]);
257
    }
258
259
    /**
260
     * Ajax: remove user from the project.
261
     *
262
     * @param Project $project
263
     * @param Request $request
264
     *
265
     * @return \Symfony\Component\HttpFoundation\Response
266
     */
267 1 View Code Duplication
    public function postUnassign(Project $project, Request $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...
268
    {
269 1
        $status = false;
270 1
        if ($request->has('user_id')) {
271 1
            $project->unassignUser((int) $request->input('user_id'));
272 1
            $status = true;
273
        }
274
275 1
        return response()->json(['status' => $status]);
276
    }
277
278
    /**
279
     * To add a new note to the project.
280
     *
281
     * @param Project          $project
282
     * @param Note             $note
283
     * @param FormRequest\Note $request
284
     *
285
     * @return \Illuminate\Http\RedirectResponse
286
     */
287 2
    public function postAddNote(Project $project, Note $note, FormRequest\Note $request)
288
    {
289 2
        $note->setRelation('project', $project);
290 2
        $note->setRelation('createdBy', $this->auth->user());
291 2
        $note->createNote($request->all());
292
293 2
        return redirect($note->to())->with('notice', trans('tinyissue.your_note_added'));
294
    }
295
296
    /**
297
     * Ajax: To update project note.
298
     *
299
     * @param Project $project
300
     * @param Note    $note
301
     * @param Request $request
302
     *
303
     * @return \Symfony\Component\HttpFoundation\Response
304
     */
305 1
    public function postEditNote(Project $project, Project\Note $note, Request $request)
306
    {
307 1
        $body = '';
308 1
        if ($request->has('body')) {
309 1
            $note->setRelation('project', $project)->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...
310 1
            $body = \Html::format($note->body);
311
        }
312
313 1
        return response()->json(['status' => true, 'text' => $body]);
314
    }
315
316
    /**
317
     * Ajax: to delete a project note.
318
     *
319
     * @param Project $project
320
     * @param Note    $note
321
     *
322
     * @return \Symfony\Component\HttpFoundation\Response
323
     */
324 1
    public function getDeleteNote(Project $project, Project\Note $note)
0 ignored issues
show
Unused Code introduced by
The parameter $project is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
325
    {
326 1
        $note->delete();
327
328 1
        return response()->json(['status' => true]);
329
    }
330
331
    /**
332
     * Ajax: generate the issues export file.
333
     *
334
     * @param Project  $project
335
     * @param Exporter $exporter
336
     * @param Request  $request
337
     *
338
     * @return \Symfony\Component\HttpFoundation\Response
339
     */
340
    public function postExportIssues(Project $project, Exporter $exporter, Request $request)
341
    {
342
        // Generate export file
343
        $info = $exporter->exportFile(
344
            'Project\Issue',
345
            $request->input('format', Exporter::TYPE_CSV),
0 ignored issues
show
Bug introduced by
It seems like $request->input('format'...ces\Exporter::TYPE_CSV) targeting Illuminate\Http\Request::input() can also be of type array; however, Tinyissue\Services\Exporter::exportFile() 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...
346
            $request->all()
347
        );
348
349
        // Download link
350
        $link = link_to(
351
            $project->to('download_export/' . $info['file']),
352
            trans('tinyissue.download_export'),
353
            ['class' => 'btn btn-link']
354
        );
355
356
        return response()->json([
357
            'link'  => $link,
358
            'title' => $info['title'],
359
            'file'  => $info['file'],
360
            'ext'   => $info['ext'],
361
        ]);
362
    }
363
364
    /**
365
     * Download and then delete an export file.
366
     *
367
     * @param Project $project
368
     * @param string  $file
369
     *
370
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
371
     */
372
    public function getDownloadExport(Project $project, $file)
0 ignored issues
show
Unused Code introduced by
The parameter $project is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
373
    {
374
        // Filter out any characters that are not in pattern
375
        $file = preg_replace('/[^a-z0-9\_\.]/mi', '', $file);
376
377
        // Download export
378
        return response()->download(storage_path('exports/' . $file), $file)->deleteFileAfterSend(true);
379
    }
380
}
381