Passed
Push — master ( 417c1c...abd91e )
by Malte
02:26 queued 24s
created

Query::paginate()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 14
rs 9.6111
cc 5
nc 3
nop 3
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\PHPIMAP\Query;
14
15
use Carbon\Carbon;
16
use Illuminate\Pagination\LengthAwarePaginator;
17
use Illuminate\Support\Collection;
18
use Webklex\PHPIMAP\Client;
19
use Webklex\PHPIMAP\ClientManager;
20
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
21
use Webklex\PHPIMAP\Exceptions\GetMessagesFailedException;
22
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
23
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
24
use Webklex\PHPIMAP\Exceptions\MessageHeaderFetchingException;
25
use Webklex\PHPIMAP\Exceptions\MessageSearchValidationException;
26
use Webklex\PHPIMAP\Exceptions\RuntimeException;
27
use Webklex\PHPIMAP\IMAP;
28
use Webklex\PHPIMAP\Message;
29
use Webklex\PHPIMAP\Support\MessageCollection;
30
31
/**
32
 * Class Query
33
 *
34
 * @package Webklex\PHPIMAP\Query
35
 */
36
class Query {
37
38
    /** @var array $query */
39
    protected $query;
40
41
    /** @var string $raw_query  */
42
    protected $raw_query;
43
44
    /** @var string $charset */
45
    protected $charset;
46
47
    /** @var Client $client */
48
    protected $client;
49
50
    /** @var int $limit */
51
    protected $limit = null;
52
53
    /** @var int $page */
54
    protected $page = 1;
55
56
    /** @var int $fetch_options */
57
    protected $fetch_options = null;
58
59
    /** @var int $fetch_body */
60
    protected $fetch_body = true;
61
62
    /** @var int $fetch_flags */
63
    protected $fetch_flags = true;
64
65
    /** @var int $sequence */
66
    protected $sequence = IMAP::NIL;
67
68
    /** @var string $fetch_order */
69
    protected $fetch_order;
70
71
    /** @var string $date_format */
72
    protected $date_format;
73
74
    /**
75
     * Query constructor.
76
     * @param Client $client
77
     * @param string $charset
78
     */
79
    public function __construct(Client $client, $charset = 'UTF-8') {
80
        $this->setClient($client);
81
82
        $this->sequence = ClientManager::get('options.sequence', IMAP::ST_MSGN);
83
        if(ClientManager::get('options.fetch') === IMAP::FT_PEEK) $this->leaveUnread();
84
85
        if (ClientManager::get('options.fetch_order') === 'desc') {
86
            $this->fetch_order = 'desc';
87
        } else {
88
            $this->fetch_order = 'asc';
89
        }
90
91
        $this->date_format = ClientManager::get('date_format', 'd M y');
92
93
        $this->charset = $charset;
94
        $this->query = collect();
95
        $this->boot();
96
    }
97
98
    /**
99
     * Instance boot method for additional functionality
100
     */
101
    protected function boot(){}
102
103
    /**
104
     * Parse a given value
105
     * @param mixed $value
106
     *
107
     * @return string
108
     */
109
    protected function parse_value($value){
110
        switch(true){
111
            case $value instanceof \Carbon\Carbon:
112
                $value = $value->format($this->date_format);
113
                break;
114
        }
115
116
        return (string) $value;
117
    }
118
119
    /**
120
     * Check if a given date is a valid carbon object and if not try to convert it
121
     * @param $date
122
     *
123
     * @return Carbon
124
     * @throws MessageSearchValidationException
125
     */
126
    protected function parse_date($date) {
127
        if($date instanceof \Carbon\Carbon) return $date;
128
129
        try {
130
            $date = Carbon::parse($date);
131
        } catch (\Exception $e) {
132
            throw new MessageSearchValidationException();
133
        }
134
135
        return $date;
136
    }
137
138
    /**
139
     * Don't mark messages as read when fetching
140
     *
141
     * @return $this
142
     */
143
    public function leaveUnread() {
144
        $this->setFetchOptions(IMAP::FT_PEEK);
145
146
        return $this;
147
    }
148
149
    /**
150
     * Mark all messages as read when fetching
151
     *
152
     * @return $this
153
     */
154
    public function markAsRead() {
155
        $this->setFetchOptions(IMAP::FT_UID);
156
157
        return $this;
158
    }
159
160
    /**
161
     * Set the sequence type
162
     * @param int $sequence
163
     *
164
     * @return $this
165
     */
166
    public function setSequence($sequence) {
167
        $this->sequence = $sequence != IMAP::ST_MSGN ? IMAP::ST_UID : $sequence;
168
169
        return $this;
170
    }
171
172
    /**
173
     * Perform an imap search request
174
     *
175
     * @return Collection
176
     * @throws GetMessagesFailedException
177
     */
178
    protected function search(){
179
        $this->generate_query();
180
181
        try {
182
            $available_messages = $this->client->getConnection()->search([$this->getRawQuery()], $this->sequence == IMAP::ST_UID);
183
        } catch (RuntimeException $e) {
184
            $available_messages = false;
185
        } catch (ConnectionFailedException $e) {
186
            throw new GetMessagesFailedException("failed to fetch messages", 0, $e);
187
        }
188
189
        if ($available_messages !== false) {
190
            return collect($available_messages);
191
        }
192
193
        return collect();
194
    }
195
196
    /**
197
     * Count all available messages matching the current search criteria
198
     *
199
     * @return int
200
     * @throws GetMessagesFailedException
201
     */
202
    public function count() {
203
        return $this->search()->count();
204
    }
205
206
    /**
207
     * Fetch the current query and return all found messages
208
     *
209
     * @return MessageCollection
210
     * @throws GetMessagesFailedException
211
     */
212
    public function get() {
213
        $messages = MessageCollection::make([]);
214
215
        $available_messages = $this->search();
216
        try {
217
            if (($available_messages_count = $available_messages->count()) > 0) {
218
219
                $messages->total($available_messages_count);
220
221
                if ($this->fetch_order === 'desc') {
222
                    $available_messages = $available_messages->reverse();
223
                }
224
225
                $message_key = ClientManager::get('options.message_key');
226
227
                $uids = $available_messages->forPage($this->page, $this->limit)->toArray();
228
229
                $raw_flags = $this->client->getConnection()->flags($uids, $this->sequence == IMAP::ST_UID);
230
                $raw_headers = $this->client->getConnection()->headers($uids, "RFC822", $this->sequence == IMAP::ST_UID);
231
232
                $raw_contents = [];
233
                if ($this->getFetchBody()) {
234
                    $raw_contents = $this->client->getConnection()->content($uids, "RFC822", $this->sequence == IMAP::ST_UID);
235
                }
236
237
                $msglist = 0;
238
                foreach ($raw_headers as $uid => $raw_header) {
239
                    $raw_content = isset($raw_contents[$uid]) ? $raw_contents[$uid] : "";
240
                    $raw_flag = isset($raw_flags[$uid]) ? $raw_flags[$uid] : [];
241
242
                    $message = Message::make($uid, $msglist, $this->getClient(), $raw_header, $raw_content, $raw_flag, $this->getFetchOptions(), $this->sequence);
243
                    switch ($message_key){
244
                        case 'number':
245
                            $message_key = $message->getMessageNo();
246
                            break;
247
                        case 'list':
248
                            $message_key = $msglist;
249
                            break;
250
                        case 'uid':
251
                            $message_key = $message->getUid();
252
                            break;
253
                        default:
254
                            $message_key = $message->getMessageId();
255
                            break;
256
257
                    }
258
                    $messages->put($message_key, $message);
259
                    $msglist++;
260
                }
261
            }
262
263
            return $messages;
264
        } catch (\Exception $e) {
265
            throw new GetMessagesFailedException($e->getMessage(),0, $e);
266
        }
267
    }
268
269
    /**
270
     * Get a new Message instance
271
     * @param int $uid
272
     * @param null $msglist
273
     * @param null $sequence
274
     *
275
     * @return Message
276
     * @throws ConnectionFailedException
277
     * @throws RuntimeException
278
     * @throws InvalidMessageDateException
279
     * @throws MessageContentFetchingException
280
     * @throws MessageHeaderFetchingException
281
     * @throws \Webklex\PHPIMAP\Exceptions\EventNotFoundException
282
     */
283
    public function getMessage($uid, $msglist = null, $sequence = null){
284
        return new Message($uid, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchFlags(), $sequence ? $sequence : $this->sequence);
285
    }
286
287
    /**
288
     * Get a message by its message number
289
     * @param $msgn
290
     * @param null $msglist
291
     * 
292
     * @return Message
293
     * @throws ConnectionFailedException
294
     * @throws InvalidMessageDateException
295
     * @throws MessageContentFetchingException
296
     * @throws MessageHeaderFetchingException
297
     * @throws RuntimeException
298
     * @throws \Webklex\PHPIMAP\Exceptions\EventNotFoundException
299
     */
300
    public function getMessageByMsgn($msgn, $msglist = null){
301
        return $this->getMessage($msgn, $msglist, IMAP::ST_MSGN);
302
    }
303
     * Paginate the current query
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected '*', expecting T_FUNCTION or T_CONST on line 303 at column 5
Loading history...
304
     * @param int $per_page
305
     * @param null $page
306
     * @param string $page_name
307
     *
308
     * @return LengthAwarePaginator
309
     * @throws GetMessagesFailedException
310
     */
311
    public function paginate($per_page = 5, $page = null, $page_name = 'imap_page'){
312
        if (
313
               $page === null
314
            && isset($_GET[$page_name])
315
            && $_GET[$page_name] > 0
316
        ) {
317
            $this->page = intval($_GET[$page_name]);
318
        } elseif ($page > 0) {
319
            $this->page = $page;
320
        }
321
322
        $this->limit = $per_page;
323
324
        return $this->get()->paginate($per_page, $this->page, $page_name, true);
325
    }
326
327
    /**
328
     * Get the raw IMAP search query
329
     *
330
     * @return string
331
     */
332
    public function generate_query() {
333
        $query = '';
334
        $this->query->each(function($statement) use(&$query) {
335
            if (count($statement) == 1) {
336
                $query .= $statement[0];
337
            } else {
338
                if($statement[1] === null){
339
                    $query .= $statement[0];
340
                }else{
341
                    $query .= $statement[0].' "'.$statement[1].'"';
342
                }
343
            }
344
            $query .= ' ';
345
346
        });
347
348
        $this->raw_query = trim($query);
349
350
        return $this->raw_query;
351
    }
352
353
    /**
354
     * @return Client
355
     * @throws ConnectionFailedException
356
     */
357
    public function getClient() {
358
        $this->client->checkConnection();
359
        return $this->client;
360
    }
361
362
    /**
363
     * Set the limit and page for the current query
364
     * @param int $limit
365
     * @param int $page
366
     *
367
     * @return $this
368
     */
369
    public function limit($limit, $page = 1) {
370
        if($page >= 1) $this->page = $page;
371
        $this->limit = $limit;
372
373
        return $this;
374
    }
375
376
    /**
377
     * @return array
378
     */
379
    public function getQuery() {
380
        return $this->query;
381
    }
382
383
    /**
384
     * @param array $query
385
     * @return Query
386
     */
387
    public function setQuery($query) {
388
        $this->query = $query;
389
        return $this;
390
    }
391
392
    /**
393
     * @return string
394
     */
395
    public function getRawQuery() {
396
        return $this->raw_query;
397
    }
398
399
    /**
400
     * @param string $raw_query
401
     * @return Query
402
     */
403
    public function setRawQuery($raw_query) {
404
        $this->raw_query = $raw_query;
405
        return $this;
406
    }
407
408
    /**
409
     * @return string
410
     */
411
    public function getCharset() {
412
        return $this->charset;
413
    }
414
415
    /**
416
     * @param string $charset
417
     * @return Query
418
     */
419
    public function setCharset($charset) {
420
        $this->charset = $charset;
421
        return $this;
422
    }
423
424
    /**
425
     * @param Client $client
426
     * @return Query
427
     */
428
    public function setClient(Client $client) {
429
        $this->client = $client;
430
        return $this;
431
    }
432
433
    /**
434
     * @return int
435
     */
436
    public function getLimit() {
437
        return $this->limit;
438
    }
439
440
    /**
441
     * @param int $limit
442
     * @return Query
443
     */
444
    public function setLimit($limit) {
445
        $this->limit = $limit <= 0 ? null : $limit;
446
        return $this;
447
    }
448
449
    /**
450
     * @return int
451
     */
452
    public function getPage() {
453
        return $this->page;
454
    }
455
456
    /**
457
     * @param int $page
458
     * @return Query
459
     */
460
    public function setPage($page) {
461
        $this->page = $page;
462
        return $this;
463
    }
464
465
    /**
466
     * @param boolean $fetch_options
467
     * @return Query
468
     */
469
    public function setFetchOptions($fetch_options) {
470
        $this->fetch_options = $fetch_options;
471
        return $this;
472
    }
473
474
    /**
475
     * @param boolean $fetch_options
476
     * @return Query
477
     */
478
    public function fetchOptions($fetch_options) {
479
        return $this->setFetchOptions($fetch_options);
480
    }
481
482
    /**
483
     * @return int
484
     */
485
    public function getFetchOptions() {
486
        return $this->fetch_options;
487
    }
488
489
    /**
490
     * @return boolean
491
     */
492
    public function getFetchBody() {
493
        return $this->fetch_body;
494
    }
495
496
    /**
497
     * @param boolean $fetch_body
498
     * @return Query
499
     */
500
    public function setFetchBody($fetch_body) {
501
        $this->fetch_body = $fetch_body;
502
        return $this;
503
    }
504
505
    /**
506
     * @param boolean $fetch_body
507
     * @return Query
508
     */
509
    public function fetchBody($fetch_body) {
510
        return $this->setFetchBody($fetch_body);
511
    }
512
513
    /**
514
     * @return int
515
     */
516
    public function getFetchFlags() {
517
        return $this->fetch_flags;
518
    }
519
520
    /**
521
     * @param int $fetch_flags
522
     * @return Query
523
     */
524
    public function setFetchFlags($fetch_flags) {
525
        $this->fetch_flags = $fetch_flags;
526
        return $this;
527
    }
528
529
    /**
530
     * @param string $fetch_order
531
     * @return Query
532
     */
533
    public function setFetchOrder($fetch_order) {
534
        $fetch_order = strtolower($fetch_order);
535
536
        if (in_array($fetch_order, ['asc', 'desc'])) {
537
            $this->fetch_order = $fetch_order;
538
        }
539
540
        return $this;
541
    }
542
543
    /**
544
     * @param string $fetch_order
545
     * @return Query
546
     */
547
    public function fetchOrder($fetch_order) {
548
        return $this->setFetchOrder($fetch_order);
549
    }
550
551
    /**
552
     * @return string
553
     */
554
    public function getFetchOrder() {
555
        return $this->fetch_order;
556
    }
557
558
    /**
559
     * @return Query
560
     */
561
    public function setFetchOrderAsc() {
562
        return $this->setFetchOrder('asc');
563
    }
564
565
    /**
566
     * @return Query
567
     */
568
    public function fetchOrderAsc() {
569
        return $this->setFetchOrderAsc();
570
    }
571
572
    /**
573
     * @return Query
574
     */
575
    public function setFetchOrderDesc() {
576
        return $this->setFetchOrder('desc');
577
    }
578
579
    /**
580
     * @return Query
581
     */
582
    public function fetchOrderDesc() {
583
        return $this->setFetchOrderDesc();
584
    }
585
}
586