Passed
Push — master ( 4dc410...354c27 )
by Malte
03:19
created

Query::getByUidGreater()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 2
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
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 Exception;
17
use Illuminate\Pagination\LengthAwarePaginator;
18
use Illuminate\Support\Collection;
19
use ReflectionException;
20
use Webklex\PHPIMAP\Client;
21
use Webklex\PHPIMAP\ClientManager;
22
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
23
use Webklex\PHPIMAP\Exceptions\EventNotFoundException;
24
use Webklex\PHPIMAP\Exceptions\GetMessagesFailedException;
25
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
26
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
27
use Webklex\PHPIMAP\Exceptions\MessageFlagException;
28
use Webklex\PHPIMAP\Exceptions\MessageHeaderFetchingException;
29
use Webklex\PHPIMAP\Exceptions\MessageNotFoundException;
30
use Webklex\PHPIMAP\Exceptions\MessageSearchValidationException;
31
use Webklex\PHPIMAP\Exceptions\RuntimeException;
32
use Webklex\PHPIMAP\IMAP;
33
use Webklex\PHPIMAP\Message;
34
use Webklex\PHPIMAP\Support\MessageCollection;
35
36
/**
37
 * Class Query
38
 *
39
 * @package Webklex\PHPIMAP\Query
40
 */
41
class Query {
42
43
    /** @var Collection $query */
44
    protected $query;
45
46
    /** @var string $raw_query */
47
    protected $raw_query;
48
49
    /** @var string[] $extensions */
50
    protected $extensions;
51
52
    /** @var Client $client */
53
    protected $client;
54
55
    /** @var int $limit */
56
    protected $limit = null;
57
58
    /** @var int $page */
59
    protected $page = 1;
60
61
    /** @var int $fetch_options */
62
    protected $fetch_options = null;
63
64
    /** @var int $fetch_body */
65
    protected $fetch_body = true;
66
67
    /** @var int $fetch_flags */
68
    protected $fetch_flags = true;
69
70
    /** @var int|string $sequence */
71
    protected $sequence = IMAP::NIL;
72
73
    /** @var string $fetch_order */
74
    protected $fetch_order;
75
76
    /** @var string $date_format */
77
    protected $date_format;
78
79
    /** @var bool $soft_fail */
80
    protected $soft_fail = false;
81
82
    /** @var array $errors */
83
    protected $errors = [];
84
85
    /**
86
     * Query constructor.
87
     * @param Client $client
88
     * @param string[] $extensions
89
     */
90
    public function __construct(Client $client, $extensions = []) {
91
        $this->setClient($client);
92
93
        $this->sequence = ClientManager::get('options.sequence', IMAP::ST_MSGN);
94
        if (ClientManager::get('options.fetch') === IMAP::FT_PEEK) $this->leaveUnread();
95
96
        if (ClientManager::get('options.fetch_order') === 'desc') {
97
            $this->fetch_order = 'desc';
98
        } else {
99
            $this->fetch_order = 'asc';
100
        }
101
102
        $this->date_format = ClientManager::get('date_format', 'd M y');
103
        $this->soft_fail = ClientManager::get('options.soft_fail', false);
104
105
        $this->setExtensions($extensions);
106
        $this->query = new Collection();
107
        $this->boot();
108
    }
109
110
    /**
111
     * Instance boot method for additional functionality
112
     */
113
    protected function boot() {
114
    }
115
116
    /**
117
     * Parse a given value
118
     * @param mixed $value
119
     *
120
     * @return string
121
     */
122
    protected function parse_value($value) {
123
        switch (true) {
124
            case $value instanceof Carbon:
125
                $value = $value->format($this->date_format);
126
                break;
127
        }
128
129
        return (string)$value;
130
    }
131
132
    /**
133
     * Check if a given date is a valid carbon object and if not try to convert it
134
     * @param string|Carbon $date
135
     *
136
     * @return Carbon
137
     * @throws MessageSearchValidationException
138
     */
139
    protected function parse_date($date) {
140
        if ($date instanceof Carbon) return $date;
141
142
        try {
143
            $date = Carbon::parse($date);
144
        } catch (Exception $e) {
145
            throw new MessageSearchValidationException();
146
        }
147
148
        return $date;
149
    }
150
151
    /**
152
     * Get the raw IMAP search query
153
     *
154
     * @return string
155
     */
156
    public function generate_query() {
157
        $query = '';
158
        $this->query->each(function($statement) use (&$query) {
159
            if (count($statement) == 1) {
160
                $query .= $statement[0];
161
            } else {
162
                if ($statement[1] === null) {
163
                    $query .= $statement[0];
164
                } else {
165
                    if (is_numeric($statement[1])) {
166
                        $query .= $statement[0] . ' ' . $statement[1];
167
                    } else {
168
                        $query .= $statement[0] . ' "' . $statement[1] . '"';
169
                    }
170
                }
171
            }
172
            $query .= ' ';
173
174
        });
175
176
        $this->raw_query = trim($query);
177
178
        return $this->raw_query;
179
    }
180
181
    /**
182
     * Perform an imap search request
183
     *
184
     * @return Collection
185
     * @throws GetMessagesFailedException
186
     */
187
    protected function search() {
188
        $this->generate_query();
189
190
        try {
191
            $available_messages = $this->client->getConnection()->search([$this->getRawQuery()], $this->sequence);
192
            return $available_messages !== false ? new Collection($available_messages) : new Collection();
0 ignored issues
show
introduced by
The condition $available_messages !== false is always true.
Loading history...
193
        } catch (RuntimeException $e) {
194
            throw new GetMessagesFailedException("failed to fetch messages", 0, $e);
195
        } catch (ConnectionFailedException $e) {
196
            throw new GetMessagesFailedException("failed to fetch messages", 0, $e);
197
        }
198
    }
199
200
    /**
201
     * Count all available messages matching the current search criteria
202
     *
203
     * @return int
204
     * @throws GetMessagesFailedException
205
     */
206
    public function count() {
207
        return $this->search()->count();
208
    }
209
210
    /**
211
     * Fetch a given id collection
212
     * @param Collection $available_messages
213
     *
214
     * @return array
215
     * @throws ConnectionFailedException
216
     * @throws RuntimeException
217
     */
218
    protected function fetch($available_messages) {
219
        if ($this->fetch_order === 'desc') {
220
            $available_messages = $available_messages->reverse();
221
        }
222
223
        $uids = $available_messages->forPage($this->page, $this->limit)->toArray();
224
        $extensions = [];
225
        if (empty($this->getExtensions()) === false) {
226
            $extensions = $this->client->getConnection()->fetch($this->getExtensions(), $uids, null, $this->sequence);
0 ignored issues
show
Bug introduced by
The method fetch() does not exist on Webklex\PHPIMAP\Connecti...ocols\ProtocolInterface. It seems like you code against a sub-type of Webklex\PHPIMAP\Connecti...ocols\ProtocolInterface such as Webklex\PHPIMAP\Connection\Protocols\ImapProtocol. ( Ignorable by Annotation )

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

226
            $extensions = $this->client->getConnection()->/** @scrutinizer ignore-call */ fetch($this->getExtensions(), $uids, null, $this->sequence);
Loading history...
Bug introduced by
The method fetch() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. It seems like you code against a sub-type of Webklex\PHPIMAP\Connection\Protocols\Protocol such as Webklex\PHPIMAP\Connection\Protocols\ImapProtocol. ( Ignorable by Annotation )

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

226
            $extensions = $this->client->getConnection()->/** @scrutinizer ignore-call */ fetch($this->getExtensions(), $uids, null, $this->sequence);
Loading history...
227
        }
228
        $flags = $this->client->getConnection()->flags($uids, $this->sequence);
229
        $headers = $this->client->getConnection()->headers($uids, "RFC822", $this->sequence);
230
231
        $contents = [];
232
        if ($this->getFetchBody()) {
233
            $contents = $this->client->getConnection()->content($uids, "RFC822", $this->sequence);
234
        }
235
236
        return [
237
            "uids"       => $uids,
238
            "flags"      => $flags,
239
            "headers"    => $headers,
240
            "contents"   => $contents,
241
            "extensions" => $extensions,
242
        ];
243
    }
244
245
    /**
246
     * Make a new message from given raw components
247
     * @param integer $uid
248
     * @param integer $msglist
249
     * @param string $header
250
     * @param string $content
251
     * @param array $flags
252
     *
253
     * @return Message|null
254
     * @throws ConnectionFailedException
255
     * @throws EventNotFoundException
256
     * @throws GetMessagesFailedException
257
     * @throws ReflectionException
258
     */
259
    protected function make($uid, $msglist, $header, $content, $flags) {
260
        try {
261
            return Message::make($uid, $msglist, $this->getClient(), $header, $content, $flags, $this->getFetchOptions(), $this->sequence);
262
        } catch (MessageNotFoundException $e) {
263
            $this->setError($uid, $e);
264
        } catch (RuntimeException $e) {
265
            $this->setError($uid, $e);
266
        } catch (MessageFlagException $e) {
267
            $this->setError($uid, $e);
268
        } catch (InvalidMessageDateException $e) {
269
            $this->setError($uid, $e);
270
        } catch (MessageContentFetchingException $e) {
271
            $this->setError($uid, $e);
272
        }
273
274
        $this->handleException($uid);
275
276
        return null;
277
    }
278
279
    /**
280
     * Get the message key for a given message
281
     * @param string $message_key
282
     * @param integer $msglist
283
     * @param Message $message
284
     *
285
     * @return string
286
     */
287
    protected function getMessageKey($message_key, $msglist, $message) {
288
        switch ($message_key) {
289
            case 'number':
290
                $key = $message->getMessageNo();
291
                break;
292
            case 'list':
293
                $key = $msglist;
294
                break;
295
            case 'uid':
296
                $key = $message->getUid();
297
                break;
298
            default:
299
                $key = $message->getMessageId();
300
                break;
301
        }
302
        return (string)$key;
303
    }
304
305
    /**
306
     * Currates a given collection aof messages
307
     * @param Collection $available_messages
308
     *
309
     * @return MessageCollection
310
     * @throws GetMessagesFailedException
311
     */
312
    public function curate_messages($available_messages) {
313
        try {
314
            if ($available_messages->count() > 0) {
315
                return $this->populate($available_messages);
316
            }
317
            return MessageCollection::make([]);
318
        } catch (Exception $e) {
319
            throw new GetMessagesFailedException($e->getMessage(), 0, $e);
320
        }
321
    }
322
323
    /**
324
     * Populate a given id collection and receive a fully fetched message collection
325
     * @param Collection $available_messages
326
     *
327
     * @return MessageCollection
328
     * @throws ConnectionFailedException
329
     * @throws EventNotFoundException
330
     * @throws GetMessagesFailedException
331
     * @throws ReflectionException
332
     * @throws RuntimeException
333
     */
334
    protected function populate($available_messages) {
335
        $messages = MessageCollection::make([]);
336
337
        $messages->total($available_messages->count());
338
339
        $message_key = ClientManager::get('options.message_key');
340
341
        $raw_messages = $this->fetch($available_messages);
342
343
        $msglist = 0;
344
        foreach ($raw_messages["headers"] as $uid => $header) {
345
            $content = isset($raw_messages["contents"][$uid]) ? $raw_messages["contents"][$uid] : "";
346
            $flag = isset($raw_messages["flags"][$uid]) ? $raw_messages["flags"][$uid] : [];
347
            $extensions = isset($raw_messages["extensions"][$uid]) ? $raw_messages["extensions"][$uid] : [];
348
349
            $message = $this->make($uid, $msglist, $header, $content, $flag);
350
            foreach($extensions as $key => $extension) {
351
                $message->getHeader()->set($key, $extension);
352
            }
353
            if ($message !== null) {
354
                $key = $this->getMessageKey($message_key, $msglist, $message);
355
                $messages->put("$key", $message);
356
            }
357
            $msglist++;
358
        }
359
360
        return $messages;
361
    }
362
363
    /**
364
     * Fetch the current query and return all found messages
365
     *
366
     * @return MessageCollection
367
     * @throws GetMessagesFailedException
368
     */
369
    public function get() {
370
        return $this->curate_messages($this->search());
371
    }
372
373
    /**
374
     * Fetch the current query as chunked requests
375
     * @param callable $callback
376
     * @param int $chunk_size
377
     * @param int $start_chunk
378
     *
379
     * @throws ConnectionFailedException
380
     * @throws EventNotFoundException
381
     * @throws GetMessagesFailedException
382
     * @throws ReflectionException
383
     * @throws RuntimeException
384
     */
385
    public function chunked($callback, $chunk_size = 10, $start_chunk = 1) {
386
        $available_messages = $this->search();
387
        if (($available_messages_count = $available_messages->count()) > 0) {
388
            $old_limit = $this->limit;
389
            $old_page = $this->page;
390
391
            $this->limit = $chunk_size;
392
            $this->page = $start_chunk;
393
            $handled_messages_count = 0;
394
            do {
395
                $messages = $this->populate($available_messages);
396
                $handled_messages_count += $messages->count();
397
                $callback($messages, $this->page);
398
                $this->page++;
399
            } while ($handled_messages_count < $available_messages_count);
400
            $this->limit = $old_limit;
401
            $this->page = $old_page;
402
        }
403
    }
404
405
    /**
406
     * Paginate the current query
407
     * @param int $per_page Results you which to receive per page
408
     * @param int|null $page The current page you are on (e.g. 0, 1, 2, ...) use `null` to enable auto mode
409
     * @param string $page_name The page name / uri parameter used for the generated links and the auto mode
410
     *
411
     * @return LengthAwarePaginator
412
     * @throws GetMessagesFailedException
413
     */
414
    public function paginate($per_page = 5, $page = null, $page_name = 'imap_page') {
415
        if (
416
            $page === null
417
            && isset($_GET[$page_name])
418
            && $_GET[$page_name] > 0
419
        ) {
420
            $this->page = intval($_GET[$page_name]);
421
        } elseif ($page > 0) {
422
            $this->page = $page;
423
        }
424
425
        $this->limit = $per_page;
426
427
        return $this->get()->paginate($per_page, $this->page, $page_name, true);
428
    }
429
430
    /**
431
     * Get a new Message instance
432
     * @param int $uid
433
     * @param int|null $msglist
434
     * @param int|string|null $sequence
435
     *
436
     * @return Message
437
     * @throws ConnectionFailedException
438
     * @throws RuntimeException
439
     * @throws InvalidMessageDateException
440
     * @throws MessageContentFetchingException
441
     * @throws MessageHeaderFetchingException
442
     * @throws EventNotFoundException
443
     * @throws MessageFlagException
444
     * @throws MessageNotFoundException
445
     */
446
    public function getMessage($uid, $msglist = null, $sequence = null) {
447
        return new Message($uid, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchFlags(), $sequence ? $sequence : $this->sequence);
0 ignored issues
show
Bug introduced by
It seems like $sequence ? $sequence : $this->sequence can also be of type string; however, parameter $sequence of Webklex\PHPIMAP\Message::__construct() does only seem to accept integer, 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

447
        return new Message($uid, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchFlags(), /** @scrutinizer ignore-type */ $sequence ? $sequence : $this->sequence);
Loading history...
Bug introduced by
$this->getFetchFlags() of type integer is incompatible with the type boolean expected by parameter $fetch_flags of Webklex\PHPIMAP\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

447
        return new Message($uid, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), /** @scrutinizer ignore-type */ $this->getFetchFlags(), $sequence ? $sequence : $this->sequence);
Loading history...
448
    }
449
450
    /**
451
     * Get a message by its message number
452
     * @param $msgn
453
     * @param int|null $msglist
454
     *
455
     * @return Message
456
     * @throws ConnectionFailedException
457
     * @throws InvalidMessageDateException
458
     * @throws MessageContentFetchingException
459
     * @throws MessageHeaderFetchingException
460
     * @throws RuntimeException
461
     * @throws EventNotFoundException
462
     * @throws MessageFlagException
463
     * @throws MessageNotFoundException
464
     */
465
    public function getMessageByMsgn($msgn, $msglist = null) {
466
        return $this->getMessage($msgn, $msglist, IMAP::ST_MSGN);
467
    }
468
469
    /**
470
     * Get a message by its uid
471
     * @param $uid
472
     *
473
     * @return Message
474
     * @throws ConnectionFailedException
475
     * @throws InvalidMessageDateException
476
     * @throws MessageContentFetchingException
477
     * @throws MessageHeaderFetchingException
478
     * @throws RuntimeException
479
     * @throws EventNotFoundException
480
     * @throws MessageFlagException
481
     * @throws MessageNotFoundException
482
     */
483
    public function getMessageByUid($uid) {
484
        return $this->getMessage($uid, null, IMAP::ST_UID);
485
    }
486
487
    /**
488
     * Filter all available uids by a given closure and get a curated list of messages
489
     * @param callable $closure
490
     *
491
     * @return MessageCollection
492
     * @throws ConnectionFailedException
493
     * @throws GetMessagesFailedException
494
     * @throws MessageNotFoundException
495
     */
496
    public function filter($closure) {
497
        $connection = $this->getClient()->getConnection();
498
499
        $uids = $connection->getUid();
500
        $available_messages = new Collection();
501
        if (is_array($uids)) {
502
            foreach ($uids as $id){
503
                if ($closure($id)) {
504
                    $available_messages->push($id);
505
                }
506
            }
507
        }
508
509
        return $this->curate_messages($available_messages);
510
    }
511
512
    /**
513
     * Get all messages with an uid greater or equal to a given UID
514
     * @param int $uid
515
     *
516
     * @return MessageCollection
517
     * @throws ConnectionFailedException
518
     * @throws GetMessagesFailedException
519
     * @throws MessageNotFoundException
520
     */
521
    public function getByUidGreaterOrEqual($uid) {
522
        return $this->filter(function($id) use($uid){
523
            return $id >= $uid;
524
        });
525
    }
526
527
    /**
528
     * Get all messages with an uid greater than a given UID
529
     * @param int $uid
530
     *
531
     * @return MessageCollection
532
     * @throws ConnectionFailedException
533
     * @throws GetMessagesFailedException
534
     * @throws MessageNotFoundException
535
     */
536
    public function getByUidGreater($uid) {
537
        return $this->filter(function($id) use($uid){
538
            return $id > $uid;
539
        });
540
    }
541
542
    /**
543
     * Get all messages with an uid lower than a given UID
544
     * @param int $uid
545
     *
546
     * @return MessageCollection
547
     * @throws ConnectionFailedException
548
     * @throws GetMessagesFailedException
549
     * @throws MessageNotFoundException
550
     */
551
    public function getByUidLower($uid) {
552
        return $this->filter(function($id) use($uid){
553
            return $id < $uid;
554
        });
555
    }
556
557
    /**
558
     * Get all messages with an uid lower or equal to a given UID
559
     * @param int $uid
560
     *
561
     * @return MessageCollection
562
     * @throws ConnectionFailedException
563
     * @throws GetMessagesFailedException
564
     * @throws MessageNotFoundException
565
     */
566
    public function getByUidLowerOrEqual($uid) {
567
        return $this->filter(function($id) use($uid){
568
            return $id <= $uid;
569
        });
570
    }
571
572
    /**
573
     * Get all messages with an uid greater than a given UID
574
     * @param int $uid
575
     *
576
     * @return MessageCollection
577
     * @throws ConnectionFailedException
578
     * @throws GetMessagesFailedException
579
     * @throws MessageNotFoundException
580
     */
581
    public function getByUidLowerThan($uid) {
582
        return $this->filter(function($id) use($uid){
583
            return $id < $uid;
584
        });
585
    }
586
587
    /**
588
     * Don't mark messages as read when fetching
589
     *
590
     * @return $this
591
     */
592
    public function leaveUnread() {
593
        $this->setFetchOptions(IMAP::FT_PEEK);
0 ignored issues
show
Bug introduced by
Webklex\PHPIMAP\IMAP::FT_PEEK of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\PHPIMAP\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

593
        $this->setFetchOptions(/** @scrutinizer ignore-type */ IMAP::FT_PEEK);
Loading history...
594
595
        return $this;
596
    }
597
598
    /**
599
     * Mark all messages as read when fetching
600
     *
601
     * @return $this
602
     */
603
    public function markAsRead() {
604
        $this->setFetchOptions(IMAP::FT_UID);
0 ignored issues
show
Bug introduced by
Webklex\PHPIMAP\IMAP::FT_UID of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\PHPIMAP\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

604
        $this->setFetchOptions(/** @scrutinizer ignore-type */ IMAP::FT_UID);
Loading history...
605
606
        return $this;
607
    }
608
609
    /**
610
     * Set the sequence type
611
     * @param int $sequence
612
     *
613
     * @return $this
614
     */
615
    public function setSequence($sequence) {
616
        $this->sequence = $sequence;
617
618
        return $this;
619
    }
620
621
    /**
622
     * Get the sequence type
623
     *
624
     * @return int|string
625
     */
626
    public function getSequence() {
627
        return $this->sequence;
628
    }
629
630
    /**
631
     * @return Client
632
     * @throws ConnectionFailedException
633
     */
634
    public function getClient() {
635
        $this->client->checkConnection();
636
        return $this->client;
637
    }
638
639
    /**
640
     * Set the limit and page for the current query
641
     * @param int $limit
642
     * @param int $page
643
     *
644
     * @return $this
645
     */
646
    public function limit($limit, $page = 1) {
647
        if ($page >= 1) $this->page = $page;
648
        $this->limit = $limit;
649
650
        return $this;
651
    }
652
653
    /**
654
     * @return Collection
655
     */
656
    public function getQuery() {
657
        return $this->query;
658
    }
659
660
    /**
661
     * @param array $query
662
     * @return Query
663
     */
664
    public function setQuery($query) {
665
        $this->query = new Collection($query);
666
        return $this;
667
    }
668
669
    /**
670
     * @return string
671
     */
672
    public function getRawQuery() {
673
        return $this->raw_query;
674
    }
675
676
    /**
677
     * @param string $raw_query
678
     * @return Query
679
     */
680
    public function setRawQuery($raw_query) {
681
        $this->raw_query = $raw_query;
682
        return $this;
683
    }
684
685
    /**
686
     * @return string[]
687
     */
688
    public function getExtensions() {
689
        return $this->extensions;
690
    }
691
692
    /**
693
     * @param string[] $extensions
694
     * @return Query
695
     */
696
    public function setExtensions($extensions) {
697
        $this->extensions = $extensions;
698
        if (count($this->extensions) > 0) {
699
            if (in_array("UID", $this->extensions) === false) {
700
                $this->extensions[] = "UID";
701
            }
702
        }
703
        return $this;
704
    }
705
706
    /**
707
     * @param Client $client
708
     * @return Query
709
     */
710
    public function setClient(Client $client) {
711
        $this->client = $client;
712
        return $this;
713
    }
714
715
    /**
716
     * @return int
717
     */
718
    public function getLimit() {
719
        return $this->limit;
720
    }
721
722
    /**
723
     * @param int $limit
724
     * @return Query
725
     */
726
    public function setLimit($limit) {
727
        $this->limit = $limit <= 0 ? null : $limit;
728
        return $this;
729
    }
730
731
    /**
732
     * @return int
733
     */
734
    public function getPage() {
735
        return $this->page;
736
    }
737
738
    /**
739
     * @param int $page
740
     * @return Query
741
     */
742
    public function setPage($page) {
743
        $this->page = $page;
744
        return $this;
745
    }
746
747
    /**
748
     * @param boolean $fetch_options
749
     * @return Query
750
     */
751
    public function setFetchOptions($fetch_options) {
752
        $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...
753
        return $this;
754
    }
755
756
    /**
757
     * @param boolean $fetch_options
758
     * @return Query
759
     */
760
    public function fetchOptions($fetch_options) {
761
        return $this->setFetchOptions($fetch_options);
762
    }
763
764
    /**
765
     * @return int
766
     */
767
    public function getFetchOptions() {
768
        return $this->fetch_options;
769
    }
770
771
    /**
772
     * @return boolean
773
     */
774
    public function getFetchBody() {
775
        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...
776
    }
777
778
    /**
779
     * @param boolean $fetch_body
780
     * @return Query
781
     */
782
    public function setFetchBody($fetch_body) {
783
        $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...
784
        return $this;
785
    }
786
787
    /**
788
     * @param boolean $fetch_body
789
     * @return Query
790
     */
791
    public function fetchBody($fetch_body) {
792
        return $this->setFetchBody($fetch_body);
793
    }
794
795
    /**
796
     * @return int
797
     */
798
    public function getFetchFlags() {
799
        return $this->fetch_flags;
800
    }
801
802
    /**
803
     * @param int $fetch_flags
804
     * @return Query
805
     */
806
    public function setFetchFlags($fetch_flags) {
807
        $this->fetch_flags = $fetch_flags;
808
        return $this;
809
    }
810
811
    /**
812
     * @param string $fetch_order
813
     * @return Query
814
     */
815
    public function setFetchOrder($fetch_order) {
816
        $fetch_order = strtolower($fetch_order);
817
818
        if (in_array($fetch_order, ['asc', 'desc'])) {
819
            $this->fetch_order = $fetch_order;
820
        }
821
822
        return $this;
823
    }
824
825
    /**
826
     * @param string $fetch_order
827
     * @return Query
828
     */
829
    public function fetchOrder($fetch_order) {
830
        return $this->setFetchOrder($fetch_order);
831
    }
832
833
    /**
834
     * @return string
835
     */
836
    public function getFetchOrder() {
837
        return $this->fetch_order;
838
    }
839
840
    /**
841
     * @return Query
842
     */
843
    public function setFetchOrderAsc() {
844
        return $this->setFetchOrder('asc');
845
    }
846
847
    /**
848
     * @return Query
849
     */
850
    public function fetchOrderAsc() {
851
        return $this->setFetchOrderAsc();
852
    }
853
854
    /**
855
     * @return Query
856
     */
857
    public function setFetchOrderDesc() {
858
        return $this->setFetchOrder('desc');
859
    }
860
861
    /**
862
     * @return Query
863
     */
864
    public function fetchOrderDesc() {
865
        return $this->setFetchOrderDesc();
866
    }
867
868
    /**
869
     * @return Query
870
     * @var boolean $state
871
     *
872
     */
873
    public function softFail($state = true) {
874
        return $this->setSoftFail($state);
875
    }
876
877
    /**
878
     * @return Query
879
     * @var boolean $state
880
     *
881
     */
882
    public function setSoftFail($state = true) {
883
        $this->soft_fail = $state;
884
885
        return $this;
886
    }
887
888
    /**
889
     * @return boolean
890
     */
891
    public function getSoftFail() {
892
        return $this->soft_fail;
893
    }
894
895
    /**
896
     * Handle the exception for a given uid
897
     * @param integer $uid
898
     *
899
     * @throws GetMessagesFailedException
900
     */
901
    protected function handleException($uid) {
902
        if ($this->soft_fail === false && $this->hasError($uid)) {
903
            $error = $this->getError($uid);
904
            throw new GetMessagesFailedException($error->getMessage(), 0, $error);
905
        }
906
    }
907
908
    /**
909
     * Add a new error to the error holder
910
     * @param integer $uid
911
     * @param Exception $error
912
     */
913
    protected function setError($uid, $error) {
914
        $this->errors[$uid] = $error;
915
    }
916
917
    /**
918
     * Check if there are any errors / exceptions present
919
     * @return boolean
920
     * @var integer|null $uid
921
     *
922
     */
923
    public function hasErrors($uid = null) {
924
        if ($uid !== null) {
925
            return $this->hasError($uid);
926
        }
927
        return count($this->errors) > 0;
928
    }
929
930
    /**
931
     * Check if there is an error / exception present
932
     * @return boolean
933
     * @var integer $uid
934
     *
935
     */
936
    public function hasError($uid) {
937
        return isset($this->errors[$uid]);
938
    }
939
940
    /**
941
     * Get all available errors / exceptions
942
     *
943
     * @return array
944
     */
945
    public function errors() {
946
        return $this->getErrors();
947
    }
948
949
    /**
950
     * Get all available errors / exceptions
951
     *
952
     * @return array
953
     */
954
    public function getErrors() {
955
        return $this->errors;
956
    }
957
958
    /**
959
     * Get a specific error / exception
960
     * @return Exception|null
961
     * @var integer $uid
962
     *
963
     */
964
    public function error($uid) {
965
        return $this->getError($uid);
966
    }
967
968
    /**
969
     * Get a specific error / exception
970
     * @return Exception|null
971
     * @var integer $uid
972
     *
973
     */
974
    public function getError($uid) {
975
        if ($this->hasError($uid)) {
976
            return $this->errors[$uid];
977
        }
978
        return null;
979
    }
980
}
981