Passed
Push — master ( 9a8532...e68fd2 )
by Johnny
02:06
created

Rivescript::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
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;
12
13
use Axiom\Rivescript\Cortex\ContentLoader\ContentLoader;
14
use Axiom\Rivescript\Cortex\Input;
15
use Axiom\Rivescript\Cortex\Output;
16
use Axiom\Rivescript\Traits\Tags;
17
18
/**
19
 * Rivescript class
20
 *
21
 * The entry point for using the interpreter.
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 Rivescript extends ContentLoader
33
{
34
    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\Rivescript.
Loading history...
35
36
    public const VERBOSITY_NORMAL = 0;
37
    public const VERBOSITY_VERBOSE = 1;
38
    public const VERBOSITY_VERY_VERBOSE = 2;
39
    public const VERBOSITY_DEBUG = 3;
40
41
    public $onSay = null;
42
43
    /**
44
     * A recursion limit before an attempt to
45
     * fetch a reply will be abandoned.
46
     *
47
     * @var int
48
     */
49
    public int $depth = 50;
50
51
    /**
52
     * Error messages.
53
     *
54
     * @var array|string[]
55
     */
56
    public array $errors = [
57
        "replyNotMatched" => "ERR: No Reply Matched",
58
        "replyNotFound" => "ERR: No Reply Found",
59
        "objectNotFound" => "[ERR: Object Not Found]",
60
        "deepRecursion" => "ERR: Deep Recursion Detected"
61
    ];
62
63
    /**
64
     * Flag to indicating if utf8
65
     * modes is enabled.
66
     *
67
     * @var bool
68
     */
69
    protected bool $utf8 = false;
70
71
    /**
72
     * Flag to indicate debug mode
73
     * is enabled or not.
74
     *
75
     * @var bool
76
     */
77
    public bool $debug = false;
78
79
    /**
80
     * Create a new Rivescript instance.
81
     *
82
     * @throws \Axiom\Rivescript\Exceptions\ContentLoadingException
83
     */
84
    public function __construct()
85
    {
86
        parent::__construct();
87
88
        include __DIR__ . '/bootstrap.php';
89
90
        synapse()->brain->setMaster($this);
91
        synapse()->rivescript = $this;
92
93
        $this->registerTags();
94
    }
95
96
    /**
97
     * Initialize the tags
98
     *
99
     * @return void
100
     */
101
    private function registerTags(): void
102
    {
103
        synapse()->tags->each(
104
            function ($tag) {
105
                $class = "\\Axiom\\Rivescript\\Cortex\\Tags\\$tag";
106
                $tagInstance = new $class();
107
108
                $tagInfo = $tagInstance->getTagName();
109
                if (is_array($tagInfo)) {
110
                    foreach ($tagInfo as $tagName) {
111
                        synapse()->memory->tags()->put($tagName, $tagInstance);
112
                    }
113
                } else {
114
                    synapse()->memory->tags()->put($tagInfo, $tagInstance);
115
                }
116
            }
117
        );
118
    }
119
120
    /**
121
     * Load Rivescript interpretable content.
122
     * Into the Interpreter.
123
     *
124
     * Please note: This supports
125
     *
126
     * - Directory path to Rivescript interpretable files.
127
     * - Array of absolute paths to Rivescript interpretable files
128
     * - Absolute string containing path to Rivescript interpretable file.
129
     * - A stream of text with Rivescript interpretable script.
130
     *
131
     * Please note 2:
132
     *
133
     * If you profile a directory with rivescript documents make sure they are
134
     * all interpretable rivescript will throw syntax errors while trying to
135
     * parse those files.
136
     *
137
     * @param array<string>|string $info The files to read
138
     *
139
     * @return void
140
     */
141
    public function load($info): void
142
    {
143
        parent::load($info);
144
        $this->processInformation();
145
    }
146
147
    /**
148
     * Stream new information into the brain.
149
     *
150
     * @param string $string The string of information to feed the brain.
151
     *
152
     * @return void
153
     */
154
    public function stream(string $string): void
155
    {
156
        fseek($this->getStream(), 0, SEEK_SET);
157
        rewind($this->getStream());
158
159
        $this->writeToMemory($string);
160
        $this->processInformation();
161
    }
162
163
    /**
164
     * Process new information in the
165
     * stream.
166
     *
167
     * @return void
168
     */
169
    private function processInformation(): void
170
    {
171
        synapse()->memory->local()->put('concat', 'none');
172
        synapse()->brain->teach($this->getStream());
173
    }
174
175
    /**
176
     * Set user variables.
177
     *
178
     * @param string $user  The user for this variable.
179
     * @param string $name  The name of the variable.
180
     * @param string $value The value of the variable.
181
     *
182
     * @return void
183
     */
184
    public function setUservar(string $user, string $name, string $value): void
185
    {
186
        synapse()->memory->user($user)->put($name, $value);
187
    }
188
189
    /**
190
     * Get user variable.
191
     *
192
     * @param string $user The user for this variable.
193
     * @param string $name The name of the variable.
194
     *
195
     * @return mixed
196
     */
197
    public function getUservar(string $user, string $name)
198
    {
199
        return synapse()->memory->user($user)->get($name);
200
    }
201
202
    /**
203
     * @param string $string
204
     * @param bool   $utf8
205
     *
206
     * @return string
207
     * @deprecated
208
     */
209
    private function stripNasties(string $string, bool $utf8): string
0 ignored issues
show
Unused Code introduced by
The method stripNasties() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
Unused Code introduced by
The parameter $utf8 is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

209
    private function stripNasties(string $string, /** @scrutinizer ignore-unused */ bool $utf8): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
210
    {
211
        return preg_replace("/[^A-Za-z0-9 ]/m", "", $string);
212
    }
213
214
    /**
215
     * Log a message to say.
216
     *
217
     * @param string $message   The message to print out.
218
     * @param array  $args      (format) arguments for the message.
219
     * @param int    $verbosity The verbosity level of the message.
220
     *
221
     * @return void
222
     */
223
    public function say(string $message, array $args = [], int $verbosity = Rivescript::VERBOSITY_NORMAL): void
224
    {
225
226
        $message = $this->formatString($message, $args);
227
228
        if ($this->onSay) {
229
            call_user_func($this->onSay, $message, $verbosity);
230
        }
231
    }
232
233
    /**
234
     * Write a warning.
235
     *
236
     * @param string $message   The message to print out.
237
     * @param array  $args      (format) arguments for the message.
238
     * @param int    $verbosity The verbosity level of the message.
239
     *
240
     * @return void
241
     */
242
    public function warn(string $message, array $args = [], int $verbosity = Rivescript::VERBOSITY_NORMAL): void
243
    {
244
        $message = $this->formatString($message, $args);
245
246
        if ($this->onSay) {
247
            call_user_func($this->onSay, $message, $verbosity);
248
        }
249
    }
250
251
252
    /**
253
     * Create a string PDO style/
254
     *
255
     * @param string $msg  The message to write.
256
     * @param array  $args The arguments for the message.
257
     *
258
     * @return string
259
     */
260
    private function formatString(string $msg, array $args = []): string
261
    {
262
        $words = explode(' ', $msg);
263
        $parameters = array_filter($words, static function (string $part) {
264
            return ($part[0] === ':');
265
        });
266
267
        if (is_array($args) === true && count($args) > 0) {
268
            foreach ($parameters as $param) {
269
                $key = substr($param, 1);
270
                if (isset($args[$key]) === true) {
271
                    $msg = str_replace($param, $args[$key], $msg);
272
                }
273
            }
274
        }
275
276
        return $msg;
277
    }
278
279
    /**
280
     * Enable debug mode.
281
     *
282
     * @param bool $enabled Enable true/false.
283
     *
284
     * @return void
285
     */
286
    public function enableDebugMode(bool $enabled = true): void
0 ignored issues
show
Unused Code introduced by
The parameter $enabled is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

286
    public function enableDebugMode(/** @scrutinizer ignore-unused */ bool $enabled = true): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
287
    {
288
        synapse()->memory->global()->put('debug', true);
289
    }
290
291
    /**
292
     * Make the client respond to a message.
293
     *
294
     * @param string      $msg   The message the client has to process and respond to.
295
     * @param string      $user  The user id.
296
     * @param string|null $scope Not used at this point.
297
     *
298
     * @return string
299
     */
300
    public function reply(string $msg, string $user = 'local-user', string $scope = null): string
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

300
    public function reply(string $msg, string $user = 'local-user', /** @scrutinizer ignore-unused */ string $scope = null): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
301
    {
302
303
        // FIXME: Must be $user, $message, Sscope
304
        //    $msg = $this->stripNasties($msg, "");
305
        synapse()->rivescript->say("Asked to reply to :user :msg", ['user' => $user, 'message' => $msg]);
306
307
308
        $input = new Input($msg, $user);
309
        $output = new Output();
310
311
        synapse()->input = $input;
312
313
        $output = $output->process();
314
315
        if (empty($output)) {
316
            $output = $this->errors['replyNotMatched'];
317
        }
318
319
        synapse()->memory->inputs()->push($msg);
320
        synapse()->memory->replies()->push($output);
321
322
        return $output;
323
    }
324
}
325