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
![]() |
|||||||
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
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
![]() $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
![]() |
|||||||
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
|
|||||||
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
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;
![]() |
|||||||
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 |