Passed
Push — master ( af6300...030a8a )
by Johnny
02:39
created

Output::isValidTrigger()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 15
rs 10
1
<?php
2
/*
3
 * This file is part of Rivescript-php
4
 *
5
 * (c) Shea Lewis <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Axiom\Rivescript\Cortex;
12
13
use Axiom\Rivescript\Cortex\ResponseQueue\ResponseQueueItem;
14
use Axiom\Rivescript\Traits\Regex;
15
use Axiom\Rivescript\Traits\Tags;
16
17
/**
18
 * Output class
19
 *
20
 * This class is responsible for generating the
21
 * bot response.
22
 *
23
 * PHP version 7.4 and higher.
24
 *
25
 * @category Core
26
 * @package  Cortext
27
 * @author   Shea Lewis <[email protected]>
28
 * @license  https://opensource.org/licenses/MIT MIT
29
 * @link     https://github.com/axiom-labs/rivescript-php
30
 * @since    0.3.0
31
 */
32
class Output
33
{
34
35
    use Regex;
36
    use Tags;
0 ignored issues
show
Bug introduced by
The trait Axiom\Rivescript\Traits\Tags requires the property $memory which is not provided by Axiom\Rivescript\Cortex\Output.
Loading history...
37
38
    /**
39
     * The output string
40
     *
41
     * @var string
42
     */
43
    protected string $output = '';
44
45
    /**
46
     * Keep track of the recursion
47
     * in the output.
48
     *
49
     * @var int
50
     */
51
    protected int $recursion = 0;
52
53
    /**
54
     * Process the correct output response by the interpreter.
55
     *
56
     * @return string
57
     */
58
    public function process(): string
59
    {
60
//        $triggers = synapse()->brain->topic()->triggers();
61
        $begin = synapse()->brain->topic("__begin__");
0 ignored issues
show
Unused Code introduced by
The assignment to $begin is dead and can be removed.
Loading history...
62
63
        $this->output = "";
64
65
66
        /**
67
         * 1. Check if topic is valid
68
         * 2. Process the triggers
69
         * 3. if valid trigger
70
         *   - Check if response is redirect
71
         *   -
72
         */
73
//        if ($begin) {
74
//            synapse()->rivescript->say("Begin label found. Starting processing.");
75
//
76
//            $request = $begin->triggers()->get("request");
77
//
78
//            if ($request) {
79
//                $this->output = $request['responses']->process();
80
//
81
//                if ($begin->isOk() === false) {
82
//                    return $this->output;
83
//                }
84
//            }
85
//        }
86
87
88
        return $this->processTopic();
89
90
        return trim($this->output);
0 ignored issues
show
Unused Code introduced by
return trim($this->output) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
91
    }
92
93
    protected function processTopic(int $recursion = 0): string
94
    {
95
        $topic = synapse()->memory->shortTerm()->get('topic') ?? 'random';
96
97
        // synapse()->rivescript->say("TOPIC {$topic}...");
98
        $triggers = synapse()->brain->topic($topic)->triggers();
99
100
        if ($recursion == 200) {
101
            synapse()->rivescript->warn("Top many recursive calls to :func", ["func" => __CLASS__ . "::" . __FUNCTION__]);
102
            exit;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
103
        }
104
105
        foreach ($triggers as $trigger => $data) {
106
            $valid = $this->isValidTrigger($trigger);
107
108
            if ($valid === true) {
109
                synapse()->rivescript->debug("Found trigger \":trigger\".", [
110
                    'trigger' => $trigger,
111
                ]);
112
113
                synapse()->memory->shortTerm()->put('trigger', $trigger);
114
                $response = $this->getValidResponse($trigger);
115
116
                if ($response) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
117
118
119
                    if ($response->isTopicChanged() === true) {
120
                        synapse()->rivescript->debug(
121
                            "Topic changed from \":from\" to \":to\"",
122
                            [
123
                                "from" => $topic,
124
                                "to" => synapse()->memory->shortTerm()->get('topic') ?? 'random'
125
                            ]
126
                        );
127
128
                        synapse()->rivescript->debug(
129
                            "Parsed trigger :trigger",
130
                            [
131
                                "trigger" => $response->getValue(),
132
                            ]
133
                        );
134
135
                        //     synapse()->memory->shortTerm()->put('trigger', $response->getValue());
136
137
                        /**
138
                         * The topic has changed to something else during $this->getValidResponse($trigger).
139
                         * Call $this->>processTopic again to process the new topic.
140
                         *
141
                         * @note in this case the input can stay the same.
142
                         */
143
                        //    return $this->processTopic(++$recursion);
144
                    }
145
146
                    if ($response->isRedirect() === true) {
147
                        synapse()->rivescript->debug("Found redirect to \":redirect\" current topic is \":topic\".", [
148
                            "redirect" => $response->getRedirect(),
149
                            "topic" => $response->getTopic()
150
                        ]);
151
152
                        synapse()->input = new Input($response->getRedirect(), synapse()->rivescript->getClientId());
153
                        synapse()->memory->shortTerm()->put('trigger', $response->getRedirect());
154
155
                        return $this->processTopic(++$recursion);
156
                    }
157
158
159
                    $output = $response->getValue();
160
161
                    if ($output) {
162
                        $this->output = $output;
163
                        break;
164
                    }
165
                } else {
166
                    synapse()->rivescript->warn("Could not find a valid response for trigger \":trigger\"", [
167
                        "trigger" => $trigger
168
                    ]);
169
                }
170
            }
171
        }
172
173
        return trim($this->output);
174
    }
175
176
177
    /**
178
     * Search through available triggers to find a possible match.
179
     *
180
     * @param string $trigger The trigger to find responses for.
181
     *
182
     * @return bool
183
     */
184
    protected function isValidTrigger(string $trigger): bool
185
    {
186
        $triggers = synapse()->triggers;
187
        foreach ($triggers as $class) {
188
            $triggerClass = "\\Axiom\\Rivescript\\Cortex\\Triggers\\{$class}";
189
            $triggerInstance = new $triggerClass(synapse()->input);
190
191
            $found = $triggerInstance->parse($trigger, synapse()->input);
192
193
            if ($found) {
194
                return true;
195
            }
196
        }
197
198
        return false;
199
    }
200
201
    protected function getValidResponse(string $trigger)
202
    {
203
        $originalTrigger = synapse()->brain->topic()->triggers()->get($trigger);
204
        $queueItem = null;
205
206
        if ($originalTrigger['responses']) {
207
            $queueItem = $originalTrigger['responses']->process();
208
209
            if ($queueItem) {
210
                $queueItem->parse();
211
            }
212
        }
213
214
        return $queueItem;
215
    }
216
}
217