Completed
Push — master ( d3ac05...ae5f25 )
by Ehsan
04:38
created

CommandExtractor::getCommandByMessage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
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
10
/**
11
 * Class CommandExtractor.
12
 */
13
class CommandExtractor
14
{
15
    private $config;
16
    private $error;
17
    private $messageUtility;
18
    private $dictionary;
19
    private $commandContainer;
20
21
    /**
22
     * @param null $message
23
     *
24
     * @return Command|void
25
     */
26 8
    public function getCommandByMessage($message)
27
    {
28 8
        if (empty($message)) {
29 1
            $this->setError('Message is empty');
30
31 1
            return;
32
        }
33
34
        /*
35
         * Process the message and find explicitly specified command
36
         */
37 7
        return $this->getCommandObjectByMessage($message);
38
    }
39
40
    /**
41
     * @param $message
42
     *
43
     * @return array
44
     */
45 4
    public function countKeywordOccurrence($message)
46
    {
47 4
        $stemmer = new PorterStemmer();
48
49
        // tokenize $message
50 4
        $stemmed = implode(' ', $stemmer->stemAll((new WhitespaceAndPunctuationTokenizer())->tokenize($message)));
51
52 4
        $count = [];
53 4
        foreach ($this->getCommandContainer()->getAllAsObject() as $commandKey => $commandObject) {
54 4
            $keywordsCount = $this->commandKeywordOccurrence($commandObject, $stemmed);
55
56 4
            $total = 0;
57 4
            if (empty($keywordsCount)) {
58 4
                $count[$commandKey] = $total;
59 4
                continue;
60
            }
61
62 2
            $count[$commandKey] = array_sum($keywordsCount);
63
        }
64
65 4
        return $count;
66
    }
67
68
    /**
69
     * @param Command $command
70
     * @param string  $message
71
     *
72
     * @return array|void
73
     */
74 4
    private function commandKeywordOccurrence(Command $command, $message)
75
    {
76 4
        $stemmer = new PorterStemmer();
77 4
        $keywords = $command->getKeywords();
78 4
        if (empty($keywords)) {
79 4
            return;
80
        }
81
82 4
        return $this->getMessageUtility()->keywordCount(
83 4
            $stemmer->stemAll($keywords),
84
            $message
85
        );
86
    }
87
88
    /**
89
     * @param $message
90
     *
91
     * @return Command|null
92
     */
93 7
    private function getCommandObjectByMessage($message)
94
    {
95 7
        $command = $this->getMessageUtility()->extractCommandName($message);
96 7
        if (empty($command)) {
97 3
            $command = (new ArrayUtility())->maxPositiveValueKey($this->countKeywordOccurrence($message));
98
        }
99
100
        // check command name
101 7
        if (empty($command)) {
102
            // get the default command if no command is find in the message
103 3
            $command = $this->checkDefaultCommand();
104
        }
105
106 7
        return $this->getCommandObjectByCommand($command);
107
    }
108
109
    /**
110
     * @return mixed|void
111
     */
112 3
    private function checkDefaultCommand()
113
    {
114 3
        $command = $this->getConfig()->get('defaultCommand');
115
116 3
        if (empty($command)) {
117 2
            $this->setError($this->getDictionary()->get('generic-messages')['noCommandMessage']);
118
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