Completed
Push — master ( dd7177...241235 )
by Kacper
04:07
created

Component/Roster.php (3 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Nucleus - XMPP Library for PHP
4
 *
5
 * Copyright (C) 2016, Some rights reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 *
9
 * Contact with author:
10
 * Xmpp: [email protected]
11
 * E-mail: [email protected]
12
 *
13
 * From Kadet with love.
14
 */
15
16
namespace Kadet\Xmpp\Component;
17
18
19
use Kadet\Highlighter\Utils\Console;
20
use Kadet\Xmpp\Exception\ReadOnlyException;
21
use Kadet\Xmpp\Jid;
22
use Kadet\Xmpp\Stanza\Iq;
23
use Kadet\Xmpp\Utils\Accessors;
24
use Kadet\Xmpp\Utils\BetterEmitter;
25
use Kadet\Xmpp\Utils\filter as with;
26
use Kadet\Xmpp\XmppClient;
27
use Traversable;
28
use function Kadet\Xmpp\Utils\helper\format;
29
30
/**
31
 * Class Roster
32
 * @package Kadet\Xmpp\Component
33
 *
34
 * @property-read Iq\Query\Roster\Item[] $items Copy of all roster items
35
 */
36
class Roster extends Component implements \IteratorAggregate
37
{
38
    use BetterEmitter, Accessors;
39
40
    private $_items = [];
41
42 3
    public function setClient(XmppClient $client)
43
    {
44 3
        parent::setClient($client);
45
        $this->_client->on('init', function(\SplQueue $queue) {
46 1
            $queue->enqueue($this->_client->send(new Iq('get', ['query' => new Iq\Query\Roster()])));
47 3
        });
48
49 3
        $this->_client->on('iq', function(Iq $iq) {
50
            /** @var Roster $iq->query */
51 2
            switch ($iq->type) {
52 2
                case "result":
53 2
                    $this->handleResult($iq->query);
54 2
                    break;
55
                case "set":
56
                    $this->handleSet($iq->query);
57
                    break;
58
            }
59 3
        }, with\iq\query(Iq\Query\Roster::class));
60 3
    }
61
62 2
    private function handleSet(Iq\Query\Roster $query)
63
    {
64 2
        foreach ($query->items as $item) {
65 2
            if($item->subscription == 'remove') {
66
                $this->removeItem($item->jid);
67
            } else {
68 2
                $this->setItem($item);
69
            }
70
        }
71
72 2
        $this->emit('update');
73 2
    }
74
75 2
    private function handleResult(Iq\Query\Roster $query)
76
    {
77 2
        $this->_client->getLogger()->debug(format('Received roster (version: {version}) update with {no} roster items.', [
78 2
            'no' => count($query->items),
79 2
            'version' => $query->version
80
        ]));
81 2
        $this->_items = [];
82 2
        $this->handleSet($query);
83 2
    }
84
85
    /**
86
     * Whether a offset exists
87
     * @link  http://php.net/manual/en/arrayaccess.offsetexists.php
88
     * @param mixed $offset <p>
89
     *                      An offset to check for.
90
     *                      </p>
91
     * @return boolean true on success or false on failure.
92
     *                      </p>
93
     *                      <p>
94
     *                      The return value will be casted to boolean if non-boolean was returned.
95
     * @since 5.0.0
96
     */
97
    public function offsetExists($offset)
98
    {
99
        return array_key_exists($offset, $this->_items);
100
    }
101
102
    /**
103
     * Offset to retrieve
104
     * @link  http://php.net/manual/en/arrayaccess.offsetget.php
105
     * @param mixed $offset <p>
106
     *                      The offset to retrieve.
107
     *                      </p>
108
     * @return mixed Can return all value types.
109
     * @since 5.0.0
110
     */
111
    public function offsetGet($offset)
112
    {
113
        return clone ($this->_items[(string)$offset] ?? null);
114
    }
115
116
    /**
117
     * Offset to set
118
     * @link  http://php.net/manual/en/arrayaccess.offsetset.php
119
     * @param mixed $offset <p>
120
     *                      The offset to assign the value to.
121
     *                      </p>
122
     * @param mixed $value  <p>
123
     *                      The value to set.
124
     *                      </p>
125
     * @return void
126
     * @since 5.0.0
127
     */
128
    public function offsetSet($offset, $value)
0 ignored issues
show
The parameter $offset is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
129
    {
130
        throw new ReadOnlyException('You should not modify roster directly, use update() method.');
131
    }
132
133
    /**
134
     * Offset to unset
135
     * @link  http://php.net/manual/en/arrayaccess.offsetunset.php
136
     * @param mixed $offset <p>
137
     *                      The offset to unset.
138
     *                      </p>
139
     * @return void
140
     * @since 5.0.0
141
     */
142
    public function offsetUnset($offset)
0 ignored issues
show
The parameter $offset is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
143
    {
144
        throw new ReadOnlyException('You should not modify roster directly, use remove() method.');
145
    }
146
147 1
    public function remove($what)
148
    {
149 1
        $predicate = $what instanceof \Closure ? $what : with\property('jid', with\equals($what));
150 1
        $remove    = array_filter($this->_items, $predicate);
151
152 1
        $iq = new Iq('remove', ['query' => new Iq\Query\Roster()]);
153
        /** @var Iq\Query\Roster\Item $item */
154 1
        foreach($remove as $item) {
155 1
            $iq->query->append(new Iq\Query\Roster\Item($item->jid, ['subscription' => 'remove']));
156
        }
157
158 1
        $this->_client->send($iq);
159 1
    }
160
161
    /**
162
     * Retrieve an external iterator
163
     * @link  http://php.net/manual/en/iteratoraggregate.getiterator.php
164
     * @return Traversable An instance of an object implementing <b>Iterator</b> or
165
     * <b>Traversable</b>
166
     * @since 5.0.0
167
     */
168
    public function getIterator(): Traversable
169
    {
170
        return new \ArrayIterator($this->_items);
171
    }
172
173
    /**
174
     * @return Iq\Query\Roster\Item[]
175
     */
176 1
    public function getItems()
177
    {
178 1
        return \Kadet\Xmpp\Utils\helper\copy($this->_items);
179
    }
180
181
    public static function group($name)
182
    {
183
        return with\property('groups', with\contains($name));
184
    }
185
186
    /**
187
     * @param callable(Item $item) $mapper
188
     * @return array
189
     */
190
    public function map(callable $mapper)
191
    {
192
        return array_map($mapper, $this->items);
193
    }
194
195
    /**
196
     * @param callable $predicate
197
     * @return Iq\Query\Roster\Item[]
198
     */
199
    public function filter(callable $predicate)
200
    {
201
        return array_filter($this->items, $predicate);
202
    }
203
204
    public function asArray() : array
205
    {
206
        return $this->items;
207
    }
208
209
    public static function fromArray(array $array)
210
    {
211
        // TODO: Implement fromArray() method.
212
    }
213
214
    /**
215
     * Count elements of an object
216
     * @link  http://php.net/manual/en/countable.count.php
217
     * @return int The custom count as an integer.
218
     * </p>
219
     * <p>
220
     * The return value is cast to an integer.
221
     * @since 5.1.0
222
     */
223
    public function count()
224
    {
225
        return count($this->items);
226
    }
227
228
229 2
    private function setItem(Iq\Query\Roster\Item $item)
230
    {
231 2
        $this->emit('item', [ $item ]);
232 2
        $this->_items[(string)$item->jid] = $item;
233 2
    }
234
235
    private function removeItem(Jid $jid)
236
    {
237
        if (!isset($this->_items[(string)$jid])) {
238
            $this->_client->getLogger()->warning(format('Trying to remove non-existing roster item {jid}', [
239
                'item' => Console::styled(['color' => 'green'], (string)$jid)
240
            ]));
241
            return;
242
        }
243
244
        $this->emit('remove', [ $this->_items[(string)$jid] ]);
245
        unset($this->_items[(string)$jid]);
246
    }
247
}
248