Completed
Push — develop ( 42d29e...bf2b91 )
by Mohamed
06:16
created

CrudTagTrait::changeKanbanTag()   C

Complexity

Conditions 8
Paths 18

Size

Total Lines 52
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 52
ccs 0
cts 27
cp 0
rs 6.8493
cc 8
eloc 27
nc 18
nop 3
crap 72

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\Model\Traits\Project\Issue;
13
14
use Illuminate\Database\Eloquent;
15
use Illuminate\Support\Collection;
16
use Tinyissue\Model;
17
use Tinyissue\Model\Activity;
18
use Tinyissue\Model\Project;
19
use Tinyissue\Model\Tag;
20
use Tinyissue\Model\Traits\Tag\DataMappingTrait;
21
use Tinyissue\Model\Traits\Tag\FilterTrait;
22
use Tinyissue\Model\User;
23
24
/**
25
 * CrudTagTrait is trait class containing the methods for adding/editing/deleting the tags of Project\Issue model.
26
 *
27
 * @author Mohamed Alsharaf <[email protected]>
28
 *
29
 * @property int $id
30
 * @property int $created_by
31
 * @property int $project_id
32
 * @property string $title
33
 * @property string $body
34
 * @property int $assigned_to
35
 * @property int $time_quote
36
 * @property int $closed_by
37
 * @property int $closed_at
38
 * @property int status
39
 * @property int $updated_at
40
 * @property int $updated_by
41
 * @property Model\Project $project
42
 * @property Model\User $user
43
 * @property Model\User $updatedBy
44
 */
45
trait CrudTagTrait
46
{
47
    use DataMappingTrait,
48
        FilterTrait;
49
50
    /**
51
     * Change the status of an issue.
52
     *
53
     * @param int $status
54
     * @param int $userId
55
     *
56
     * @return Eloquent\Model
57
     */
58 5
    public function changeStatus($status, $userId)
59
    {
60 5
        if ($status == 0) {
61 5
            $this->closed_by = $userId;
62 5
            $this->closed_at = (new \DateTime())->format('Y-m-d H:i:s');
63
64 5
            $activityType = Activity::TYPE_CLOSE_ISSUE;
65 5
            $addTagName   = Tag::STATUS_CLOSED;
66
67
            /** @var \Illuminate\Support\Collection $ids */
68 5
            $ids = $this->getTagsExceptStatus()->getRelatedIds();
0 ignored issues
show
Bug introduced by
It seems like getTagsExceptStatus() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
69
        } else {
70 1
            $activityType = Activity::TYPE_REOPEN_ISSUE;
71 1
            $removeTag    = Tag::STATUS_CLOSED;
72 1
            $addTagName   = Tag::STATUS_OPEN;
73
74
            /** @var \Illuminate\Support\Collection $ids */
75 1
            $ids = $this->getTagsExcept($removeTag)->getRelatedIds();
0 ignored issues
show
Bug introduced by
It seems like getTagsExcept() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
76
        }
77
78 5
        $ids->push((new Tag())->getTagByName($addTagName)->id);
79
80 5
        $this->tags()->sync($ids->unique()->all());
0 ignored issues
show
Bug introduced by
It seems like tags() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
81
82
        /* Add to activity log */
83 5
        $this->activities()->save(new User\Activity([
0 ignored issues
show
Bug introduced by
It seems like activities() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
84 5
            'type_id'   => $activityType,
85 5
            'parent_id' => $this->project->id,
86 5
            'user_id'   => $userId,
87
        ]));
88
89 5
        $this->status = $status;
90
91 5
        return $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
92
    }
93
94
    /**
95
     * Sync the issue tags.
96
     *
97
     * @param Collection $tags
98
     * @param Collection $currentTags
99
     *
100
     * @return bool
101
     */
102 28
    public function syncTags(Collection $tags, Collection $currentTags = null)
103
    {
104 28
        $removedTags = [];
105 28
        if (null === $currentTags) {
106
            // Open status tag
107 28
            $openTag = (new Tag())->getTagByName(Tag::STATUS_OPEN);
108
109
            // Add the following tags except for open status
110
            $addedTags = $tags
111 28
                ->filter([$this, 'tagsExceptStatusOpenCallback'])
112 28
                ->map([$this, 'toArrayCallback'])
113 28
                ->toArray();
114
        } else {
115
            // Open status tag
116 1
            $openTag = $currentTags->first([$this, 'onlyStatusOpenCallback']);
117
118
            // Remove status tag
119 1
            $currentTags = $currentTags->filter([$this, 'tagsExceptStatusOpenCallback']);
120
121
            // Make sure the tags does not includes the open status
122 1
            $tags = $tags->filter([$this, 'tagsExceptStatusOpenCallback']);
123
124
            // Tags remove from the issue
125
            $removedTags = $currentTags
126 1
                ->diff($tags)
127 1
                ->map([$this, 'toArrayCallback'])
128 1
                ->toArray();
129
130
            // Check if we are adding new tags
131
            $addedTags = $tags
132
                ->filter(function (Tag $tag) use ($currentTags) {
133 1
                    return $currentTags->where('id', $tag->id)->count() === 0;
134 1
                })
135 1
                ->map([$this, 'toArrayCallback'])
136 1
                ->toArray();
137
138
            // No new tags to add or remove
139 1
            if (empty($removedTags) && empty($addedTags)) {
140 1
                return true;
141
            }
142
        }
143
144
        // Make sure open status exists
145 28
        $tags->put($openTag->id, $openTag);
146
147
        // Save relation
148 28
        $this->tags()->sync($tags->lists('id')->all());
0 ignored issues
show
Bug introduced by
It seems like tags() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
149
150
        // Activity is added when new issue create with tags or updated with tags excluding the open status tag
151 28
        if (!empty($removedTags) || !empty($addedTags)) {
152
            // Add to activity log for tags if changed
153 4
            $this->activities()->save(new User\Activity([
0 ignored issues
show
Bug introduced by
It seems like activities() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
154 4
                'type_id'   => Activity::TYPE_ISSUE_TAG,
155 4
                'parent_id' => $this->project->id,
156 4
                'user_id'   => $this->user->id,
157 4
                'data'      => ['added_tags' => $addedTags, 'removed_tags' => $removedTags],
158
            ]));
159
        }
160
161 28
        return true;
162
    }
163
164
    /**
165
     * Create new tags from a string "group:tag_name" and fetch tag from a tag id.
166
     *
167
     * @param array $tags
168
     * @param bool  $isAdmin
169
     *
170
     * @return Collection
171
     */
172 28
    protected function createTags(array $tags, $isAdmin = false)
173
    {
174 28
        $newTags = new Collection($tags);
175
176
        // Transform the user input tags into tag objects
177
        $newTags->transform(function ($tagNameOrId) use ($isAdmin) {
178 28
            if (strpos($tagNameOrId, ':') !== false && $isAdmin) {
179 1
                return (new Tag())->createTagFromString($tagNameOrId);
180
            } else {
181 28
                return Tag::find($tagNameOrId);
182
            }
183 28
        });
184
185
        // Filter out invalid tags entered by the user
186 28
        $newTags = $newTags->filter(function ($tag) {
187 28
            return $tag instanceof Tag;
188 28
        });
189
190 28
        return $newTags;
191
    }
192
193
    /**
194
     * Add tag to the issue & close issue if added tag is Closed.
195
     *
196
     * @param Tag  $newTag
197
     * @param Tag  $oldTag
198
     * @param User $user
199
     *
200
     * @return $this
201
     */
202
    public function changeKanbanTag(Tag $newTag, Tag $oldTag, User $user)
203
    {
204
        if ($newTag->name === Tag::STATUS_CLOSED) {
205
            // Close issue
206
            $this->changeStatus(Project\Issue::STATUS_CLOSED, $user->id);
207
        } elseif ($oldTag->name !== $newTag->name) {
208
            // Open issue
209
            $data = ['added_tags' => [], 'removed_tags' => []];
210
211
            // Remove previous status tag
212
            if ($oldTag->name !== Tag::STATUS_OPEN) {
213
                $this->tags()->detach($oldTag);
0 ignored issues
show
Bug introduced by
It seems like tags() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
214
                $data['removed_tags'][] = $oldTag->toArrayCallback($oldTag);
215
            }
216
217
            // Add new tag
218
            if (!$this->tags->contains($newTag)) {
0 ignored issues
show
Bug introduced by
The property tags does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
219
                $this->tags()->attach($newTag);
0 ignored issues
show
Bug introduced by
It seems like tags() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
220
221
                $data['added_tags'][] = $newTag->toArrayCallback($newTag);
222
            }
223
224
            // Make sure open tag exists
225
            if ($newTag->name !== Tag::STATUS_OPEN && !$this->tags->where('name', Tag::STATUS_OPEN)->first()) {
226
                $openTag = (new Tag())->getTagByName(Tag::STATUS_OPEN);
227
                $this->tags()->attach($openTag);
0 ignored issues
show
Bug introduced by
It seems like tags() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
228
229
                // Set issue status open
230
                $this->status = Project\Issue::STATUS_OPEN;
231
                $this->save();
0 ignored issues
show
Bug introduced by
It seems like save() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
232
233
                // Add to activity log re-open issue
234
                $this->activities()->save(new User\Activity([
0 ignored issues
show
Bug introduced by
It seems like activities() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
235
                    'type_id'   => Activity::TYPE_REOPEN_ISSUE,
236
                    'parent_id' => $this->project->id,
237
                    'user_id'   => $this->user->id,
238
                ]));
239
            }
240
241
            // Add to activity log for tags if changed
242
            if (!empty($data)) {
243
                $this->activities()->save(new User\Activity([
0 ignored issues
show
Bug introduced by
It seems like activities() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
244
                    'type_id'   => Activity::TYPE_ISSUE_TAG,
245
                    'parent_id' => $this->project->id,
246
                    'user_id'   => $this->user->id,
247
                    'data'      => $data,
248
                ]));
249
            }
250
        }
251
252
        return $this;
253
    }
254
}
255