Passed
Push — master ( 204e2b...dee98e )
by Gallice
03:34
created

Conversation::converse()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 31
ccs 0
cts 27
cp 0
rs 6.7272
nc 12
cc 7
eloc 23
nop 4
crap 56
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\Model\Context;
9
use Tgallice\Wit\Model\Step;
10
11
class Conversation
12
{
13
    const MAX_STEPS_ITERATION = 5;
14
15
    /**
16
     * @var API
17
     */
18
    private $api;
19
20
    /**
21
     * @var ActionMapping
22
     */
23
    private $actionMapping;
24
25
    public function __construct(Api $api, ActionMapping $actionMapping)
26
    {
27
        $this->api = $api;
28
        $this->actionMapping = $actionMapping;
29
    }
30
31
    /**
32
     * @param string $sessionId
33
     * @param string|null $message
34
     * @param Context|null $context
35
     * @param int $maxStepsIteration
36
     *
37
     * @return Context $context
38
     *
39
     * @throws ConversationException
40
     */
41
    public function converse($sessionId, $message = null, Context $context = null, $maxStepsIteration = self::MAX_STEPS_ITERATION)
42
    {
43
        $context = (null !== $context) ? $context : new Context();
44
45
        if ($maxStepsIteration === 0) {
46
            throw new ConversationException($sessionId, "Max iteration exceeded", $context);
47
        }
48
49
        $step = $this->getNextStep($sessionId, $message, $context);
50
51
        switch ($step->getType()) {
52
            case Step::TYPE_MERGE:
53
                $newContext = $this->actionMapping->merge($sessionId, $context, $step->getEntities());
0 ignored issues
show
Bug introduced by
The method getEntities does only exist in Tgallice\Wit\Model\Step\Merge, but not in Tgallice\Wit\Model\Step\...ice\Wit\Model\Step\Stop.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
54
                $context = $this->converse($sessionId, null, $newContext, --$maxStepsIteration);
55
                break;
56
            case Step::TYPE_MESSAGE:
57
                $this->actionMapping->say($sessionId, $step->getMessage(), $context);
0 ignored issues
show
Bug introduced by
The method getMessage does only exist in Tgallice\Wit\Model\Step\Message, but not in Tgallice\Wit\Model\Step\...ice\Wit\Model\Step\Stop.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
58
                break;
59
            case Step::TYPE_ACTION:
60
                $newContext = $this->actionMapping->action($sessionId, $step->getAction(), $context);
0 ignored issues
show
Bug introduced by
The method getAction does only exist in Tgallice\Wit\Model\Step\Action, but not in Tgallice\Wit\Model\Step\...ice\Wit\Model\Step\Stop.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
61
                $context = $this->converse($sessionId, null, $newContext, --$maxStepsIteration);
62
                break;
63
            case Step::TYPE_STOP:
64
                $this->actionMapping->stop($sessionId, $context);
65
                break;
66
            default:
67
                $this->actionMapping->error($sessionId, $context, 'Unknown error', $step);
0 ignored issues
show
Documentation introduced by
$step is of type object<Tgallice\Wit\Mode...ce\Wit\Model\Step\Stop>, but the function expects a array.

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...
68
        }
69
70
        return $context;
71
    }
72
73
    /**
74
     * @param string $sessionId
75
     * @param string|null $message
76
     * @param Context $context
77
     *
78
     * @return Step Return the step sequence
79
     *
80
     * @throws BadResponseException
81
     */
82
    private function getNextStep($sessionId, $message, Context $context)
83
    {
84
        $response = $this->api->getConverseNextStep($sessionId, $message, $context);
85
86
        if (200 !== $response->getStatusCode()) {
87
            throw new ConversationException($sessionId, $response->getReasonPhrase(), $context);
88
        }
89
90
        $step = json_decode((string) $response->getBody(), true);
91
92
        if (null === $step) {
93
            $step = [];
94
        }
95
96
        if (isset($step['error'])) {
97
            throw new ConversationException($sessionId, $step['error'], $context, $step);
98
        }
99
100
        try {
101
            $step = StepFactory::create($step);
102
        } catch (InvalidStepException $e) {
103
            throw new ConversationException($sessionId, $e->getMessage(), $context, $e->getStepData());
104
        }
105
106
        return $step;
107
    }
108
}
109