Completed
Pull Request — master (#45)
by Fèvre
07:37
created

DiscussConversation::boot()   B

Complexity

Conditions 5
Paths 1

Size

Total Lines 50
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 8.6315
c 0
b 0
f 0
cc 5
eloc 23
nc 1
nop 0
1
<?php
2
namespace Xetaravel\Models;
3
4
use Eloquence\Behaviours\CountCache\Countable;
5
use Eloquence\Behaviours\Sluggable;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\App;
8
use Illuminate\Support\Facades\Auth;
9
use Illuminate\Support\Facades\Route;
10
use Xetaio\Mentions\Models\Traits\HasMentionsTrait;
11
use Xetaravel\Models\Gates\FloodGate;
12
use Xetaravel\Models\Presenters\DiscussConversationPresenter;
13
use Xetaravel\Models\Repositories\DiscussConversationRepository;
14
use Xetaravel\Models\Repositories\DiscussPostRepository;
15
use Xetaravel\Models\Scopes\DisplayScope;
16
use Xetaravel\Models\User;
17
18
class DiscussConversation extends Model
19
{
20
    use Countable,
21
        Sluggable,
22
        FloodGate,
23
        DiscussConversationPresenter,
24
        HasMentionsTrait;
25
26
    /**
27
     * The attributes that are mass assignable.
28
     *
29
     * @var array
30
     */
31
    protected $fillable = [
32
        'user_id',
33
        'category_id',
34
        'title',
35
        'slug',
36
        'post_count',
37
        'participants_count',
38
        'is_locked',
39
        'is_pinned',
40
        'is_solved',
41
        'is_edited',
42
        'edit_count'
43
    ];
44
45
    /**
46
     * The accessors to append to the model's array form.
47
     *
48
     * @var array
49
     */
50
    protected $appends = [
51
        'conversation_url',
52
        'last_page'
53
    ];
54
55
    /**
56
     * The attributes that should be mutated to dates.
57
     *
58
     * @var array
59
     */
60
    protected $dates = [
61
        'edited_at'
62
    ];
63
64
    /**
65
     * The "booting" method of the model.
66
     *
67
     * @return void
68
     */
69
    protected static function boot()
70
    {
71
        parent::boot();
72
73
        // Set the user id to the new conversation before saving it.
74
        static::creating(function ($model) {
75
            $model->user_id = Auth::id();
76
        });
77
78
        // Generated the slug before updating.
79
        static::updating(function ($model) {
80
            $model->generateSlug();
81
        });
82
83
        // Handle the before deleting the conversation.
84
        static::deleting(function ($model) {
85
            $category = $model->category;
86
87
            // If the conversation is the last_conversation of the category,
88
            // find the new last_conversation and update the category.
89
            if ($category->last_conversation_id == $model->getKey()) {
90
                $previousConversation = DiscussConversationRepository::findPreviousConversation($model);
91
92
                if (is_null($previousConversation)) {
93
                    $category->last_conversation_id = null;
94
                } else {
95
                    $category->last_conversation_id = $previousConversation->getKey();
96
                }
97
98
                $category->save();
99
            }
100
101
            // Set the forgein keys to null, else it won't delete since it delete
102
            // the posts before the conversation.
103
            $model->first_post_id = null;
104
            $model->last_post_id = null;
105
            $model->solved_post_id = null;
106
            $model->save();
107
108
            // We need to do this to refresh the countable cache `discuss_post_count` of the user.
109
            foreach ($model->posts as $post) {
110
                $post->delete();
111
            }
112
113
            // It don't delete the logs, so we need to do it manually.
114
            foreach ($model->discussLogs as $log) {
115
                $log->delete();
116
            }
117
        });
118
    }
119
120
    /**
121
     * Return the field to slug.
122
     *
123
     * @return string
124
     */
125
    public function slugStrategy(): string
126
    {
127
        return 'title';
128
    }
129
130
    /**
131
     * Return the count cache configuration.
132
     *
133
     * @return array
134
     */
135
    public function countCaches(): array
136
    {
137
        return [
138
            'discuss_conversation_count' => [User::class, 'user_id', 'id'],
139
            'conversation_count' => [DiscussCategory::class, 'category_id', 'id']
140
        ];
141
    }
142
143
    /**
144
     * Get the category that owns the conversation.
145
     *
146
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
147
     */
148
    public function category()
149
    {
150
        return $this->belongsTo(DiscussCategory::class);
151
    }
152
153
    /**
154
     * Get the user that owns the conversation.
155
     *
156
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
157
     */
158
    public function user()
159
    {
160
        return $this->belongsTo(User::class);
161
    }
162
163
    /**
164
     * Get the posts for the conversation.
165
     *
166
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
167
     */
168
    public function posts()
169
    {
170
        return $this->hasMany(DiscussPost::class, 'conversation_id', 'id');
171
    }
172
173
    /**
174
     * Get the users for the conversation.
175
     *
176
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
177
     */
178
    public function users()
179
    {
180
        return $this->hasMany(DiscussUser::class, 'conversation_id', 'id');
181
    }
182
183
    /**
184
     * Get the first post of the conversation.
185
     *
186
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
187
     */
188
    public function firstPost()
189
    {
190
        return $this->hasOne(DiscussPost::class, 'id', 'first_post_id');
191
    }
192
193
    /**
194
     * Get the solved post of the conversation.
195
     *
196
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
197
     */
198
    public function solvedPost()
199
    {
200
        return $this->hasOne(DiscussPost::class, 'id', 'solved_post_id');
201
    }
202
203
    /**
204
     * Get the last post of the conversation.
205
     *
206
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
207
     */
208
    public function lastPost()
209
    {
210
        return $this->hasOne(DiscussPost::class, 'id', 'last_post_id');
211
    }
212
213
    /**
214
     * Get the user that edited the conversation.
215
     *
216
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
217
     */
218
    public function editedUser()
219
    {
220
        return $this->hasOne(User::class, 'id', 'edited_user_id');
221
    }
222
223
    /**
224
     * Get the discuss logs for the conversation.
225
     *
226
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
227
     */
228
    public function discussLogs()
229
    {
230
        return $this->morphMany(DiscussLog::class, 'loggable');
231
    }
232
233
    /**
234
     * Get the logs and posts related to the current conversation
235
     * for the given the pagination posts and return the data
236
     * ordered by `created_at` as a Collection.
237
     *
238
     * @param \Illuminate\Support\Collection $posts
239
     * @param int $page
240
     *
241
     * @return \Illuminate\Support\Collection
242
     */
243
    public function getPostsWithLogs(Collection $posts, int $page): Collection
244
    {
245
        $logs = DiscussLog::where([
246
            'loggable_type' => get_class($this),
247
            'loggable_id' => $this->getKey(),
248
        ]);
249
250
        if (!$posts->isEmpty()) {
251
            $previousPost = DiscussPostRepository::findPreviousPost($posts->first());
252
        }
253
254
        // When there're several pages and the current page is not the first and not the last.
255
        if ($this->lastPage > $page && $page !== 1) {
256
            $logs = $logs->where('created_at', '<=', $posts->last()->created_at)
257
                ->where('created_at', '>=', $previousPost->created_at);
0 ignored issues
show
Bug introduced by
The variable $previousPost does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
258
259
        // When there're only one page.
260
        } elseif ($this->lastPage == 1) {
261
            $logs = $logs->where('created_at', '>=', $this->created_at);
262
263
        // When there're several pages and the current page is the first page.
264
        } elseif ($page == 1) {
265
            $logs = $logs->where('created_at', '<=', $posts->last()->created_at);
266
267
        // When there're several page and the current page is the last page
268
        } elseif ($page == $this->lastPage) {
269
            $logs = $logs->where('created_at', '>', $previousPost->created_at);
270
        }
271
        $postsWithLogs = $posts->merge($logs->get())->sortBy('created_at');
272
273
        // If the conversation has a solved post, prepend it
274
        // then prepend the first post to the collection
275
        if ($this->lastPage == 1 || $page == 1) {
276
            if (!is_null($this->solved_post_id)) {
277
                $postsWithLogs->prepend(DiscussPost::findOrFail($this->solved_post_id));
278
            }
279
            $postsWithLogs->prepend(DiscussPost::findOrFail($this->first_post_id));
280
        }
281
282
        return $postsWithLogs;
283
    }
284
}
285