Query   F
last analyzed

Complexity

Total Complexity 113

Size/Duplication

Total Lines 937
Duplicated Lines 0 %

Importance

Changes 24
Bugs 2 Features 9
Metric Value
wmc 113
eloc 245
c 24
b 2
f 9
dl 0
loc 937
rs 2

67 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 3
A boot() 0 1 1
A fetchOrderAsc() 0 2 1
A get() 0 2 1
A getSoftFail() 0 2 1
A getByUidLower() 0 3 1
A setClient() 0 3 1
A hasError() 0 2 1
A chunked() 0 17 3
A getLimit() 0 2 1
A parse_date() 0 10 3
A hasErrors() 0 5 2
A populate() 0 27 4
A setFetchFlags() 0 3 1
A setFetchBody() 0 3 1
A getFetchFlags() 0 2 1
A search() 0 10 3
A getByUidLowerThan() 0 3 1
A getFetchOptions() 0 2 1
A getPage() 0 2 1
A setFetchOrder() 0 8 2
A setQuery() 0 3 1
A paginate() 0 14 5
A count() 0 2 1
A setRawQuery() 0 3 1
A getClient() 0 3 1
A getMessage() 0 2 2
A setPage() 0 3 1
A fetchOptions() 0 2 1
A filter() 0 14 4
A getByUidGreater() 0 3 1
A getExtensions() 0 2 1
A parse_value() 0 6 2
A setFetchOrderAsc() 0 2 1
A getMessageKey() 0 16 4
A limit() 0 5 2
A getFetchBody() 0 2 1
A fetch() 0 24 5
A errors() 0 2 1
A getByUidGreaterOrEqual() 0 3 1
A markAsRead() 0 4 1
A leaveUnread() 0 4 1
A getByUidLowerOrEqual() 0 3 1
A fetchOrder() 0 2 1
A softFail() 0 2 1
A setFetchOrderDesc() 0 2 1
A getRawQuery() 0 2 1
A setLimit() 0 3 2
A setSequence() 0 4 1
A setError() 0 2 1
A fetchOrderDesc() 0 2 1
A getSequence() 0 2 1
A setFetchOptions() 0 3 1
A fetchBody() 0 2 1
A getError() 0 5 2
A getErrors() 0 2 1
A getQuery() 0 2 1
A make() 0 18 6
A getMessageByMsgn() 0 2 1
A setExtensions() 0 8 3
A handleException() 0 4 3
A generate_query() 0 23 4
A getFetchOrder() 0 2 1
A getMessageByUid() 0 2 1
A curate_messages() 0 8 3
A setSoftFail() 0 4 1
A error() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like Query often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Query, and based on these observations, apply Extract Interface, too.

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, array $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): string {
123
        if ($value instanceof Carbon) {
124
            $value = $value->format($this->date_format);
125
        }
126
127
        return (string)$value;
128
    }
129
130
    /**
131
     * Check if a given date is a valid carbon object and if not try to convert it
132
     * @param string|Carbon $date
133
     *
134
     * @return Carbon
135
     * @throws MessageSearchValidationException
136
     */
137
    protected function parse_date($date): Carbon {
138
        if ($date instanceof Carbon) return $date;
139
140
        try {
141
            $date = Carbon::parse($date);
142
        } catch (Exception $e) {
143
            throw new MessageSearchValidationException();
144
        }
145
146
        return $date;
147
    }
148
149
    /**
150
     * Get the raw IMAP search query
151
     *
152
     * @return string
153
     */
154
    public function generate_query(): string {
155
        $query = '';
156
        $this->query->each(function($statement) use (&$query) {
157
            if (count($statement) == 1) {
158
                $query .= $statement[0];
159
            } else {
160
                if ($statement[1] === null) {
161
                    $query .= $statement[0];
162
                } else {
163
                    if (is_numeric($statement[1])) {
164
                        $query .= $statement[0] . ' ' . $statement[1];
165
                    } else {
166
                        $query .= $statement[0] . ' "' . $statement[1] . '"';
167
                    }
168
                }
169
            }
170
            $query .= ' ';
171
172
        });
173
174
        $this->raw_query = trim($query);
175
176
        return $this->raw_query;
177
    }
178
179
    /**
180
     * Perform an imap search request
181
     *
182
     * @return Collection
183
     * @throws GetMessagesFailedException
184
     */
185
    protected function search(): Collection {
186
        $this->generate_query();
187
188
        try {
189
            $available_messages = $this->client->getConnection()->search([$this->getRawQuery()], $this->sequence);
190
            return new Collection($available_messages);
191
        } catch (RuntimeException $e) {
192
            throw new GetMessagesFailedException("failed to fetch messages", 0, $e);
193
        } catch (ConnectionFailedException $e) {
194
            throw new GetMessagesFailedException("failed to fetch messages", 0, $e);
195
        }
196
    }
197
198
    /**
199
     * Count all available messages matching the current search criteria
200
     *
201
     * @return int
202
     * @throws GetMessagesFailedException
203
     */
204
    public function count(): int {
205
        return $this->search()->count();
206
    }
207
208
    /**
209
     * Fetch a given id collection
210
     * @param Collection $available_messages
211
     *
212
     * @return array
213
     * @throws ConnectionFailedException
214
     * @throws RuntimeException
215
     */
216
    protected function fetch(Collection $available_messages): array {
217
        if ($this->fetch_order === 'desc') {
218
            $available_messages = $available_messages->reverse();
219
        }
220
221
        $uids = $available_messages->forPage($this->page, $this->limit)->toArray();
222
        $extensions = $this->getExtensions();
223
        if (empty($extensions) === false && method_exists($this->client->getConnection(), "fetch")) {
224
            $extensions = $this->client->getConnection()->fetch($extensions, $uids, null, $this->sequence);
225
        }
226
        $flags = $this->client->getConnection()->flags($uids, $this->sequence);
227
        $headers = $this->client->getConnection()->headers($uids, "RFC822", $this->sequence);
228
229
        $contents = [];
230
        if ($this->getFetchBody()) {
231
            $contents = $this->client->getConnection()->content($uids, "RFC822", $this->sequence);
232
        }
233
234
        return [
235
            "uids"       => $uids,
236
            "flags"      => $flags,
237
            "headers"    => $headers,
238
            "contents"   => $contents,
239
            "extensions" => $extensions,
240
        ];
241
    }
242
243
    /**
244
     * Make a new message from given raw components
245
     * @param integer $uid
246
     * @param integer $msglist
247
     * @param string $header
248
     * @param string $content
249
     * @param array $flags
250
     *
251
     * @return Message|null
252
     * @throws ConnectionFailedException
253
     * @throws EventNotFoundException
254
     * @throws GetMessagesFailedException
255
     * @throws ReflectionException
256
     */
257
    protected function make(int $uid, int $msglist, string $header, string $content, array $flags) {
258
        try {
259
            return Message::make($uid, $msglist, $this->getClient(), $header, $content, $flags, $this->getFetchOptions(), $this->sequence);
260
        } catch (MessageNotFoundException $e) {
261
            $this->setError($uid, $e);
262
        } catch (RuntimeException $e) {
263
            $this->setError($uid, $e);
264
        } catch (MessageFlagException $e) {
265
            $this->setError($uid, $e);
266
        } catch (InvalidMessageDateException $e) {
267
            $this->setError($uid, $e);
268
        } catch (MessageContentFetchingException $e) {
269
            $this->setError($uid, $e);
270
        }
271
272
        $this->handleException($uid);
273
274
        return null;
275
    }
276
277
    /**
278
     * Get the message key for a given message
279
     * @param string $message_key
280
     * @param integer $msglist
281
     * @param Message $message
282
     *
283
     * @return string
284
     */
285
    protected function getMessageKey(string $message_key, int $msglist, Message $message): string {
286
        switch ($message_key) {
287
            case 'number':
288
                $key = $message->getMessageNo();
289
                break;
290
            case 'list':
291
                $key = $msglist;
292
                break;
293
            case 'uid':
294
                $key = $message->getUid();
295
                break;
296
            default:
297
                $key = $message->getMessageId();
298
                break;
299
        }
300
        return (string)$key;
301
    }
302
303
    /**
304
     * Curates a given collection aof messages
305
     * @param Collection $available_messages
306
     *
307
     * @return MessageCollection
308
     * @throws GetMessagesFailedException
309
     */
310
    public function curate_messages(Collection $available_messages): MessageCollection {
311
        try {
312
            if ($available_messages->count() > 0) {
313
                return $this->populate($available_messages);
314
            }
315
            return MessageCollection::make([]);
316
        } catch (Exception $e) {
317
            throw new GetMessagesFailedException($e->getMessage(), 0, $e);
318
        }
319
    }
320
321
    /**
322
     * Populate a given id collection and receive a fully fetched message collection
323
     * @param Collection $available_messages
324
     *
325
     * @return MessageCollection
326
     * @throws ConnectionFailedException
327
     * @throws EventNotFoundException
328
     * @throws GetMessagesFailedException
329
     * @throws ReflectionException
330
     * @throws RuntimeException
331
     */
332
    protected function populate(Collection $available_messages): MessageCollection {
333
        $messages = MessageCollection::make([]);
334
335
        $messages->total($available_messages->count());
336
337
        $message_key = ClientManager::get('options.message_key');
338
339
        $raw_messages = $this->fetch($available_messages);
340
341
        $msglist = 0;
342
        foreach ($raw_messages["headers"] as $uid => $header) {
343
            $content = $raw_messages["contents"][$uid] ?? "";
344
            $flag = $raw_messages["flags"][$uid] ?? [];
345
            $extensions = $raw_messages["extensions"][$uid] ?? [];
346
347
            $message = $this->make($uid, $msglist, $header, $content, $flag);
348
            foreach($extensions as $key => $extension) {
349
                $message->getHeader()->set($key, $extension);
350
            }
351
            if ($message !== null) {
352
                $key = $this->getMessageKey($message_key, $msglist, $message);
0 ignored issues
show
Bug introduced by
It seems like $message_key can also be of type null; however, parameter $message_key of Webklex\PHPIMAP\Query\Query::getMessageKey() does only seem to accept string, 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

352
                $key = $this->getMessageKey(/** @scrutinizer ignore-type */ $message_key, $msglist, $message);
Loading history...
353
                $messages->put("$key", $message);
354
            }
355
            $msglist++;
356
        }
357
358
        return $messages;
359
    }
360
361
    /**
362
     * Fetch the current query and return all found messages
363
     *
364
     * @return MessageCollection
365
     * @throws GetMessagesFailedException
366
     */
367
    public function get(): MessageCollection {
368
        return $this->curate_messages($this->search());
369
    }
370
371
    /**
372
     * Fetch the current query as chunked requests
373
     * @param callable $callback
374
     * @param int $chunk_size
375
     * @param int $start_chunk
376
     *
377
     * @throws ConnectionFailedException
378
     * @throws EventNotFoundException
379
     * @throws GetMessagesFailedException
380
     * @throws ReflectionException
381
     * @throws RuntimeException
382
     */
383
    public function chunked(callable $callback, int $chunk_size = 10, int $start_chunk = 1) {
384
        $available_messages = $this->search();
385
        if (($available_messages_count = $available_messages->count()) > 0) {
386
            $old_limit = $this->limit;
387
            $old_page = $this->page;
388
389
            $this->limit = $chunk_size;
390
            $this->page = $start_chunk;
391
            $handled_messages_count = 0;
392
            do {
393
                $messages = $this->populate($available_messages);
394
                $handled_messages_count += $messages->count();
395
                $callback($messages, $this->page);
396
                $this->page++;
397
            } while ($handled_messages_count < $available_messages_count);
398
            $this->limit = $old_limit;
399
            $this->page = $old_page;
400
        }
401
    }
402
403
    /**
404
     * Paginate the current query
405
     * @param int $per_page Results you which to receive per page
406
     * @param int|null $page The current page you are on (e.g. 0, 1, 2, ...) use `null` to enable auto mode
407
     * @param string $page_name The page name / uri parameter used for the generated links and the auto mode
408
     *
409
     * @return LengthAwarePaginator
410
     * @throws GetMessagesFailedException
411
     */
412
    public function paginate(int $per_page = 5, $page = null, string $page_name = 'imap_page'): LengthAwarePaginator {
413
        if (
414
            $page === null
415
            && isset($_GET[$page_name])
416
            && $_GET[$page_name] > 0
417
        ) {
418
            $this->page = intval($_GET[$page_name]);
419
        } elseif ($page > 0) {
420
            $this->page = $page;
421
        }
422
423
        $this->limit = $per_page;
424
425
        return $this->get()->paginate($per_page, $this->page, $page_name, true);
426
    }
427
428
    /**
429
     * Get a new Message instance
430
     * @param int $uid
431
     * @param int|null $msglist
432
     * @param int|string|null $sequence
433
     *
434
     * @return Message
435
     * @throws ConnectionFailedException
436
     * @throws RuntimeException
437
     * @throws InvalidMessageDateException
438
     * @throws MessageContentFetchingException
439
     * @throws MessageHeaderFetchingException
440
     * @throws EventNotFoundException
441
     * @throws MessageFlagException
442
     * @throws MessageNotFoundException
443
     */
444
    public function getMessage(int $uid, $msglist = null, $sequence = null): Message {
445
        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|null, 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

445
        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

445
        return new Message($uid, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), /** @scrutinizer ignore-type */ $this->getFetchFlags(), $sequence ? $sequence : $this->sequence);
Loading history...
446
    }
447
448
    /**
449
     * Get a message by its message number
450
     * @param $msgn
451
     * @param int|null $msglist
452
     *
453
     * @return Message
454
     * @throws ConnectionFailedException
455
     * @throws InvalidMessageDateException
456
     * @throws MessageContentFetchingException
457
     * @throws MessageHeaderFetchingException
458
     * @throws RuntimeException
459
     * @throws EventNotFoundException
460
     * @throws MessageFlagException
461
     * @throws MessageNotFoundException
462
     */
463
    public function getMessageByMsgn($msgn, $msglist = null): Message {
464
        return $this->getMessage($msgn, $msglist, IMAP::ST_MSGN);
465
    }
466
467
    /**
468
     * Get a message by its uid
469
     * @param $uid
470
     *
471
     * @return Message
472
     * @throws ConnectionFailedException
473
     * @throws InvalidMessageDateException
474
     * @throws MessageContentFetchingException
475
     * @throws MessageHeaderFetchingException
476
     * @throws RuntimeException
477
     * @throws EventNotFoundException
478
     * @throws MessageFlagException
479
     * @throws MessageNotFoundException
480
     */
481
    public function getMessageByUid($uid): Message {
482
        return $this->getMessage($uid, null, IMAP::ST_UID);
483
    }
484
485
    /**
486
     * Filter all available uids by a given closure and get a curated list of messages
487
     * @param callable $closure
488
     *
489
     * @return MessageCollection
490
     * @throws ConnectionFailedException
491
     * @throws GetMessagesFailedException
492
     * @throws MessageNotFoundException
493
     */
494
    public function filter(callable $closure): MessageCollection {
495
        $connection = $this->getClient()->getConnection();
496
497
        $uids = $connection->getUid();
498
        $available_messages = new Collection();
499
        if (is_array($uids)) {
500
            foreach ($uids as $id){
501
                if ($closure($id)) {
502
                    $available_messages->push($id);
503
                }
504
            }
505
        }
506
507
        return $this->curate_messages($available_messages);
508
    }
509
510
    /**
511
     * Get all messages with an uid greater or equal to a given UID
512
     * @param int $uid
513
     *
514
     * @return MessageCollection
515
     * @throws ConnectionFailedException
516
     * @throws GetMessagesFailedException
517
     * @throws MessageNotFoundException
518
     */
519
    public function getByUidGreaterOrEqual(int $uid): MessageCollection {
520
        return $this->filter(function($id) use($uid){
521
            return $id >= $uid;
522
        });
523
    }
524
525
    /**
526
     * Get all messages with an uid greater than a given UID
527
     * @param int $uid
528
     *
529
     * @return MessageCollection
530
     * @throws ConnectionFailedException
531
     * @throws GetMessagesFailedException
532
     * @throws MessageNotFoundException
533
     */
534
    public function getByUidGreater(int $uid): MessageCollection {
535
        return $this->filter(function($id) use($uid){
536
            return $id > $uid;
537
        });
538
    }
539
540
    /**
541
     * Get all messages with an uid lower than a given UID
542
     * @param int $uid
543
     *
544
     * @return MessageCollection
545
     * @throws ConnectionFailedException
546
     * @throws GetMessagesFailedException
547
     * @throws MessageNotFoundException
548
     */
549
    public function getByUidLower(int $uid): MessageCollection {
550
        return $this->filter(function($id) use($uid){
551
            return $id < $uid;
552
        });
553
    }
554
555
    /**
556
     * Get all messages with an uid lower or equal to a given UID
557
     * @param int $uid
558
     *
559
     * @return MessageCollection
560
     * @throws ConnectionFailedException
561
     * @throws GetMessagesFailedException
562
     * @throws MessageNotFoundException
563
     */
564
    public function getByUidLowerOrEqual(int $uid): MessageCollection {
565
        return $this->filter(function($id) use($uid){
566
            return $id <= $uid;
567
        });
568
    }
569
570
    /**
571
     * Get all messages with an uid greater than a given UID
572
     * @param int $uid
573
     *
574
     * @return MessageCollection
575
     * @throws ConnectionFailedException
576
     * @throws GetMessagesFailedException
577
     * @throws MessageNotFoundException
578
     */
579
    public function getByUidLowerThan(int $uid): MessageCollection {
580
        return $this->filter(function($id) use($uid){
581
            return $id < $uid;
582
        });
583
    }
584
585
    /**
586
     * Don't mark messages as read when fetching
587
     *
588
     * @return $this
589
     */
590
    public function leaveUnread(): Query {
591
        $this->setFetchOptions(IMAP::FT_PEEK);
592
593
        return $this;
594
    }
595
596
    /**
597
     * Mark all messages as read when fetching
598
     *
599
     * @return $this
600
     */
601
    public function markAsRead(): Query {
602
        $this->setFetchOptions(IMAP::FT_UID);
603
604
        return $this;
605
    }
606
607
    /**
608
     * Set the sequence type
609
     * @param int $sequence
610
     *
611
     * @return $this
612
     */
613
    public function setSequence(int $sequence): Query {
614
        $this->sequence = $sequence;
615
616
        return $this;
617
    }
618
619
    /**
620
     * Get the sequence type
621
     *
622
     * @return int|string
623
     */
624
    public function getSequence() {
625
        return $this->sequence;
626
    }
627
628
    /**
629
     * @return Client
630
     * @throws ConnectionFailedException
631
     */
632
    public function getClient(): Client {
633
        $this->client->checkConnection();
634
        return $this->client;
635
    }
636
637
    /**
638
     * Set the limit and page for the current query
639
     * @param int $limit
640
     * @param int $page
641
     *
642
     * @return $this
643
     */
644
    public function limit(int $limit, int $page = 1): Query {
645
        if ($page >= 1) $this->page = $page;
646
        $this->limit = $limit;
647
648
        return $this;
649
    }
650
651
    /**
652
     * @return Collection
653
     */
654
    public function getQuery(): Collection {
655
        return $this->query;
656
    }
657
658
    /**
659
     * @param array $query
660
     * @return Query
661
     */
662
    public function setQuery(array $query): Query {
663
        $this->query = new Collection($query);
664
        return $this;
665
    }
666
667
    /**
668
     * @return string
669
     */
670
    public function getRawQuery(): string {
671
        return $this->raw_query;
672
    }
673
674
    /**
675
     * @param string $raw_query
676
     * @return Query
677
     */
678
    public function setRawQuery(string $raw_query): Query {
679
        $this->raw_query = $raw_query;
680
        return $this;
681
    }
682
683
    /**
684
     * @return string[]
685
     */
686
    public function getExtensions(): array {
687
        return $this->extensions;
688
    }
689
690
    /**
691
     * @param string[] $extensions
692
     * @return Query
693
     */
694
    public function setExtensions(array $extensions): Query {
695
        $this->extensions = $extensions;
696
        if (count($this->extensions) > 0) {
697
            if (in_array("UID", $this->extensions) === false) {
698
                $this->extensions[] = "UID";
699
            }
700
        }
701
        return $this;
702
    }
703
704
    /**
705
     * @param Client $client
706
     * @return Query
707
     */
708
    public function setClient(Client $client): Query {
709
        $this->client = $client;
710
        return $this;
711
    }
712
713
    /**
714
     * Get the set fetch limit
715
     * @return int
716
     */
717
    public function getLimit() {
718
        return $this->limit;
719
    }
720
721
    /**
722
     * @param int $limit
723
     * @return Query
724
     */
725
    public function setLimit(int $limit): Query {
726
        $this->limit = $limit <= 0 ? null : $limit;
727
        return $this;
728
    }
729
730
    /**
731
     * @return int
732
     */
733
    public function getPage(): int {
734
        return $this->page;
735
    }
736
737
    /**
738
     * @param int $page
739
     * @return Query
740
     */
741
    public function setPage(int $page): Query {
742
        $this->page = $page;
743
        return $this;
744
    }
745
746
    /**
747
     * @param int $fetch_options
748
     * @return Query
749
     */
750
    public function setFetchOptions(int $fetch_options): Query {
751
        $this->fetch_options = $fetch_options;
752
        return $this;
753
    }
754
755
    /**
756
     * @param int $fetch_options
757
     * @return Query
758
     */
759
    public function fetchOptions(int $fetch_options): Query {
760
        return $this->setFetchOptions($fetch_options);
761
    }
762
763
    /**
764
     * @return int
765
     */
766
    public function getFetchOptions() {
767
        return $this->fetch_options;
768
    }
769
770
    /**
771
     * @return boolean
772
     */
773
    public function getFetchBody() {
774
        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...
775
    }
776
777
    /**
778
     * @param boolean $fetch_body
779
     * @return Query
780
     */
781
    public function setFetchBody(bool $fetch_body): Query {
782
        $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...
783
        return $this;
784
    }
785
786
    /**
787
     * @param boolean $fetch_body
788
     * @return Query
789
     */
790
    public function fetchBody(bool $fetch_body): Query {
791
        return $this->setFetchBody($fetch_body);
792
    }
793
794
    /**
795
     * @return int
796
     */
797
    public function getFetchFlags() {
798
        return $this->fetch_flags;
799
    }
800
801
    /**
802
     * @param int $fetch_flags
803
     * @return Query
804
     */
805
    public function setFetchFlags(int $fetch_flags): Query {
806
        $this->fetch_flags = $fetch_flags;
807
        return $this;
808
    }
809
810
    /**
811
     * @param string $fetch_order
812
     * @return Query
813
     */
814
    public function setFetchOrder(string $fetch_order): Query {
815
        $fetch_order = strtolower($fetch_order);
816
817
        if (in_array($fetch_order, ['asc', 'desc'])) {
818
            $this->fetch_order = $fetch_order;
819
        }
820
821
        return $this;
822
    }
823
824
    /**
825
     * @param string $fetch_order
826
     * @return Query
827
     */
828
    public function fetchOrder(string $fetch_order): Query {
829
        return $this->setFetchOrder($fetch_order);
830
    }
831
832
    /**
833
     * @return string
834
     */
835
    public function getFetchOrder(): string {
836
        return $this->fetch_order;
837
    }
838
839
    /**
840
     * @return Query
841
     */
842
    public function setFetchOrderAsc(): Query {
843
        return $this->setFetchOrder('asc');
844
    }
845
846
    /**
847
     * @return Query
848
     */
849
    public function fetchOrderAsc(): Query {
850
        return $this->setFetchOrderAsc();
851
    }
852
853
    /**
854
     * @return Query
855
     */
856
    public function setFetchOrderDesc(): Query {
857
        return $this->setFetchOrder('desc');
858
    }
859
860
    /**
861
     * @return Query
862
     */
863
    public function fetchOrderDesc(): Query {
864
        return $this->setFetchOrderDesc();
865
    }
866
867
    /**
868
     * @return Query
869
     * @var boolean $state
870
     *
871
     */
872
    public function softFail(bool $state = true): Query {
873
        return $this->setSoftFail($state);
874
    }
875
876
    /**
877
     * @return Query
878
     * @var boolean $state
879
     *
880
     */
881
    public function setSoftFail(bool $state = true): Query {
882
        $this->soft_fail = $state;
883
884
        return $this;
885
    }
886
887
    /**
888
     * @return boolean
889
     */
890
    public function getSoftFail(): bool {
891
        return $this->soft_fail;
892
    }
893
894
    /**
895
     * Handle the exception for a given uid
896
     * @param integer $uid
897
     *
898
     * @throws GetMessagesFailedException
899
     */
900
    protected function handleException(int $uid) {
901
        if ($this->soft_fail === false && $this->hasError($uid)) {
902
            $error = $this->getError($uid);
903
            throw new GetMessagesFailedException($error->getMessage(), 0, $error);
904
        }
905
    }
906
907
    /**
908
     * Add a new error to the error holder
909
     * @param integer $uid
910
     * @param Exception $error
911
     */
912
    protected function setError(int $uid, Exception $error) {
913
        $this->errors[$uid] = $error;
914
    }
915
916
    /**
917
     * Check if there are any errors / exceptions present
918
     * @return boolean
919
     * @var integer|null $uid
920
     *
921
     */
922
    public function hasErrors($uid = null): bool {
923
        if ($uid !== null) {
924
            return $this->hasError($uid);
925
        }
926
        return count($this->errors) > 0;
927
    }
928
929
    /**
930
     * Check if there is an error / exception present
931
     * @return boolean
932
     * @var integer $uid
933
     *
934
     */
935
    public function hasError(int $uid): bool {
936
        return isset($this->errors[$uid]);
937
    }
938
939
    /**
940
     * Get all available errors / exceptions
941
     *
942
     * @return array
943
     */
944
    public function errors(): array {
945
        return $this->getErrors();
946
    }
947
948
    /**
949
     * Get all available errors / exceptions
950
     *
951
     * @return array
952
     */
953
    public function getErrors(): array {
954
        return $this->errors;
955
    }
956
957
    /**
958
     * Get a specific error / exception
959
     * @return Exception|null
960
     * @var integer $uid
961
     *
962
     */
963
    public function error(int $uid) {
964
        return $this->getError($uid);
965
    }
966
967
    /**
968
     * Get a specific error / exception
969
     * @return Exception|null
970
     * @var integer $uid
971
     *
972
     */
973
    public function getError(int $uid) {
974
        if ($this->hasError($uid)) {
975
            return $this->errors[$uid];
976
        }
977
        return null;
978
    }
979
}
980