Passed
Push — master ( f57d83...b11985 )
by Vladimir
02:42
created

ConversationManager   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 94%

Importance

Changes 0
Metric Value
dl 0
loc 132
ccs 47
cts 50
cp 0.94
rs 10
c 0
b 0
f 0
wmc 14
lcom 1
cbo 8

7 Methods

Rating   Name   Duplication   Size   Complexity  
A transition() 0 5 1
A __construct() 0 4 1
B handle() 0 24 4
A converse() 0 17 3
A restart() 0 21 3
A findIntent() 0 7 1
A isInConversation() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FondBot\Conversation;
6
7
use FondBot\Foundation\Kernel;
8
use FondBot\Drivers\ReceivedMessage;
9
use FondBot\Drivers\Exceptions\InvalidRequest;
10
11
class ConversationManager
12
{
13
    /**
14
     * Determine if conversation transitioned.
15
     *
16
     * @var bool
17
     */
18
    private $transitioned = false;
19
20
    private $kernel;
21
22 6
    public function __construct(Kernel $kernel)
23
    {
24 6
        $this->kernel = $kernel;
25 6
    }
26
27
    /**
28
     * Handle received message.
29
     *
30
     * @param ReceivedMessage $message
31
     */
32 2
    public function handle(ReceivedMessage $message): void
33
    {
34
        try {
35 2
            if (!$this->isInConversation()) {
36 1
                $this->converse(
37 1
                    $this->findIntent($message)
0 ignored issues
show
Bug introduced by
It seems like $this->findIntent($message) can be null; however, converse() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
38
                );
39
            } else {
40 1
                $this->converse(
41 1
                    session()->getInteraction()
0 ignored issues
show
Bug introduced by
It seems like session()->getInteraction() can be null; however, converse() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
42
                );
43
            }
44
45
            // Close session if conversation has not been transitioned
46
            // Otherwise, save session state
47 2
            if (!$this->transitioned) {
48 2
                $this->kernel->closeSession();
49
            } else {
50
                $this->kernel->saveSession();
51
            }
52
        } catch (InvalidRequest $exception) {
53
            logger()->warning('ConversationManager[handle] - Invalid Request', ['message' => $exception->getMessage()]);
54
        }
55 2
    }
56
57
    /**
58
     * Start conversation.
59
     *
60
     * @param Conversable|mixed $conversable
61
     */
62 5
    public function converse(Conversable $conversable): void
63
    {
64 5
        if ($conversable instanceof Intent) {
65 2
            $session = $this->kernel->getSession();
66 2
            $session->setIntent($conversable);
67 2
            $session->setInteraction(null);
68 2
            $session->setContext([]);
69
70 2
            $this->kernel->setSession($session);
0 ignored issues
show
Bug introduced by
It seems like $session defined by $this->kernel->getSession() on line 65 can be null; however, FondBot\Foundation\Kernel::setSession() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
71
72 2
            $conversable->handle($this->kernel);
73 3
        } elseif ($conversable instanceof Interaction) {
74 2
            $conversable->handle($this->kernel);
75
        } else {
76 1
            $conversable->handle($this->kernel);
77
        }
78 5
    }
79
80
    /**
81
     * Transition to intent or interaction.
82
     *
83
     * @param Conversable $conversable
84
     */
85 1
    public function transition(Conversable $conversable): void
86
    {
87 1
        $this->converse($conversable);
88 1
        $this->transitioned = true;
89 1
    }
90
91
    /**
92
     * Restart intent or interaction.
93
     *
94
     * @param Conversable|mixed $conversable
95
     */
96 2
    public function restart(Conversable $conversable): void
97
    {
98
        switch (true) {
99 2
            case $conversable instanceof Intent:
100 1
                $this->converse($conversable);
101
102 1
                $this->transitioned = true;
103 1
                break;
104 1
            case $conversable instanceof Interaction:
105 1
                $session = $this->kernel->getSession();
106 1
                $session->setInteraction(null);
107 1
                $session->setContext([]);
108
109 1
                $this->kernel->setSession($session);
0 ignored issues
show
Bug introduced by
It seems like $session defined by $this->kernel->getSession() on line 105 can be null; however, FondBot\Foundation\Kernel::setSession() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
110
111 1
                $this->transitioned = true;
112
113 1
                $this->converse($conversable);
114 1
                break;
115
        }
116 2
    }
117
118
    /**
119
     * Find matching intent.
120
     *
121
     * @param ReceivedMessage $message
122
     *
123
     * @return Intent|null
124
     */
125 1
    private function findIntent(ReceivedMessage $message): Intent
126
    {
127
        /** @var IntentManager $intentManager */
128 1
        $intentManager = $this->kernel->resolve(IntentManager::class);
129
130 1
        return $intentManager->find($message);
131
    }
132
133
    /**
134
     * Determine if conversation started.
135
     *
136
     * @return bool
137
     */
138 2
    private function isInConversation(): bool
139
    {
140 2
        return $this->kernel->getSession()->getInteraction() !== null;
141
    }
142
}
143