Passed
Push — master ( 812ed7...044883 )
by Malte
02:04
created

Folder::overview()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/*
3
* File:     Folder.php
4
* Category: -
5
* Author:   M. Goldenbaum
6
* Created:  19.01.17 22:21
7
* Updated:  -
8
*
9
* Description:
10
*  -
11
*/
12
13
namespace Webklex\PHPIMAP;
14
15
use Carbon\Carbon;
16
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
17
use Webklex\PHPIMAP\Exceptions\GetMessagesFailedException;
18
use Webklex\PHPIMAP\Exceptions\MessageSearchValidationException;
19
use Webklex\PHPIMAP\Query\WhereQuery;
20
use Webklex\PHPIMAP\Support\FolderCollection;
21
use Webklex\PHPIMAP\Support\MessageCollection;
22
use Webklex\PHPIMAP\Traits\HasEvents;
23
24
/**
25
 * Class Folder
26
 *
27
 * @package Webklex\PHPIMAP
28
 */
29
class Folder {
30
    use HasEvents;
31
32
    /**
33
     * Client instance
34
     *
35
     * @var \Webklex\PHPIMAP\Client
36
     */
37
    protected $client;
38
39
    /**
40
     * Folder full path
41
     *
42
     * @var string
43
     */
44
    public $path;
45
46
    /**
47
     * Folder name
48
     *
49
     * @var string
50
     */
51
    public $name;
52
53
    /**
54
     * Folder fullname
55
     *
56
     * @var string
57
     */
58
    public $full_name;
59
60
    /**
61
     * Children folders
62
     *
63
     * @var FolderCollection|array
64
     */
65
    public $children = [];
66
67
    /**
68
     * Delimiter for folder
69
     *
70
     * @var string
71
     */
72
    public $delimiter;
73
74
    /**
75
     * Indicates if folder can't containg any "children".
76
     * CreateFolder won't work on this folder.
77
     *
78
     * @var boolean
79
     */
80
    public $no_inferiors;
81
82
    /**
83
     * Indicates if folder is only container, not a mailbox - you can't open it.
84
     *
85
     * @var boolean
86
     */
87
    public $no_select;
88
89
    /**
90
     * Indicates if folder is marked. This means that it may contain new messages since the last time it was checked.
91
     * Not provided by all IMAP servers.
92
     *
93
     * @var boolean
94
     */
95
    public $marked;
96
97
    /**
98
     * Indicates if folder containg any "children".
99
     * Not provided by all IMAP servers.
100
     *
101
     * @var boolean
102
     */
103
    public $has_children;
104
105
    /**
106
     * Indicates if folder refers to other.
107
     * Not provided by all IMAP servers.
108
     *
109
     * @var boolean
110
     */
111
    public $referal;
112
113
    /**
114
     * Folder constructor.
115
     * @param Client $client
116
     * @param string $folder_name
117
     * @param string $delimiter
118
     * @param string[] $attributes
119
     */
120
    public function __construct(Client $client, $folder_name, $delimiter, $attributes) {
121
        $this->client = $client;
122
123
        $this->events["message"] = $client->getDefaultEvents("message");
124
        $this->events["folder"] = $client->getDefaultEvents("folder");
125
126
        $this->setDelimiter($delimiter);
127
        $this->path      = $folder_name;
128
        $this->full_name  = $this->decodeName($folder_name);
129
        $this->name      = $this->getSimpleName($this->delimiter, $this->full_name);
130
131
        $this->parseAttributes($attributes);
132
    }
133
134
    /**
135
     * Get a new search query instance
136
     * @param string $charset
137
     *
138
     * @return WhereQuery
139
     * @throws Exceptions\ConnectionFailedException
140
     */
141
    public function query($charset = 'UTF-8'){
142
        $this->getClient()->checkConnection();
143
        $this->getClient()->openFolder($this->path);
144
145
        return new WhereQuery($this->getClient(), $charset);
146
    }
147
148
    /**
149
     * @inheritdoc self::query($charset = 'UTF-8')
150
     * @throws Exceptions\ConnectionFailedException
151
     */
152
    public function search($charset = 'UTF-8'){
153
        return $this->query($charset);
154
    }
155
156
    /**
157
     * @inheritdoc self::query($charset = 'UTF-8')
158
     * @throws Exceptions\ConnectionFailedException
159
     */
160
    public function messages($charset = 'UTF-8'){
161
        return $this->query($charset);
162
    }
163
164
    /**
165
     * Determine if folder has children.
166
     *
167
     * @return bool
168
     */
169
    public function hasChildren() {
170
        return $this->has_children;
171
    }
172
173
    /**
174
     * Set children.
175
     * @param FolderCollection|array $children
176
     *
177
     * @return self
178
     */
179
    public function setChildren($children = []) {
180
        $this->children = $children;
181
182
        return $this;
183
    }
184
185
    /**
186
     * Decode name.
187
     * It converts UTF7-IMAP encoding to UTF-8.
188
     * @param $name
189
     *
190
     * @return mixed|string
191
     */
192
    protected function decodeName($name) {
193
        return mb_convert_encoding($name, "UTF-8", "UTF7-IMAP");
194
    }
195
196
    /**
197
     * Get simple name (without parent folders).
198
     * @param $delimiter
199
     * @param $full_name
200
     *
201
     * @return mixed
202
     */
203
    protected function getSimpleName($delimiter, $full_name) {
204
        $arr = explode($delimiter, $full_name);
205
206
        return end($arr);
207
    }
208
209
    /**
210
     * Parse attributes and set it to object properties.
211
     * @param $attributes
212
     */
213
    protected function parseAttributes($attributes) {
214
        $this->no_inferiors = in_array('\NoInferiors', $attributes) ? true : false;
215
        $this->no_select    = in_array('\NoSelect', $attributes) ? true : false;
216
        $this->marked       = in_array('\Marked', $attributes) ? true : false;
217
        $this->referal      = in_array('\Referal', $attributes) ? true : false;
218
        $this->has_children = in_array('\HasChildren', $attributes) ? true : false;
219
    }
220
221
    /**
222
     * Move or rename the current folder
223
     * @param string $new_name
224
     * @param boolean $expunge
225
     *
226
     * @return bool
227
     * @throws ConnectionFailedException
228
     * @throws Exceptions\EventNotFoundException
229
     * @throws Exceptions\FolderFetchingException
230
     * @throws Exceptions\RuntimeException
231
     */
232
    public function move($new_name, $expunge = true) {
233
        $this->client->checkConnection();
234
        $status = $this->client->getConnection()->renameFolder($this->full_name, $new_name);
0 ignored issues
show
Bug introduced by
The method renameFolder() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

234
        $status = $this->client->getConnection()->/** @scrutinizer ignore-call */ renameFolder($this->full_name, $new_name);
Loading history...
235
        if($expunge) $this->client->expunge();
236
237
        $folder = $this->client->getFolder($new_name);
238
        $event = $this->getEvent("folder", "moved");
239
        $event::dispatch($this, $folder);
240
241
        return $status;
242
    }
243
244
    /**
245
     * Get a message overview
246
     * @param string|null $sequence uid sequence
247
     *
248
     * @return array
249
     * @throws ConnectionFailedException
250
     */
251
    public function overview($sequence = null){
252
        $this->client->openFolder($this->path);
253
        $sequence = $sequence === null ? "1:*" : $sequence;
254
        return $this->client->getConnection()->overview($sequence);
0 ignored issues
show
Bug introduced by
The method overview() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

254
        return $this->client->getConnection()->/** @scrutinizer ignore-call */ overview($sequence);
Loading history...
255
    }
256
257
    /**
258
     * Append a string message to the current mailbox
259
     * @param string $message
260
     * @param string $options
261
     * @param string $internal_date
262
     *
263
     * @return bool
264
     * @throws Exceptions\ConnectionFailedException
265
     * @throws Exceptions\RuntimeException
266
     */
267
    public function appendMessage($message, $options = null, $internal_date = null) {
268
        /**
269
         * Check if $internal_date is parsed. If it is null it should not be set. Otherwise the message can't be stored.
270
         * If this parameter is set, it will set the INTERNALDATE on the appended message. The parameter should be a
271
         * date string that conforms to the rfc2060 specifications for a date_time value or be a Carbon object.
272
         */
273
274
        if ($internal_date != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $internal_date of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
275
            if ($internal_date instanceof Carbon){
0 ignored issues
show
introduced by
$internal_date is never a sub-type of Carbon\Carbon.
Loading history...
276
                $internal_date = $internal_date->format('d-M-Y H:i:s O');
277
            }
278
        }
279
280
        return $this->client->getConnection()->appendMessage($this->full_name, $message, $options, $internal_date);
0 ignored issues
show
Bug introduced by
The method appendMessage() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

280
        return $this->client->getConnection()->/** @scrutinizer ignore-call */ appendMessage($this->full_name, $message, $options, $internal_date);
Loading history...
281
    }
282
283
    /**
284
     * Rename the current folder
285
     * @param string $new_name
286
     * @param boolean $expunge
287
     *
288
     * @return bool
289
     * @throws ConnectionFailedException
290
     * @throws Exceptions\EventNotFoundException
291
     * @throws Exceptions\FolderFetchingException
292
     * @throws Exceptions\RuntimeException
293
     */
294
    public function rename($new_name, $expunge = true) {
295
        return $this->move($new_name, $expunge);
296
    }
297
298
    /**
299
     * Delete the current folder
300
     * @param boolean $expunge
301
     *
302
     * @return bool
303
     * @throws Exceptions\ConnectionFailedException
304
     * @throws Exceptions\RuntimeException
305
     * @throws Exceptions\EventNotFoundException
306
     */
307
    public function delete($expunge = true) {
308
        $status = $this->client->getConnection()->deleteFolder($this->path);
0 ignored issues
show
Bug introduced by
The method deleteFolder() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

308
        $status = $this->client->getConnection()->/** @scrutinizer ignore-call */ deleteFolder($this->path);
Loading history...
309
        if($expunge) $this->client->expunge();
310
311
        $event = $this->getEvent("folder", "deleted");
312
        $event::dispatch($this);
313
314
        return $status;
315
    }
316
317
    /**
318
     * Subscribe the current folder
319
     *
320
     * @return bool
321
     * @throws Exceptions\ConnectionFailedException
322
     * @throws Exceptions\RuntimeException
323
     */
324
    public function subscribe() {
325
        $this->client->openFolder($this->path);
326
        return $this->client->getConnection()->subscribeFolder($this->path);
0 ignored issues
show
Bug introduced by
The method subscribeFolder() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

326
        return $this->client->getConnection()->/** @scrutinizer ignore-call */ subscribeFolder($this->path);
Loading history...
327
    }
328
329
    /**
330
     * Unsubscribe the current folder
331
     *
332
     * @return bool
333
     * @throws Exceptions\ConnectionFailedException
334
     */
335
    public function unsubscribe() {
336
        $this->client->openFolder($this->path);
337
        return $this->client->getConnection()->unsubscribeFolder($this->path);
0 ignored issues
show
Bug introduced by
The method unsubscribeFolder() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

337
        return $this->client->getConnection()->/** @scrutinizer ignore-call */ unsubscribeFolder($this->path);
Loading history...
338
    }
339
340
    /**
341
     * Idle the current connection
342
     * @param callable $callback
343
     * @param integer $timeout max 1740 seconds - recommended by rfc2177 §3
344
     *
345
     * @throws ConnectionFailedException
346
     * @throws Exceptions\InvalidMessageDateException
347
     * @throws Exceptions\MessageContentFetchingException
348
     * @throws Exceptions\MessageHeaderFetchingException
349
     * @throws Exceptions\RuntimeException
350
     * @throws Exceptions\EventNotFoundException
351
     */
352
    public function idle(callable $callback, $timeout = 1200) {
353
        $this->client->getConnection()->setConnectionTimeout($timeout);
354
355
        $this->client->reconnect();
356
        $this->client->openFolder($this->path);
357
        $connection = $this->client->getConnection();
358
        $connection->idle();
0 ignored issues
show
Bug introduced by
The method idle() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

358
        $connection->/** @scrutinizer ignore-call */ 
359
                     idle();
Loading history...
359
360
        while (true) {
361
            try {
362
                $line = $connection->nextLine();
0 ignored issues
show
Bug introduced by
The method nextLine() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. It seems like you code against a sub-type of Webklex\PHPIMAP\Connection\Protocols\Protocol such as Webklex\PHPIMAP\Connection\Protocols\ImapProtocol. ( Ignorable by Annotation )

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

362
                /** @scrutinizer ignore-call */ 
363
                $line = $connection->nextLine();
Loading history...
363
                if (($pos = strpos($line, "EXISTS")) !== false) {
364
                    $msgn = (int) substr($line, 2, $pos -2);
365
                    $connection->done();
0 ignored issues
show
Bug introduced by
The method done() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

365
                    $connection->/** @scrutinizer ignore-call */ 
366
                                 done();
Loading history...
366
367
                    $message = $this->query()->getMessage($msgn);
368
                    $callback($message);
369
370
                    $event = $this->getEvent("message", "new");
371
                    $event::dispatch($message);
372
373
                    $connection->idle();
374
                }
375
            }catch (Exceptions\RuntimeException $e) {
376
                if(strpos($e->getMessage(), "connection closed") === false) {
377
                    throw $e;
378
                }else{
379
                    $this->client->connect();
380
                    $this->client->openFolder($this->path);
381
                    $connection = $this->client->getConnection();
382
                    $connection->idle();
383
                }
384
            }
385
        }
386
    }
387
388
    /**
389
     * Get folder status information
390
     *
391
     * @return array|bool
392
     * @throws Exceptions\ConnectionFailedException
393
     * @throws Exceptions\RuntimeException
394
     */
395
    public function getStatus() {
396
        return $this->examine();
397
    }
398
399
    /**
400
     * Examine the current folder
401
     *
402
     * @return array
403
     * @throws Exceptions\ConnectionFailedException
404
     * @throws Exceptions\RuntimeException
405
     */
406
    public function examine() {
407
        return $this->client->getConnection()->examineFolder($this->path);
0 ignored issues
show
Bug introduced by
The method examineFolder() does not exist on Webklex\PHPIMAP\Connection\Protocols\Protocol. Since it exists in all sub-types, consider adding an abstract or default implementation to Webklex\PHPIMAP\Connection\Protocols\Protocol. ( Ignorable by Annotation )

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

407
        return $this->client->getConnection()->/** @scrutinizer ignore-call */ examineFolder($this->path);
Loading history...
408
    }
409
410
    /**
411
     * Get the current Client instance
412
     *
413
     * @return Client
414
     */
415
    public function getClient() {
416
        return $this->client;
417
    }
418
419
    /**
420
     * Set the delimiter
421
     * @param $delimiter
422
     */
423
    public function setDelimiter($delimiter){
424
        if(in_array($delimiter, [null, '', ' ', false]) === true) {
425
            $delimiter = ClientManager::get('options.delimiter', '/');
426
        }
427
428
        $this->delimiter = $delimiter;
429
    }
430
}
431