Passed
Push — master ( 7ec3d6...1eec8f )
by Johnny
02:22
created

Output::processTopic()   C

Complexity

Conditions 14
Paths 99

Size

Total Lines 113
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 51
nc 99
nop 1
dl 0
loc 113
rs 6.2666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
use Axiom\Rivescript\Cortex\Trigger as TriggerData;
17
18
/**
19
 * Output class
20
 *
21
 * This class is responsible for generating the
22
 * bot response.
23
 *
24
 * PHP version 7.4 and higher.
25
 *
26
 * @category Core
27
 * @package  Cortext
28
 * @author   Shea Lewis <[email protected]>
29
 * @license  https://opensource.org/licenses/MIT MIT
30
 * @link     https://github.com/axiom-labs/rivescript-php
31
 * @since    0.3.0
32
 */
33
class Output
34
{
35
36
    use Regex;
37
    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...
38
39
    /**
40
     * The output string
41
     *
42
     * @var string
43
     */
44
    protected string $output = '';
45
46
    /**
47
     * Keep track of the recursion
48
     * in the output.
49
     *
50
     * @var int
51
     */
52
    protected int $recursion = 0;
53
54
    /**
55
     * Process the correct output response by the interpreter.
56
     *
57
     * @return string
58
     */
59
    public function process(): string
60
    {
61
        $this->output = "";
62
63
        /**
64
         * Leaving this function empty for maybe further expansion
65
         * later on.
66
         */
67
        return $this->processTopic();
68
    }
69
70
    protected function processTopic(int $recursion = 0): string
71
    {
72
        $topic = synapse()->memory->shortTerm()->get('topic') ?? 'random';
73
        $begin = synapse()->brain->topic("__begin__");
74
75
        $triggers = synapse()->brain->topic($topic)->triggers();
76
77
        if ($recursion === synapse()->memory->global()->get('depth')) {
78
            synapse()->rivescript->warn("Top many recursive calls to :func", ["func" => __CLASS__ . "::" . __FUNCTION__]);
79
            return "ERR: Deep Recursion Detected";
80
        }
81
82
        /**
83
         * 1. Check if topic is valid
84
         * 2. Process the triggers
85
         * 3. if valid trigger
86
         *   - Check if response is redirect
87
         *   -
88
         */
89
        if ($begin) {
90
            synapse()->rivescript->say("Begin label found. Starting processing.");
91
92
//            $request = $begin->triggers()->get("request");
93
            $request = null;
94
95
            // FIXME ugly code award make this global.
96
            foreach ($begin->triggers() as $trigger) {
97
                if ($trigger->getText() === "request") {
98
                    $request = $trigger;
99
                    break;
100
                }
101
            }
102
103
            if ($request) {
104
                $response = $request->getQueue()->process();
105
                $output = $response->getValue();
106
107
                if ($output !== '') {
108
                    $this->output .= $output;
109
                }
110
111
                if ($begin->isOk() === false) {
112
                    return $this->output;
113
                }
114
            }
115
        }
116
117
        foreach ($triggers as $index => $trigger) {
118
            $valid = $this->isValidTrigger($trigger);
119
120
            if ($valid === true) {
121
                synapse()->rivescript->debug("Found trigger \":trigger\".", [
122
                    'trigger' => $trigger->getText(),
123
                ]);
124
125
                synapse()->memory->shortTerm()->put('trigger', $trigger);
126
                $response = $this->getValidResponseForTriggerAtIndex($index);
127
128
                if ($response) {
129
                    if ($response->isTopicChanged() === true) {
130
                        synapse()->rivescript->debug(
131
                            "Topic changed from \":from\" to \":to\"",
132
                            [
133
                                "from" => $topic,
134
                                "to" => synapse()->memory->shortTerm()->get('topic') ?? 'random'
135
                            ]
136
                        );
137
138
                        synapse()->rivescript->debug(
139
                            "Parsed trigger :trigger",
140
                            [
141
                                "trigger" => $response->getValue(),
142
                            ]
143
                        );
144
145
                        //     synapse()->memory->shortTerm()->put('trigger', $response->getValue());
146
147
                        /**
148
                         * The topic has changed to something else during $this->getValidResponse($trigger).
149
                         * Call $this->>processTopic again to process the new topic.
150
                         *
151
                         * @note in this case the input can stay the same.
152
                         */
153
                        //    return $this->processTopic(++$recursion);
154
                    }
155
156
                    if ($response->isRedirect() === true) {
157
                        synapse()->rivescript->debug("Found redirect to \":redirect\" current topic is \":topic\".", [
158
                            "redirect" => $response->getRedirect(),
159
                            "topic" => $response->getTopic()
160
                        ]);
161
162
                        synapse()->input = new Input($response->getRedirect(), synapse()->rivescript->getClientId());
163
                        synapse()->memory->shortTerm()->put('trigger', $response->getRedirect());
164
165
                        return $this->processTopic(++$recursion);
166
                    }
167
168
                    $output = $response->getValue();
169
170
                    if ($output) {
171
                        $this->output .= $output;
172
                        break;
173
                    }
174
                } else {
175
                    synapse()->rivescript->warn("Could not find a valid response for trigger \":trigger\"", [
176
                        "trigger" => $trigger->getText()
177
                    ]);
178
                }
179
            }
180
        }
181
182
        return trim($this->output);
183
    }
184
185
186
    /**
187
     * Search through available triggers to find a possible match.
188
     *
189
     * @param TriggerData $trigger The trigger to find responses for.
190
     *
191
     * @return bool
192
     */
193
    protected function isValidTrigger(TriggerData $trigger): bool
194
    {
195
        $triggers = synapse()->triggers;
196
        foreach ($triggers as $class) {
197
            $triggerClass = "\\Axiom\\Rivescript\\Cortex\\Triggers\\{$class}";
198
            $triggerInstance = new $triggerClass(synapse()->input);
199
200
            $found = $triggerInstance->parse($trigger->getText(), synapse()->input);
201
202
            if ($found) {
203
                return true;
204
            }
205
        }
206
207
        return false;
208
    }
209
210
    protected function getValidResponseForTriggerAtIndex(int $index = 0): ?ResponseQueueItem
211
    {
212
        $originalTrigger = synapse()->brain->topic()->triggers()->get($index);
213
//        $originalTrigger = $trigger;
214
        $queueItem = null;
215
216
        if ($originalTrigger->hasResponses() === true) {
217
            $queueItem = $originalTrigger
218
                ->getQueue()
219
                ->process();
220
221
            if ($queueItem) {
222
                $queueItem->parse();
223
            }
224
        }
225
226
        return $queueItem;
227
    }
228
}
229