Completed
Push — master ( 7520aa...b5612a )
by Vladimir
07:29
created

Kernel::getInstance()   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 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FondBot\Application;
6
7
use FondBot\Http\Request;
8
use FondBot\Drivers\Driver;
9
use FondBot\Channels\Channel;
10
use League\Container\Container;
11
use FondBot\Conversation\Intent;
12
use FondBot\Conversation\Session;
13
use FondBot\Drivers\DriverManager;
14
use FondBot\Conversation\Conversable;
15
use FondBot\Conversation\Interaction;
16
use FondBot\Conversation\IntentManager;
17
use FondBot\Conversation\SessionManager;
18
use FondBot\Drivers\Exceptions\InvalidRequest;
19
use FondBot\Drivers\Extensions\WebhookVerification;
20
21
class Kernel
22
{
23
    public const VERSION = '1.0.0';
24
25
    /** @var Kernel */
26
    protected static $instance;
27
28
    private $container;
29
30
    /** @var Session|null */
31
    private $session;
32
33 9
    private function __construct(Container $container)
34
    {
35 9
        $this->container = $container;
36 9
    }
37
38
    public static function getInstance(): Kernel
39
    {
40
        return static::$instance;
41
    }
42
43 9
    public static function createInstance(Container $container): Kernel
44
    {
45 9
        return static::$instance = new static($container);
46
    }
47
48
    /**
49
     * Get current channel.
50
     *
51
     * @return Channel
52
     *
53
     * @throws \Psr\Container\ContainerExceptionInterface
54
     */
55
    public function getChannel(): Channel
56
    {
57
        return $this->container->get('channel');
58
    }
59
60
    /**
61
     * Get current driver instance.
62
     *
63
     * @return Driver
64
     *
65
     * @throws \Psr\Container\ContainerExceptionInterface
66
     */
67 1
    public function getDriver(): Driver
68
    {
69 1
        return $this->container->get('driver');
70
    }
71
72
    /**
73
     * Get session.
74
     *
75
     * @return Session|null
76
     */
77 2
    public function getSession(): ?Session
78
    {
79 2
        return $this->session;
80
    }
81
82
    /**
83
     * Set session.
84
     *
85
     * @param Session $session
86
     */
87 2
    public function setSession(Session $session): void
88
    {
89 2
        $this->session = $session;
90 2
    }
91
92
    /**
93
     * Clear session.
94
     *
95
     * @throws \Psr\Container\ContainerExceptionInterface
96
     */
97 1
    public function clearSession(): void
98
    {
99 1
        if ($this->session !== null) {
100 1
            $this->sessionManager()->clear($this->session);
101 1
            $this->session = null;
102
        }
103 1
    }
104
105
    /**
106
     * Resolve an alias from container.
107
     *
108
     * @param string $alias
109
     * @param array  $args
110
     *
111
     * @return mixed
112
     *
113
     * @throws \Psr\Container\ContainerExceptionInterface
114
     */
115 6
    public function resolve(string $alias, array $args = [])
116
    {
117 6
        return $this->container->get($alias, $args);
118
    }
119
120
    /**
121
     * Process webhook request.
122
     *
123
     * @param Channel $channel
124
     * @param Request $request
125
     *
126
     * @return mixed
127
     *
128
     * @throws \Psr\Container\ContainerExceptionInterface
129
     * @throws \FondBot\Drivers\Exceptions\DriverNotFound
130
     * @throws \FondBot\Drivers\Exceptions\InvalidConfiguration
131
     */
132 4
    public function process(Channel $channel, Request $request)
133
    {
134
        try {
135 4
            $driver = $this->driverManager()->get($channel, $request);
136
137 4
            $this->container->add('channel', $channel);
138 4
            $this->container->add('driver', $driver);
139
140
            // Driver has webhook verification
141 4
            if ($driver instanceof WebhookVerification && $driver->isVerificationRequest()) {
142 1
                return $driver->verifyWebhook();
143
            }
144
145
            // Verify request
146 3
            $driver->verifyRequest();
147
148
            // Resolve session
149 2
            $this->session = $this->sessionManager()->resolve($channel->getName(), $driver);
150
151 2
            if ($this->session->getInteraction() !== null) {
152 1
                $this->converse($this->session->getInteraction());
153
            } else {
154 1
                $intent = $this->intentManager()->find($driver->getMessage());
155
156 1
                if ($intent !== null) {
157 1
                    $this->converse($intent);
158
                }
159
            }
160
161 2
            if ($this->session !== null) {
162 2
                $this->sessionManager()->save($this->session);
163
            }
164
165 2
            return 'OK';
166 1
        } catch (InvalidRequest $exception) {
167 1
            return $exception->getMessage();
168
        }
169
    }
170
171
    /**
172
     * Start conversation.
173
     *
174
     * @param Conversable $conversable
175
     */
176 2
    public function converse(Conversable $conversable): void
177
    {
178 2
        if ($conversable instanceof Intent) {
179 1
            $this->session->setIntent($conversable);
180 1
            $this->session->setInteraction(null);
181 1
            $this->session->setValues([]);
182
183 1
            $conversable->handle($this);
184
        } elseif ($conversable instanceof Interaction) {
185 1
            $conversable->handle($this);
186
        }
187 2
    }
188
189
    /**
190
     * Get driver manager.
191
     *
192
     * @return DriverManager
193
     *
194
     * @throws \Psr\Container\ContainerExceptionInterface
195
     */
196 4
    private function driverManager(): DriverManager
197
    {
198 4
        return $this->resolve(DriverManager::class);
199
    }
200
201
    /**
202
     * Get session manager.
203
     *
204
     * @return SessionManager
205
     *
206
     * @throws \Psr\Container\ContainerExceptionInterface
207
     */
208 3
    private function sessionManager(): SessionManager
209
    {
210 3
        return $this->resolve(SessionManager::class);
211
    }
212
213
    /**
214
     * Get intent manager.
215
     *
216
     * @return IntentManager
217
     *
218
     * @throws \Psr\Container\ContainerExceptionInterface
219
     */
220 1
    private function intentManager(): IntentManager
221
    {
222 1
        return $this->resolve(IntentManager::class);
223
    }
224
}
225