Completed
Push — master ( 463ede...2a793d )
by Gallice
03:25
created

Conversation::converse()   D

Complexity

Conditions 9
Paths 16

Size

Total Lines 40
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 9.0036

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 40
ccs 27
cts 28
cp 0.9643
rs 4.909
cc 9
eloc 28
nc 16
nop 4
crap 9.0036
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 $maxStepsIteration
41
     *
42
     * @return Context The new Context
43
     */
44 10
    public function converse($sessionId, $message = null, Context $context = null, $maxStepsIteration = self::MAX_STEPS_ITERATION)
45
    {
46 10
        $context = (null !== $context) ? $context : new Context();
47
48 10
        if ($maxStepsIteration <= 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
        switch (true) {
66 7
            case $step instanceof Merge:
67 3
                $newContext = $this->actionMapping->merge($sessionId, $context, $step->getEntities());
68 3
                $context = $this->converse($sessionId, null, $newContext, --$maxStepsIteration);
69 3
                break;
70 6
            case $step instanceof Message:
71 2
                $this->actionMapping->say($sessionId, $step->getMessage(), $context);
72 2
                break;
73 4
            case $step instanceof Action:
74 1
                $newContext = $this->actionMapping->action($sessionId, $step->getAction(), $context);
75 1
                $context = $this->converse($sessionId, null, $newContext, --$maxStepsIteration);
76 1
                break;
77 4
            case $step instanceof Stop:
78 4
                $this->actionMapping->stop($sessionId, $context);
79 4
                break;
80
        }
81
82 7
        return $context;
83
    }
84
85
    /**
86
     * @param string $sessionId
87
     * @param string|null $message
88
     * @param Context $context
89
     *
90
     * @return Step Step object
91
     *
92
     * @throws BadResponseException
93
     */
94 10
    private function getNextStep($sessionId, $message, Context $context)
95
    {
96 10
        $response = $this->api->getConverseNextStep($sessionId, $message, $context);
97
98 10
        if (200 !== $response->getStatusCode()) {
99 1
            $message = empty($response->getReasonPhrase()) ? 'Bad response status code' : $response->getReasonPhrase();
100 1
            throw new BadResponseException($message, $response);
101
        }
102
103 9
        $step = json_decode((string) $response->getBody(), true);
104
105 9
        if (null === $step) {
106
            $step = [];
107
        }
108
109 9
        if (isset($step['error'])) {
110 1
            throw new ConversationException($step['error'], $sessionId, $context, $step);
111
        }
112
113
        try {
114 8
            $step = StepFactory::create($step);
115 8
        } catch (InvalidStepException $e) {
116 1
            throw new ConversationException($e->getMessage(), $sessionId, $context, $e->getStepData());
117
        }
118
119 7
        return $step;
120
    }
121
}
122