Completed
Push — master ( 2a793d...485884 )
by Gallice
03:09
created

Conversation::converse()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 23
ccs 12
cts 12
cp 1
rs 8.5906
cc 5
eloc 13
nc 8
nop 4
crap 5
1
<?php
2
3
namespace Tgallice\Wit;
4
5
use Tgallice\Wit\Exception\BadResponseException;
6
use Tgallice\Wit\Exception\ConversationException;
7
use Tgallice\Wit\Exception\InvalidStepException;
8
use Tgallice\Wit\Exception\MaxIterationException;
9
use Tgallice\Wit\Model\Context;
10
use Tgallice\Wit\Model\Step;
11
use Tgallice\Wit\Model\Step\Action;
12
use Tgallice\Wit\Model\Step\Merge;
13
use Tgallice\Wit\Model\Step\Message;
14
use Tgallice\Wit\Model\Step\Stop;
15
16
class Conversation
17
{
18
    const MAX_STEPS_ITERATION = 5;
19
20
    /**
21
     * @var API
22
     */
23
    private $api;
24
25
    /**
26
     * @var ActionMapping
27
     */
28
    private $actionMapping;
29
30 11
    public function __construct(Api $api, ActionMapping $actionMapping)
31
    {
32 11
        $this->api = $api;
33 11
        $this->actionMapping = $actionMapping;
34 11
    }
35
36
    /**
37
     * @param string $sessionId
38
     * @param string|null $message
39
     * @param Context|null $context
40
     * @param int $stepIteration
41
     *
42
     * @return Context The new Context
43
     */
44 10
    public function converse($sessionId, $message = null, Context $context = null, $stepIteration = self::MAX_STEPS_ITERATION)
45
    {
46 10
        $context = (null !== $context) ? $context : new Context();
47
48 10
        if ($stepIteration <= 0) {
49 1
            $error = new MaxIterationException("Max iteration exceeded");
50 1
            $this->actionMapping->error($sessionId, $context, $error);
51
52 1
            return $context;
53
        }
54
55
        try {
56 10
            $step = $this->getNextStep($sessionId, $message, $context);
57 10
        } catch (\Exception $e) {
58
            // Trigger the error action
59 3
            $stepData = $e instanceof ConversationException ? $e->getStepData() : [];
60 3
            $this->actionMapping->error($sessionId, $context, $e, $stepData);
61
62 3
            return new Context();
63
        }
64
65 7
        return $this->performStep($sessionId, $step, $context, $stepIteration);
66
    }
67
68
    /**
69
     * @param string $sessionId
70
     * @param string|null $message
71
     * @param Context $context
72
     *
73
     * @return Step Step object
74
     *
75
     * @throws BadResponseException
76
     */
77 10
    private function getNextStep($sessionId, $message, Context $context)
78
    {
79 10
        $response = $this->api->getConverseNextStep($sessionId, $message, $context);
80
81 10
        if (200 !== $response->getStatusCode()) {
82 1
            $message = empty($response->getReasonPhrase()) ? 'Bad response status code' : $response->getReasonPhrase();
83 1
            throw new BadResponseException($message, $response);
84
        }
85
86 9
        $step = json_decode((string) $response->getBody(), true);
87
88 9
        if (null === $step) {
89 1
            $step = [];
90 1
        }
91
92 9
        if (isset($step['error'])) {
93 1
            throw new ConversationException($step['error'], $sessionId, $context, $step);
94
        }
95
96
        try {
97 8
            $step = StepFactory::create($step);
98 8
        } catch (InvalidStepException $e) {
99 1
            throw new ConversationException($e->getMessage(), $sessionId, $context, $e->getStepData());
100
        }
101
102 7
        return $step;
103
    }
104
105
    /**
106
     * @param $sessionId
107
     * @param Step $step
108
     * @param Context $context
109
     * @param int $currentIteration
110
     *
111
     * @return Context
112
     */
113 7
    private function performStep($sessionId, Step $step, Context $context, $currentIteration)
114
    {
115 7
        switch (true) {
116 7
            case $step instanceof Merge:
117 3
                $newContext = $this->actionMapping->merge($sessionId, $context, $step->getEntities());
118 3
                $context = $this->converse($sessionId, null, $newContext, --$currentIteration);
119 3
                break;
120 6
            case $step instanceof Message:
121 2
                $this->actionMapping->say($sessionId, $step->getMessage(), $context);
122 2
                break;
123 4
            case $step instanceof Action:
124 1
                $newContext = $this->actionMapping->action($sessionId, $step->getAction(), $context);
125 1
                $context = $this->converse($sessionId, null, $newContext, --$currentIteration);
126 1
                break;
127 4
            case $step instanceof Stop:
128 4
                $this->actionMapping->stop($sessionId, $context);
129 4
                break;
130
        }
131
132 7
        return $context;
133
    }
134
}
135