Completed
Push — master ( 1d0faf...7a5aed )
by Kacper
05:34
created

XmppClient::getJid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 1
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
/**
3
 * XMPP Library
4
 *
5
 * Copyright (C) 2016, Some right 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;
17
18
use DI\Container;
19
use DI\ContainerBuilder;
20
use Interop\Container\ContainerInterface;
21
use Kadet\Xmpp\Exception\InvalidArgumentException;
22
use Kadet\Xmpp\Module\ClientModuleInterface;
23
use Kadet\Xmpp\Module\SaslAuthenticator;
24
use Kadet\Xmpp\Module\StartTls;
25
use Kadet\Xmpp\Network\Connector;
26
use Kadet\Xmpp\Stream\Features;
27
use Kadet\Xmpp\Utils\Accessors;
28
use Kadet\Xmpp\Utils\filter as with;
29
use Kadet\Xmpp\Utils\ServiceManager;
30
use Kadet\Xmpp\Xml\XmlElementFactory;
31
use Kadet\Xmpp\Xml\XmlParser;
32
use Kadet\Xmpp\Xml\XmlStream;
33
use React\EventLoop\LoopInterface;
34
35
/**
36
 * Class XmppClient
37
 * @package Kadet\Xmpp
38
 *
39
 * @property-read Jid $jid Client's jid (Jabber Identifier) address.
40
 * @property-write Connector $connector
41
 */
42
class XmppClient extends XmlStream implements ContainerInterface
43
{
44
    use ServiceManager, Accessors;
45
46
    private $_attributes = [];
47
    private $_lang;
48
49
    /**
50
     * Connector used to instantiate stream connection to server.
51
     *
52
     * @var Connector
53
     */
54
    protected $_connector;
55
56
    /**
57
     * Client's jid (Jabber Identifier) address.
58
     *
59
     * @var Jid
60
     */
61
    protected $_jid;
62
63
    /**
64
     * Dependency container used as service manager.
65
     *
66
     * @var Container
67
     */
68
    protected $_container;
69
70
71
    /**
72
     * XmppClient constructor.
73
     * @param Jid   $jid
74
     * @param array $options
75
     */
76
    public function __construct(Jid $jid, array $options = [])
77
    {
78
        $options = array_merge_recursive([
79
            'parser'  => new XmlParser(new XmlElementFactory()),
80
            'lang'    => 'en',
81
            'modules' => [
82
                new StartTls()
83
            ]
84
        ], $options);
85
86
        parent::__construct($options['parser'], null);
87
88
        $this->_parser->factory->load(require __DIR__ . '/XmlElementLookup.php');
89
90
        $this->_lang      = $options['lang'];
91
        $this->_container = ContainerBuilder::buildDevContainer();
92
        $this->_jid       = $jid;
93
        $this->connector  = $options['connector'] ?? new Connector\TcpXmppConnector($jid->domain, $options['loop']);
94
95
        if (isset($options['password'])) {
96
            $this->register(new SaslAuthenticator($options['password']));
97
        }
98
99
        foreach ($options['modules'] as $module) {
100
            $this->register($module);
101
        }
102
103
        $this->_connector->on('connect', function (...$arguments) {
104
            return $this->emit('connect', $arguments);
105
        });
106
107
        $this->on('element', function (Features $element) {
108
            $this->emit('features', [$element]);
109
        }, Features::class);
110
111
        $this->connect();
112
    }
113
114
    public function start(array $attributes = [])
115
    {
116
        $this->_attributes = $attributes;
117
118
        parent::start(array_merge([
119
            'xmlns'    => 'jabber:client',
120
            'version'  => '1.0',
121
            'xml:lang' => $this->_lang
122
        ], $attributes));
123
    }
124
125
    public function restart()
126
    {
127
        $this->getLogger()->debug('Restarting stream', $this->_attributes);
128
        $this->start($this->_attributes);
129
    }
130
131
    public function connect()
132
    {
133
        $this->getLogger()->debug("Connecting to {$this->_jid->domain}");
134
135
        $this->_connector->connect();
136
    }
137
138
    public function getJid()
139
    {
140
        return $this->_jid;
141
    }
142
143
    private function handleConnect($stream)
144
    {
145
        $this->exchangeStream($stream);
146
147
        $this->getLogger()->info("Connected to {$this->_jid->domain}");
148
        $this->start([
149
            'from' => (string)$this->_jid,
150
            'to'   => $this->_jid->domain
151
        ]);
152
    }
153
154
    /**
155
     * @param $connector
156
     */
157
    protected function setConnector($connector)
158
    {
159
        if ($connector instanceof LoopInterface) {
160
            $this->_connector = new Connector\TcpXmppConnector($this->_jid->domain, $connector);
161
        } elseif ($connector instanceof Connector) {
162
            $this->_connector = $connector;
163
        } else {
164
            throw new InvalidArgumentException(sprintf(
165
                '$connector must be either %s, or %s instance %s given.',
166
                LoopInterface::class, Connector::class, \Kadet\Xmpp\Utils\helper\typeof($connector)
167
            ));
168
        }
169
170
        $this->_connector->on('connect', function ($stream) {
171
            $this->handleConnect($stream);
172
        });
173
    }
174
175
    protected function register(ClientModuleInterface $module, $alias = true)
176
    {
177
        $module->setClient($this);
178
        if ($alias === true) {
179
            $parents = array_merge(class_implements($module), array_slice(class_parents($module), 1));
180
            foreach ($parents as $alias) {
181
                if (!$this->has($alias)) {
182
                    $this->_container->set($alias, $module);
183
                }
184
            }
185
        } else {
186
            $this->_container->set($alias === true ? get_class($module) : $alias, $module);
0 ignored issues
show
Bug introduced by
It seems like $alias === true ? get_class($module) : $alias can also be of type boolean; however, DI\Container::set() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
187
        }
188
    }
189
190
    protected function getContainer() : ContainerInterface
191
    {
192
        return $this->_container;
193
    }
194
}
195