Passed
Push — master ( 646b1f...d2cbbe )
by Malte
02:44
created

Query::paginate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
* File:     Query.php
4
* Category: -
5
* Author:   M. Goldenbaum
6
* Created:  21.07.18 18:54
7
* Updated:  -
8
*
9
* Description:
10
*  -
11
*/
12
13
namespace Webklex\IMAP\Query;
14
15
use Carbon\Carbon;
16
use Webklex\IMAP\Client;
17
use Webklex\IMAP\Exceptions\GetMessagesFailedException;
18
use Webklex\IMAP\Exceptions\MessageSearchValidationException;
19
use Webklex\IMAP\IMAP;
20
use Webklex\IMAP\Message;
21
use Webklex\IMAP\Support\MessageCollection;
22
23
/**
24
 * Class Query
25
 *
26
 * @package Webklex\IMAP\Query
27
 */
28
class Query {
29
30
    /** @var array $query */
31
    protected $query;
32
33
    /** @var string $raw_query  */
34
    protected $raw_query;
35
36
    /** @var string $charset */
37
    protected $charset;
38
39
    /** @var Client $client */
40
    protected $client;
41
42
    /** @var int $limit */
43
    protected $limit = null;
44
45
    /** @var int $page */
46
    protected $page = 1;
47
48
    /** @var int $fetch_options */
49
    protected $fetch_options = null;
50
51
    /** @var int $fetch_body */
52
    protected $fetch_body = true;
53
54
    /** @var int $fetch_attachment */
55
    protected $fetch_attachment = true;
56
57
    /** @var int $fetch_flags */
58
    protected $fetch_flags = true;
59
60
    /**
61
     * Query constructor.
62
     * @param Client $client
63
     * @param string $charset
64
     */
65
    public function __construct(Client $client, $charset = 'UTF-8') {
66
        $this->setClient($client);
67
68
        if(config('imap.options.fetch') === IMAP::FT_PEEK) $this->leaveUnread();
69
70
        $this->charset = $charset;
71
        $this->query = collect();
0 ignored issues
show
Documentation Bug introduced by
It seems like collect() of type Illuminate\Support\Collection is incompatible with the declared type array of property $query.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
72
        $this->boot();
73
    }
74
75
    /**
76
     * Instance boot method for additional functionality
77
     */
78
    protected function boot(){}
79
80
    /**
81
     * Parse a given value
82
     * @param mixed $value
83
     *
84
     * @return string
85
     */
86
    protected function parse_value($value){
87
        switch(true){
88
            case $value instanceof \Carbon\Carbon:
89
                $value = $value->format('d M y');
90
                break;
91
        }
92
93
        return (string) $value;
94
    }
95
96
    /**
97
     * Check if a given date is a valid carbon object and if not try to convert it
98
     * @param $date
99
     *
100
     * @return Carbon
101
     * @throws MessageSearchValidationException
102
     */
103
    protected function parse_date($date) {
104
        if($date instanceof \Carbon\Carbon) return $date;
105
106
        try {
107
            $date = Carbon::parse($date);
108
        } catch (\Exception $e) {
109
            throw new MessageSearchValidationException();
110
        }
111
112
        return $date;
113
    }
114
115
    /**
116
     * Don't mark messages as read when fetching
117
     *
118
     * @return $this
119
     */
120
    public function leaveUnread() {
121
        $this->setFetchOptions(IMAP::FT_PEEK);
0 ignored issues
show
Bug introduced by
Webklex\IMAP\IMAP::FT_PEEK of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
        $this->setFetchOptions(/** @scrutinizer ignore-type */ IMAP::FT_PEEK);
Loading history...
122
123
        return $this;
124
    }
125
126
    /**
127
     * Mark all messages as read when fetching
128
     *
129
     * @return $this
130
     */
131
    public function markAsRead() {
132
        $this->setFetchOptions(IMAP::FT_UID);
0 ignored issues
show
Bug introduced by
Webklex\IMAP\IMAP::FT_UID of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
        $this->setFetchOptions(/** @scrutinizer ignore-type */ IMAP::FT_UID);
Loading history...
133
134
        return $this;
135
    }
136
137
    /**
138
     * Fetch the current query and return all found messages
139
     *
140
     * @return MessageCollection
141
     * @throws GetMessagesFailedException
142
     */
143
    public function get() {
144
        $messages = MessageCollection::make([]);
145
146
        try {
147
            $this->generate_query();
148
149
            /**
150
             * Don't set the charset if it isn't used - prevent strange outlook mail server errors
151
             * @see https://github.com/Webklex/laravel-imap/issues/100
152
             */
153
            if($this->getCharset() === null){
0 ignored issues
show
introduced by
The condition $this->getCharset() === null is always false.
Loading history...
154
                $available_messages = imap_search($this->getClient()->getConnection(), $this->getRawQuery(), IMAP::SE_UID);
155
            }else{
156
                $available_messages = imap_search($this->getClient()->getConnection(), $this->getRawQuery(), IMAP::SE_UID, $this->getCharset());
0 ignored issues
show
Bug introduced by
It seems like $this->getClient()->getConnection() can also be of type true; however, parameter $imap_stream of imap_search() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

156
                $available_messages = imap_search(/** @scrutinizer ignore-type */ $this->getClient()->getConnection(), $this->getRawQuery(), IMAP::SE_UID, $this->getCharset());
Loading history...
157
            }
158
159
            if ($available_messages !== false) {
160
161
                $available_messages = collect($available_messages);
162
                $options = config('imap.options');
163
164
                if(strtolower($options['fetch_order']) === 'desc'){
165
                    $available_messages = $available_messages->reverse();
166
                }
167
168
                $available_messages->forPage($this->page, $this->limit)->each(function($msgno, $msglist) use(&$messages, $options) {
169
                    $oMessage = new Message($msgno, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchAttachment(), $this->getFetchFlags());
0 ignored issues
show
Bug introduced by
$this->getFetchFlags() of type integer is incompatible with the type boolean expected by parameter $fetch_flags of Webklex\IMAP\Message::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
                    $oMessage = new Message($msgno, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchAttachment(), /** @scrutinizer ignore-type */ $this->getFetchFlags());
Loading history...
170
                    switch ($options['message_key']){
171
                        case 'number':
172
                            $message_key = $oMessage->getMessageNo();
173
                            break;
174
                        case 'list':
175
                            $message_key = $msglist;
176
                            break;
177
                        default:
178
                            $message_key = $oMessage->getMessageId();
179
                            break;
180
181
                    }
182
                    $messages->put($message_key, $oMessage);
183
                });
184
            }
185
186
            return $messages;
187
        } catch (\Exception $e) {
188
            $message = $e->getMessage();
189
190
            throw new GetMessagesFailedException($message);
191
        }
192
    }
193
194
    /**
195
     * Paginate the current query
196
     * @param int $per_page
197
     * @param null $page
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $page is correct as it would always require null to be passed?
Loading history...
198
     * @param string $page_name
199
     *
200
     * @return \Illuminate\Pagination\LengthAwarePaginator
201
     * @throws GetMessagesFailedException
202
     */
203
    public function paginate($per_page = 5, $page = null, $page_name = 'imap_page'){
204
        $this->page = $page > $this->page ? $page : $this->page;
205
        $this->limit = $per_page;
206
207
        return $this->get()->paginate($per_page = 5, $this->page, $page_name);
208
    }
209
210
    /**
211
     * Get the raw IMAP search query
212
     *
213
     * @return string
214
     */
215
    public function generate_query() {
216
        $query = '';
217
        $this->query->each(function($statement) use(&$query) {
218
            if (count($statement) == 1) {
219
                $query .= $statement[0];
220
            } else {
221
                if($statement[1] === null){
222
                    $query .= $statement[0];
223
                }else{
224
                    $query .= $statement[0].' "'.$statement[1].'"';
225
                }
226
            }
227
            $query .= ' ';
228
229
        });
230
231
        $this->raw_query = trim($query);
232
233
        return $this->raw_query;
234
    }
235
236
    /**
237
     * @return Client
238
     * @throws \Webklex\IMAP\Exceptions\ConnectionFailedException
239
     */
240
    public function getClient() {
241
        $this->client->checkConnection();
242
        return $this->client;
243
    }
244
245
    /**
246
     * Set the limit and page for the current query
247
     * @param int $limit
248
     * @param int $page
249
     *
250
     * @return $this
251
     */
252
    public function limit($limit, $page = 1) {
253
        if($page >= 1) $this->page = $page;
254
        $this->limit = $limit;
255
256
        return $this;
257
    }
258
259
    /**
260
     * @return array
261
     */
262
    public function getQuery() {
263
        return $this->query;
264
    }
265
266
    /**
267
     * @param array $query
268
     * @return Query
269
     */
270
    public function setQuery($query) {
271
        $this->query = $query;
272
        return $this;
273
    }
274
275
    /**
276
     * @return string
277
     */
278
    public function getRawQuery() {
279
        return $this->raw_query;
280
    }
281
282
    /**
283
     * @param string $raw_query
284
     * @return Query
285
     */
286
    public function setRawQuery($raw_query) {
287
        $this->raw_query = $raw_query;
288
        return $this;
289
    }
290
291
    /**
292
     * @return string
293
     */
294
    public function getCharset() {
295
        return $this->charset;
296
    }
297
298
    /**
299
     * @param string $charset
300
     * @return Query
301
     */
302
    public function setCharset($charset) {
303
        $this->charset = $charset;
304
        return $this;
305
    }
306
307
    /**
308
     * @param Client $client
309
     * @return Query
310
     */
311
    public function setClient(Client $client) {
312
        $this->client = $client;
313
        return $this;
314
    }
315
316
    /**
317
     * @return int
318
     */
319
    public function getLimit() {
320
        return $this->limit;
321
    }
322
323
    /**
324
     * @param int $limit
325
     * @return Query
326
     */
327
    public function setLimit($limit) {
328
        $this->limit = $limit <= 0 ? null : $limit;
329
        return $this;
330
    }
331
332
    /**
333
     * @return int
334
     */
335
    public function getPage() {
336
        return $this->page;
337
    }
338
339
    /**
340
     * @param int $page
341
     * @return Query
342
     */
343
    public function setPage($page) {
344
        $this->page = $page;
345
        return $this;
346
    }
347
348
    /**
349
     * @param boolean $fetch_options
350
     * @return Query
351
     */
352
    public function setFetchOptions($fetch_options) {
353
        $this->fetch_options = $fetch_options;
0 ignored issues
show
Documentation Bug introduced by
The property $fetch_options was declared of type integer, but $fetch_options is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
354
        return $this;
355
    }
356
357
    /**
358
     * @param boolean $fetch_options
359
     * @return Query
360
     */
361
    public function fetchOptions($fetch_options) {
362
        return $this->setFetchOptions($fetch_options);
363
    }
364
365
    /**
366
     * @return int
367
     */
368
    public function getFetchOptions() {
369
        return $this->fetch_options;
370
    }
371
372
    /**
373
     * @return boolean
374
     */
375
    public function getFetchBody() {
376
        return $this->fetch_body;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->fetch_body returns the type integer which is incompatible with the documented return type boolean.
Loading history...
377
    }
378
379
    /**
380
     * @param boolean $fetch_body
381
     * @return Query
382
     */
383
    public function setFetchBody($fetch_body) {
384
        $this->fetch_body = $fetch_body;
0 ignored issues
show
Documentation Bug introduced by
The property $fetch_body was declared of type integer, but $fetch_body is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
385
        return $this;
386
    }
387
388
    /**
389
     * @param boolean $fetch_body
390
     * @return Query
391
     */
392
    public function fetchBody($fetch_body) {
393
        return $this->setFetchBody($fetch_body);
394
    }
395
396
    /**
397
     * @return boolean
398
     */
399
    public function getFetchAttachment() {
400
        return $this->fetch_attachment;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->fetch_attachment returns the type integer which is incompatible with the documented return type boolean.
Loading history...
401
    }
402
403
    /**
404
     * @param boolean $fetch_attachment
405
     * @return Query
406
     */
407
    public function setFetchAttachment($fetch_attachment) {
408
        $this->fetch_attachment = $fetch_attachment;
0 ignored issues
show
Documentation Bug introduced by
The property $fetch_attachment was declared of type integer, but $fetch_attachment is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
409
        return $this;
410
    }
411
412
    /**
413
     * @param boolean $fetch_attachment
414
     * @return Query
415
     */
416
    public function fetchAttachment($fetch_attachment) {
417
        return $this->setFetchAttachment($fetch_attachment);
418
    }
419
420
    /**
421
     * @return int
422
     */
423
    public function getFetchFlags() {
424
        return $this->fetch_flags;
425
    }
426
427
    /**
428
     * @param int $fetch_flags
429
     * @return Query
430
     */
431
    public function setFetchFlags($fetch_flags) {
432
        $this->fetch_flags = $fetch_flags;
433
        return $this;
434
    }
435
}