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

XmppClient.php (1 issue)

Labels
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
 * 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
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