Completed
Pull Request — master (#34)
by Fèvre
18:57 queued 15:50
created

DiscussConversation::getPostsWithLogs()   D

Complexity

Conditions 9
Paths 15

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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