Passed
Push — master ( 1b679e...f46407 )
by Ehsan
02:49
created

CommandExtractor::checkDefaultCommand()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Botonomous;
4
5
use Botonomous\utility\ArrayUtility;
6
use Botonomous\utility\MessageUtility;
7
use NlpTools\Stemmers\PorterStemmer;
8
use NlpTools\Tokenizers\WhitespaceAndPunctuationTokenizer;
9
use NlpTools\Tokenizers\WhitespaceTokenizer;
10
11
/**
12
 * Class CommandExtractor.
13
 */
14
class CommandExtractor
15
{
16
    private $config;
17
    private $error;
18
    private $messageUtility;
19
    private $dictionary;
20
    private $commandContainer;
21
22
    /**
23
     * @param null $message
24
     *
25
     * @return Command|void
26
     */
27 8
    public function getCommandByMessage($message)
28
    {
29 8
        if (empty($message)) {
30 1
            $this->setError('Message is empty');
31
32 1
            return;
33
        }
34
35
        /*
36
         * Process the message and find explicitly specified command
37
         */
38 7
        return $this->getCommandObjectByMessage($message);
39
    }
40
41
    /**
42
     * @param $message
43
     *
44
     * @return array
45
     */
46 4
    public function countKeywordOccurrence($message)
47
    {
48 4
        $stemmer = new PorterStemmer();
49
50
        // tokenize $message
51 4
        $stemmed = implode(' ', $stemmer->stemAll((new WhitespaceAndPunctuationTokenizer())->tokenize($message)));
52
53 4
        $count = [];
54 4
        foreach ($this->getCommandContainer()->getAllAsObject() as $commandKey => $commandObject) {
55 4
            $keywordsCount = $this->commandKeywordOccurrence($commandObject, $stemmed);
56
57 4
            $total = 0;
58 4
            if (empty($keywordsCount)) {
59 4
                $count[$commandKey] = $total;
60 4
                continue;
61
            }
62
63 2
            $count[$commandKey] = array_sum($keywordsCount);
64
        }
65
66 4
        return $count;
67
    }
68
69
    /**
70
     * @param Command $command
71
     * @param         $message
72
     *
73
     * @return array|void
74
     */
75 4
    private function commandKeywordOccurrence(Command $command, $message)
76
    {
77 4
        $stemmer = new PorterStemmer();
78 4
        $keywords = $command->getKeywords();
79 4
        if (empty($keywords)) {
80 4
            return;
81
        }
82
83 4
        return $this->getMessageUtility()->keywordCount(
84 4
            $stemmer->stemAll($keywords),
85
            $message
86
        );
87
    }
88
89
    /**
90
     * @param $message
91
     *
92
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be Command|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
93
     */
94 7
    private function getCommandObjectByMessage($message)
95
    {
96 7
        $command = $this->getMessageUtility()->extractCommandName($message);
97 7
        if (empty($command)) {
98 3
            $command = (new ArrayUtility())->maxPositiveValueKey($this->countKeywordOccurrence($message));
99
        }
100
101
        // check command name
102 7
        if (empty($command)) {
103
            // get the default command if no command is find in the message
104 3
            $command = $this->checkDefaultCommand();
105
        }
106
107 7
        return $this->getCommandObjectByCommand($command);
108
    }
109
110
    /**
111
     * @return mixed|void
112
     */
113 3
    private function checkDefaultCommand()
114
    {
115 3
        $command = $this->getConfig()->get('defaultCommand');
116
117 3
        if (empty($command)) {
118 2
            $this->setError($this->getDictionary()->get('generic-messages')['noCommandMessage']);
119 2
            return;
120
        }
121
122 1
        return $command;
123
    }
124
125
    /**
126
     * @param $command
127
     *
128
     * @return Command|void
129
     */
130 7
    private function getCommandObjectByCommand($command)
131
    {
132 7
        if (empty($command)) {
133 2
            return;
134
        }
135
136 5
        $commandObject = $this->getCommandContainer()->getAsObject($command);
137
138 5
        if ($this->validateCommandObject($commandObject) !== true) {
139 2
            return;
140
        }
141
142 5
        return $commandObject;
143
    }
144
145
    /**
146
     * Validate the command object.
147
     *
148
     * @param Command|null $commandObject
149
     *
150
     * @return bool
151
     */
152 5
    private function validateCommandObject($commandObject)
153
    {
154
        // check command details
155 5
        if (empty($commandObject)) {
156 2
            $this->setError(
157 2
                $this->getDictionary()->getValueByKey('generic-messages', 'unknownCommandMessage')
158
            );
159
160 2
            return false;
161
        }
162
163 5
        return true;
164
    }
165
166
    /**
167
     * @return string
168
     */
169 4
    public function getError()
170
    {
171 4
        return $this->error;
172
    }
173
174
    /**
175
     * @param string $error
176
     */
177 5
    public function setError($error)
178
    {
179 5
        $this->error = $error;
180 5
    }
181
182
    /**
183
     * @return Config
184
     */
185 4
    public function getConfig()
186
    {
187 4
        if ($this->config === null) {
188 3
            $this->config = (new Config());
189
        }
190
191 4
        return $this->config;
192
    }
193
194
    /**
195
     * @param Config $config
196
     */
197 1
    public function setConfig(Config $config)
198
    {
199 1
        $this->config = $config;
200 1
    }
201
202
    /**
203
     * @return MessageUtility
204
     */
205 8
    public function getMessageUtility()
206
    {
207 8
        if (!isset($this->messageUtility)) {
208 8
            $this->setMessageUtility(new MessageUtility());
209
        }
210
211 8
        return $this->messageUtility;
212
    }
213
214
    /**
215
     * @param MessageUtility $messageUtility
216
     */
217 8
    public function setMessageUtility(MessageUtility $messageUtility)
218
    {
219 8
        $this->messageUtility = $messageUtility;
220 8
    }
221
222
    /**
223
     * @return Dictionary
224
     */
225 4
    public function getDictionary()
226
    {
227 4
        if (!isset($this->dictionary)) {
228 4
            $this->setDictionary(new Dictionary());
229
        }
230
231 4
        return $this->dictionary;
232
    }
233
234
    /**
235
     * @param Dictionary $dictionary
236
     */
237 4
    public function setDictionary(Dictionary $dictionary)
238
    {
239 4
        $this->dictionary = $dictionary;
240 4
    }
241
242
    /**
243
     * @return CommandContainer
244
     */
245 8
    public function getCommandContainer()
246
    {
247 8
        if (!isset($this->commandContainer)) {
248 6
            $this->setCommandContainer(new CommandContainer());
249
        }
250
251 8
        return $this->commandContainer;
252
    }
253
254
    /**
255
     * @param CommandContainer $commandContainer
256
     */
257 8
    public function setCommandContainer(CommandContainer $commandContainer)
258
    {
259 8
        $this->commandContainer = $commandContainer;
260 8
    }
261
}
262