Webklex /
php-imap
| 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
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
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
Loading history...
$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
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
|
|||||||
| 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;
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 |