Completed
Push — master ( 15677b...615879 )
by Vladimir
02:54
created

Bot::sendMessage()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 4
cts 4
cp 1
rs 9.4285
cc 3
eloc 12
nc 2
nop 4
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FondBot;
6
7
use FondBot\Traits\Loggable;
8
use FondBot\Channels\Channel;
9
use FondBot\Conversation\Context;
10
use FondBot\Contracts\Channels\User;
11
use FondBot\Contracts\Channels\Driver;
12
use FondBot\Conversation\IntentManager;
13
use FondBot\Conversation\ContextManager;
14
use FondBot\Contracts\Container\Container;
15
use FondBot\Contracts\Conversation\Intent;
16
use FondBot\Contracts\Conversation\Keyboard;
17
use FondBot\Contracts\Channels\OutgoingMessage;
18
use FondBot\Contracts\Conversation\Conversable;
19
use FondBot\Contracts\Conversation\Interaction;
20
use FondBot\Channels\Exceptions\InvalidChannelRequest;
21
use FondBot\Contracts\Channels\Extensions\WebhookVerification;
22
23
class Bot
24
{
25
    use Loggable;
26
27
    /** @var Bot */
28
    protected static $instance;
29
30
    private $container;
31
    private $channel;
32
    private $driver;
33
    private $request;
34
    private $headers;
35
36
    /** @var Context|null */
37
    private $context;
38
39 9
    protected function __construct(
40
        Container $container,
41
        Channel $channel,
42
        Driver $driver,
43
        array $request,
44
        array $headers
45
    ) {
46 9
        $this->container = $container;
47 9
        $this->channel = $channel;
48 9
        $this->driver = $driver;
49 9
        $this->request = $request;
50 9
        $this->headers = $headers;
51 9
    }
52
53
    /**
54
     * Create new bot instance.
55
     *
56
     * @param Container $container
57
     * @param Channel   $channel
58
     * @param Driver    $driver
59
     * @param array     $request
60
     * @param array     $headers
61
     */
62 9
    public static function createInstance(
63
        Container $container,
64
        Channel $channel,
65
        Driver $driver,
66
        array $request,
67
        array $headers
68
    ): void {
69 9
        static::setInstance(
70 9
            new static($container, $channel, $driver, $request, $headers)
71
        );
72 9
    }
73
74
    /**
75
     * Get current instance.
76
     *
77
     * @return Bot
78
     */
79 29
    public static function getInstance(): Bot
80
    {
81 29
        return static::$instance;
82
    }
83
84
    /**
85
     * Set instance of the bot.
86
     *
87
     * @param Bot $instance
88
     */
89 114
    public static function setInstance(Bot $instance): void
90
    {
91 114
        static::$instance = $instance;
92 114
    }
93
94
    /**
95
     * Get context instance.
96
     *
97
     * @return Context|null
98
     */
99 2
    public function getContext(): ?Context
100
    {
101 2
        return $this->context;
102
    }
103
104
    /**
105
     * Set context instance.
106
     *
107
     * @param Context $context
108
     */
109 2
    public function setContext(Context $context): void
110
    {
111 2
        $this->context = $context;
112 2
    }
113
114
    /**
115
     * Clear context.
116
     */
117 1
    public function clearContext(): void
118
    {
119 1
        if ($this->context !== null) {
120 1
            $this->contextManager()->clear($this->context);
121 1
            $this->context = null;
122
        }
123 1
    }
124
125
    /**
126
     * Resolve from container.
127
     *
128
     * @param string $class
129
     *
130
     * @return mixed
131
     */
132 5
    public function get(string $class)
133
    {
134 5
        return $this->container->make($class);
135
    }
136
137
    /**
138
     * Process webhook request.
139
     *
140
     * @return mixed
141
     */
142 4
    public function process()
143
    {
144
        try {
145 4
            $this->debug('process', [
146 4
                'channel' => $this->channel->getName(),
147 4
                'request' => $this->request,
148 4
                'headers' => $this->headers,
149
            ]);
150
151
            // Driver has webhook verification
152 4
            if ($this->driver instanceof WebhookVerification && $this->driver->isVerificationRequest()) {
153 1
                $this->debug('process.verifyWebhook');
154
155 1
                return $this->driver->verifyWebhook();
156
            }
157
158
            // Verify request
159 3
            $this->driver->verifyRequest();
160
161
            // Resolve context
162 2
            $this->context = $this->contextManager()->resolve($this->channel->getName(), $this->driver);
163
164 2
            if ($this->context->getInteraction() !== null) {
165 1
                $this->converse($this->context->getInteraction());
0 ignored issues
show
Documentation introduced by
$this->context->getInteraction() is of type object<FondBot\Contracts...nversation\Interaction>, but the function expects a object<FondBot\Contracts...nversation\Conversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
166
            } else {
167 1
                $intent = $this->intentManager()->find($this->driver->getMessage());
168
169 1
                if ($intent !== null) {
170 1
                    $this->converse($intent);
0 ignored issues
show
Documentation introduced by
$intent is of type object<FondBot\Contracts\Conversation\Intent>, but the function expects a object<FondBot\Contracts...nversation\Conversable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
171
                }
172
            }
173
174 2
            if ($this->context !== null) {
175 2
                $this->contextManager()->save($this->context);
176
            }
177
178 2
            return 'OK';
179 1
        } catch (InvalidChannelRequest $exception) {
180 1
            $this->error($exception->getMessage());
181
182 1
            return $exception->getMessage();
183
        }
184
    }
185
186
    /**
187
     * Start conversation.
188
     *
189
     * @param Conversable|Intent|Interaction $conversable
190
     */
191 2
    public function converse(Conversable $conversable): void
192
    {
193 2
        if ($conversable instanceof Intent) {
194 1
            $this->context->setIntent($conversable);
195 1
            $this->context->setInteraction(null);
196 1
            $this->context->setValues([]);
197
198 1
            $conversable->handle($this);
199
        } elseif ($conversable instanceof Interaction) {
200 1
            $conversable->handle($this);
201
        }
202 2
    }
203
204
    /**
205
     * Send message.
206
     *
207
     * @param User          $recipient
208
     * @param string        $text
209
     * @param Keyboard|null $keyboard
210
     * @param string|null   $driver
211
     *
212
     * @return OutgoingMessage|null
213
     */
214 2
    public function sendMessage(
215
        User $recipient,
216
        string $text,
217
        Keyboard $keyboard = null,
218
        string $driver = null
219
    ): ?OutgoingMessage {
220 2
        if ($driver !== null && !$this->driver instanceof $driver) {
221 1
            return null;
222
        }
223
224 1
        return $this->driver->sendMessage(
225
            $recipient,
226
            $text,
227
            $keyboard
228
        );
229
    }
230
231
    /**
232
     * Get context manager.
233
     *
234
     * @return ContextManager
235
     */
236 3
    private function contextManager(): ContextManager
237
    {
238 3
        return $this->get(ContextManager::class);
239
    }
240
241
    /**
242
     * Get intent manager.
243
     *
244
     * @return IntentManager
245
     */
246 1
    private function intentManager(): IntentManager
247
    {
248 1
        return $this->get(IntentManager::class);
249
    }
250
}
251