Passed
Push — master ( 162a39...7b742a )
by Malte
02:35
created

Query::parse_value()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
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\IMAP\Query;
14
15
use Carbon\Carbon;
16
use Webklex\IMAP\Client;
17
use Webklex\IMAP\Exceptions\GetMessagesFailedException;
18
use Webklex\IMAP\Exceptions\MessageSearchValidationException;
19
use Webklex\IMAP\Message;
20
use Webklex\IMAP\Support\MessageCollection;
21
22
/**
23
 * Class Query
24
 *
25
 * @package Webklex\IMAP\Query
26
 */
27
class Query {
28
29
    /** @var array $query */
30
    protected $query;
31
32
    /** @var string $raw_query  */
33
    protected $raw_query;
34
35
    /** @var string $charset */
36
    protected $charset;
37
38
    /** @var Client $client */
39
    protected $client;
40
41
    /** @var int $limit */
42
    protected $limit = null;
43
44
    /** @var int $page */
45
    protected $page = 1;
46
47
    /** @var int $fetch_options */
48
    protected $fetch_options = null;
49
50
    /** @var int $fetch_body */
51
    protected $fetch_body = true;
52
53
    /** @var int $fetch_attachment */
54
    protected $fetch_attachment = true;
55
56
    /** @var int $fetch_flags */
57
    protected $fetch_flags = true;
58
59
    /**
60
     * Query constructor.
61
     * @param Client $client
62
     * @param string $charset
63
     */
64
    public function __construct(Client $client, $charset = 'UTF-8') {
65
        $this->setClient($client);
66
67
        if(config('imap.options.fetch') === FT_PEEK) $this->leaveUnread();
68
69
        $this->charset = $charset;
70
        $this->query = collect();
0 ignored issues
show
Documentation Bug introduced by
It seems like collect() of type Illuminate\Support\Collection is incompatible with the declared type array of property $query.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
71
        $this->boot();
72
    }
73
74
    /**
75
     * Instance boot method for additional functionality
76
     */
77
    protected function boot(){}
78
79
    /**
80
     * Parse a given value
81
     * @param mixed $value
82
     *
83
     * @return string
84
     */
85
    protected function parse_value($value){
86
        switch(true){
87
            case $value instanceof \Carbon\Carbon:
88
                $value = $value->format('d M y');
89
                break;
90
        }
91
92
        return (string) $value;
93
    }
94
95
    /**
96
     * Check if a given date is a valid carbon object and if not try to convert it
97
     * @param $date
98
     *
99
     * @return Carbon
100
     * @throws MessageSearchValidationException
101
     */
102
    protected function parse_date($date) {
103
        if($date instanceof \Carbon\Carbon) return $date;
104
105
        try {
106
            $date = Carbon::parse($date);
107
        } catch (\Exception $e) {
108
            throw new MessageSearchValidationException();
109
        }
110
111
        return $date;
112
    }
113
114
    /**
115
     * Don't mark messages as read when fetching
116
     *
117
     * @return $this
118
     */
119
    public function leaveUnread() {
120
        $this->setFetchOptions(FT_PEEK);
0 ignored issues
show
Bug introduced by
Webklex\IMAP\Query\FT_PEEK of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions(). ( Ignorable by Annotation )

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

120
        $this->setFetchOptions(/** @scrutinizer ignore-type */ FT_PEEK);
Loading history...
121
122
        return $this;
123
    }
124
125
    /**
126
     * Mark all messages as read when fetching
127
     *
128
     * @return $this
129
     */
130
    public function markAsRead() {
131
        $this->setFetchOptions(FT_UID);
0 ignored issues
show
Bug introduced by
Webklex\IMAP\Query\FT_UID of type integer is incompatible with the type boolean expected by parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions(). ( Ignorable by Annotation )

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

131
        $this->setFetchOptions(/** @scrutinizer ignore-type */ FT_UID);
Loading history...
132
133
        return $this;
134
    }
135
136
    /**
137
     * Fetch the current query and return all found messages
138
     *
139
     * @return MessageCollection
140
     * @throws GetMessagesFailedException
141
     */
142
    public function get() {
143
        $messages = MessageCollection::make([]);
144
145
        try {
146
            $this->generate_query();
147
148
            /**
149
             * Don't set the charset if it isn't used - prevent strange outlook mail server errors
150
             * @see https://github.com/Webklex/laravel-imap/issues/100
151
             */
152
            if($this->getCharset() === null){
0 ignored issues
show
introduced by
The condition $this->getCharset() === null is always false.
Loading history...
153
                $available_messages = imap_search($this->getClient()->getConnection(), $this->getRawQuery(), SE_UID);
154
            }else{
155
                $available_messages = imap_search($this->getClient()->getConnection(), $this->getRawQuery(), SE_UID, $this->getCharset());
0 ignored issues
show
Bug introduced by
It seems like $this->getClient()->getConnection() can also be of type true; however, parameter $imap_stream of imap_search() does only seem to accept resource, 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

155
                $available_messages = imap_search(/** @scrutinizer ignore-type */ $this->getClient()->getConnection(), $this->getRawQuery(), SE_UID, $this->getCharset());
Loading history...
156
            }
157
158
            if ($available_messages !== false) {
159
160
                $available_messages = collect($available_messages);
161
                $options = config('imap.options');
162
163
                if(strtolower($options['fetch_order']) === 'desc'){
164
                    $available_messages = $available_messages->reverse();
165
                }
166
167
                $available_messages->forPage($this->page, $this->limit)->each(function($msgno, $msglist) use(&$messages, $options) {
168
                    $oMessage = new Message($msgno, $msglist, $this->getClient(), $this->getFetchOptions(), $this->getFetchBody(), $this->getFetchAttachment());
169
                    switch ($options['message_key']){
170
                        case 'number':
171
                            $message_key = $oMessage->getMessageNo();
172
                            break;
173
                        case 'list':
174
                            $message_key = $msglist;
175
                            break;
176
                        default:
177
                            $message_key = $oMessage->getMessageId();
178
                            break;
179
180
                    }
181
                    $messages->put($message_key, $oMessage);
182
                });
183
            }
184
185
            return $messages;
186
        } catch (\Exception $e) {
187
            $message = $e->getMessage();
188
189
            throw new GetMessagesFailedException($message);
190
        }
191
    }
192
193
    /**
194
     * Get the raw IMAP search query
195
     *
196
     * @return string
197
     */
198
    public function generate_query() {
199
        $query = '';
200
        $this->query->each(function($statement) use(&$query) {
201
            if (count($statement) == 1) {
202
                $query .= $statement[0];
203
            } else {
204
                if($statement[1] === null){
205
                    $query .= $statement[0];
206
                }else{
207
                    $query .= $statement[0].' "'.$statement[1].'"';
208
                }
209
            }
210
            $query .= ' ';
211
212
        });
213
214
        $this->raw_query = trim($query);
215
216
        return $this->raw_query;
217
    }
218
219
    /**
220
     * @return Client
221
     */
222
    public function getClient() {
223
        $this->client->checkConnection();
224
        return $this->client;
225
    }
226
227
    /**
228
     * Set the limit and page for the current query
229
     * @param int $limit
230
     * @param int $page
231
     *
232
     * @return $this
233
     */
234
    public function limit($limit, $page = 1) {
235
        if($page >= 1) $this->page = $page;
236
        $this->limit = $limit;
237
238
        return $this;
239
    }
240
241
    /**
242
     * @return array
243
     */
244
    public function getQuery() {
245
        return $this->query;
246
    }
247
248
    /**
249
     * @param array $query
250
     * @return Query
251
     */
252
    public function setQuery($query) {
253
        $this->query = $query;
254
        return $this;
255
    }
256
257
    /**
258
     * @return string
259
     */
260
    public function getRawQuery() {
261
        return $this->raw_query;
262
    }
263
264
    /**
265
     * @param string $raw_query
266
     * @return Query
267
     */
268
    public function setRawQuery($raw_query) {
269
        $this->raw_query = $raw_query;
270
        return $this;
271
    }
272
273
    /**
274
     * @return string
275
     */
276
    public function getCharset() {
277
        return $this->charset;
278
    }
279
280
    /**
281
     * @param string $charset
282
     * @return Query
283
     */
284
    public function setCharset($charset) {
285
        $this->charset = $charset;
286
        return $this;
287
    }
288
289
    /**
290
     * @param Client $client
291
     * @return Query
292
     */
293
    public function setClient(Client $client) {
294
        $this->client = $client;
295
        return $this;
296
    }
297
298
    /**
299
     * @return int
300
     */
301
    public function getLimit() {
302
        return $this->limit;
303
    }
304
305
    /**
306
     * @param int $limit
307
     * @return Query
308
     */
309
    public function setLimit($limit) {
310
        $this->limit = $limit <= 0 ? null : $limit;
311
        return $this;
312
    }
313
314
    /**
315
     * @return int
316
     */
317
    public function getPage() {
318
        return $this->page;
319
    }
320
321
    /**
322
     * @param int $page
323
     * @return Query
324
     */
325
    public function setPage($page) {
326
        $this->page = $page;
327
        return $this;
328
    }
329
330
    /**
331
     * @param boolean $fetch_options
332
     * @return Query
333
     */
334
    public function setFetchOptions($fetch_options) {
335
        $this->fetch_options = $fetch_options;
0 ignored issues
show
Documentation Bug introduced by
The property $fetch_options was declared of type integer, but $fetch_options is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
336
        return $this;
337
    }
338
339
    /**
340
     * @param boolean $fetch_options
341
     * @return Query
342
     */
343
    public function fetchOptions($fetch_options) {
344
        return $this->setFetchOptions($fetch_options);
345
    }
346
347
    /**
348
     * @return int
349
     */
350
    public function getFetchOptions() {
351
        return $this->fetch_options;
352
    }
353
354
    /**
355
     * @return boolean
356
     */
357
    public function getFetchBody() {
358
        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...
359
    }
360
361
    /**
362
     * @param boolean $fetch_body
363
     * @return Query
364
     */
365
    public function setFetchBody($fetch_body) {
366
        $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...
367
        return $this;
368
    }
369
370
    /**
371
     * @param boolean $fetch_body
372
     * @return Query
373
     */
374
    public function fetchBody($fetch_body) {
375
        return $this->setFetchBody($fetch_body);
376
    }
377
378
    /**
379
     * @return boolean
380
     */
381
    public function getFetchAttachment() {
382
        return $this->fetch_attachment;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->fetch_attachment returns the type integer which is incompatible with the documented return type boolean.
Loading history...
383
    }
384
385
    /**
386
     * @param boolean $fetch_attachment
387
     * @return Query
388
     */
389
    public function setFetchAttachment($fetch_attachment) {
390
        $this->fetch_attachment = $fetch_attachment;
0 ignored issues
show
Documentation Bug introduced by
The property $fetch_attachment was declared of type integer, but $fetch_attachment 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...
391
        return $this;
392
    }
393
394
    /**
395
     * @param boolean $fetch_attachment
396
     * @return Query
397
     */
398
    public function fetchAttachment($fetch_attachment) {
399
        return $this->setFetchAttachment($fetch_attachment);
400
    }
401
402
    /**
403
     * @return int
404
     */
405
    public function getFetchFlags() {
406
        return $this->fetch_flags;
407
    }
408
409
    /**
410
     * @param int $fetch_flags
411
     * @return Query
412
     */
413
    public function setFetchFlags($fetch_flags) {
414
        $this->fetch_flags = $fetch_flags;
415
        return $this;
416
    }
417
}