Completed
Push — master ( fa5230...195b94 )
by Mohamed
16:12 queued 06:12
created

CrudTagTrait::changeStatus()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2

Importance

Changes 7
Bugs 3 Features 1
Metric Value
c 7
b 3
f 1
dl 0
loc 35
ccs 15
cts 15
cp 1
rs 8.8571
cc 2
eloc 20
nc 2
nop 2
crap 2
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 5
     * @param int $status
54
     * @param int $userId
55 5
     *
56 5
     * @return Eloquent\Model
57 5
     */
58 5
    public function changeStatus($status, $userId)
59
    {
60 1
        if ($status == 0) {
61 1
            $this->closed_by = $userId;
62 1
            $this->closed_at = (new \DateTime())->format('Y-m-d H:i:s');
63
64
            $activityType = Activity::TYPE_CLOSE_ISSUE;
65
            $addTagName   = Tag::STATUS_CLOSED;
66 5
67 5
            /** @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 5
        } else {
70
            $activityType = Activity::TYPE_REOPEN_ISSUE;
71
            $removeTag    = Tag::STATUS_CLOSED;
72 5
            $addTagName   = Tag::STATUS_OPEN;
73
74 5
            /** @var \Illuminate\Support\Collection $ids */
75
            $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
        $ids->push((new Tag())->getTagByName($addTagName)->id);
79
80
        $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
        $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
            'type_id'   => $activityType,
85 28
            'parent_id' => $this->project->id,
86
            'user_id'   => $userId,
87 28
        ]));
88 28
89
        $this->status = $status;
90 28
91
        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 28
    }
93 28
94
    /**
95
     * Sync the issue tags.
96
     *
97 2
     * @param array      $input
98 28
     * @param Collection $currentTags
99 28
     *
100
     * @return bool
101
     */
102
    public function syncTags(array $input, Collection $currentTags = null)
103 1
    {
104
        $tagIds = array_only($input, [
105
            'tag_type', 'tag_status', 'tag_resolution',
106 1
        ]);
107 1
        $tags = (new Tag())->whereIn('id', $tagIds)->get();
108
109
        $removedTags = [];
110
        if (null === $currentTags) {
111
            // Open status tag
112
            $openTag = (new Tag())->getTagByName(Tag::STATUS_OPEN);
113 1
114 1
            // Add the following tags except for open status
115
            $addedTags = $tags
0 ignored issues
show
Bug introduced by
The method filter cannot be called on $tags (of type array).

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...
116 1
                ->filter([$this, 'tagsExceptStatusOpenCallback'])
117 1
                ->map([$this, 'toArrayCallback'])
118
                ->toArray();
119
        } else {
120 1
            // Open status tag
121 1
            $openTag = $currentTags->first([$this, 'onlyStatusOpenCallback']);
122
123
            // Remove status tag
124
            $currentTags = $currentTags->filter([$this, 'tagsExceptStatusOpenCallback']);
125
126 28
            // Make sure the tags does not includes the open status
127
            $tags = $tags->filter([$this, 'tagsExceptStatusOpenCallback']);
0 ignored issues
show
Bug introduced by
The method filter cannot be called on $tags (of type array).

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...
128
129 28
            // Tags remove from the issue
130
            $removedTags = $currentTags
131 2
                ->diff($tags)
132 2
                ->map([$this, 'toArrayCallback'])
133 2
                ->toArray();
134 2
135 2
            // Check if we are adding new tags
136
            $addedTags = $tags
137
                ->filter(function (Tag $tag) use ($currentTags) {
138
                    return $currentTags->where('id', $tag->id)->count() === 0;
139 28
                })
140
                ->map([$this, 'toArrayCallback'])
141
                ->toArray();
142
143
            // No new tags to add or remove
144
            if (empty($removedTags) && empty($addedTags)) {
145
                return true;
146
            }
147
        }
148
149
        // Make sure open status exists
150
        $tags->put($openTag->id, $openTag);
151
152
        // Save relation
153
        $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...
154
155
        // Activity is added when new issue create with tags or updated with tags excluding the open status tag
156
        if (!empty($removedTags) || !empty($addedTags)) {
157
            // Add to activity log for tags if changed
158
            $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...
159
                'type_id'   => Activity::TYPE_ISSUE_TAG,
160
                'parent_id' => $this->project->id,
161
                'user_id'   => $this->user->id,
162
                'data'      => ['added_tags' => $addedTags, 'removed_tags' => $removedTags],
163
            ]));
164
        }
165
166
        return true;
167
    }
168
169
    /**
170
     * Add tag to the issue & close issue if added tag is Closed.
171
     *
172
     * @param Tag  $newTag
173
     * @param Tag  $oldTag
174
     * @param User $user
175
     *
176
     * @return $this
177
     */
178
    public function changeKanbanTag(Tag $newTag, Tag $oldTag, User $user)
179
    {
180
        if ($newTag->name === Tag::STATUS_CLOSED) {
181
            // Close issue
182
            $this->changeStatus(Project\Issue::STATUS_CLOSED, $user->id);
183
        } elseif ($oldTag->name !== $newTag->name) {
184
            // Open issue
185
            $data = ['added_tags' => [], 'removed_tags' => []];
186
187
            // Remove previous status tag
188
            if ($oldTag->name !== Tag::STATUS_OPEN) {
189
                $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...
190
                $data['removed_tags'][] = $oldTag->toArrayCallback($oldTag);
191
            }
192
193
            // Add new tag
194
            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...
195
                $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...
196
197
                $data['added_tags'][] = $newTag->toArrayCallback($newTag);
198
            }
199
200
            // Make sure open tag exists
201
            if ($newTag->name !== Tag::STATUS_OPEN && !$this->tags->where('name', Tag::STATUS_OPEN)->first()) {
202
                $openTag = (new Tag())->getTagByName(Tag::STATUS_OPEN);
203
                $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...
204
205
                // Set issue status open
206
                $this->status = Project\Issue::STATUS_OPEN;
207
                $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...
208
209
                // Add to activity log re-open issue
210
                $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...
211
                    'type_id'   => Activity::TYPE_REOPEN_ISSUE,
212
                    'parent_id' => $this->project->id,
213
                    'user_id'   => $this->user->id,
214
                ]));
215
            }
216
217
            // Add to activity log for tags if changed
218
            if (!empty($data)) {
219
                $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...
220
                    'type_id'   => Activity::TYPE_ISSUE_TAG,
221
                    'parent_id' => $this->project->id,
222
                    'user_id'   => $this->user->id,
223
                    'data'      => $data,
224
                ]));
225
            }
226
        }
227
228
        return $this;
229
    }
230
}
231