1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Telegram\Bot\Commands; |
4
|
|
|
|
5
|
|
|
use Telegram\Bot\Api; |
6
|
|
|
use Telegram\Bot\Exceptions\TelegramSDKException; |
7
|
|
|
use Telegram\Bot\Objects\Update; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class CommandBus. |
11
|
|
|
*/ |
12
|
|
|
class CommandBus |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* @var Command[] Holds all commands. |
16
|
|
|
*/ |
17
|
|
|
protected $commands = []; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @var Api |
21
|
|
|
*/ |
22
|
|
|
private $telegram; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Instantiate Command Bus. |
26
|
|
|
* |
27
|
|
|
* @param Api $telegram |
28
|
|
|
* |
29
|
|
|
* @throws TelegramSDKException |
30
|
|
|
*/ |
31
|
18 |
|
public function __construct(Api $telegram) |
32
|
|
|
{ |
33
|
18 |
|
$this->telegram = $telegram; |
34
|
18 |
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Returns the list of commands. |
38
|
|
|
* |
39
|
|
|
* @return array |
40
|
|
|
*/ |
41
|
8 |
|
public function getCommands() |
42
|
|
|
{ |
43
|
8 |
|
return $this->commands; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Add a list of commands. |
48
|
|
|
* |
49
|
|
|
* @param array $commands |
50
|
|
|
* |
51
|
|
|
* @return CommandBus |
52
|
|
|
*/ |
53
|
6 |
|
public function addCommands(array $commands) |
54
|
|
|
{ |
55
|
6 |
|
foreach ($commands as $command) { |
56
|
6 |
|
$this->addCommand($command); |
57
|
6 |
|
} |
58
|
|
|
|
59
|
6 |
|
return $this; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Add a command to the commands list. |
64
|
|
|
* |
65
|
|
|
* @param CommandInterface|string $command Either an object or full path to the command class. |
66
|
|
|
* |
67
|
|
|
* @throws TelegramSDKException |
68
|
|
|
* |
69
|
|
|
* @return CommandBus |
70
|
|
|
*/ |
71
|
14 |
|
public function addCommand($command) |
72
|
|
|
{ |
73
|
14 |
|
if (!is_object($command)) { |
74
|
10 |
|
if (!class_exists($command)) { |
75
|
2 |
|
throw new TelegramSDKException(sprintf('Command class "%s" not found! Please make sure the class exists.', |
76
|
2 |
|
$command)); |
77
|
|
|
} |
78
|
|
|
|
79
|
8 |
|
if ($this->telegram->hasContainer()) { |
80
|
|
|
$command = $this->buildDependencyInjectedCommand($command); |
81
|
|
|
} else { |
82
|
8 |
|
$command = new $command(); |
83
|
|
|
} |
84
|
8 |
|
} |
85
|
|
|
|
86
|
12 |
|
if ($command instanceof CommandInterface) { |
87
|
|
|
|
88
|
|
|
/* |
89
|
|
|
* At this stage we definitely have a proper command to use. |
90
|
|
|
* |
91
|
|
|
* @var Command $command |
92
|
|
|
*/ |
93
|
10 |
|
$this->commands[$command->getName()] = $command; |
94
|
|
|
|
95
|
10 |
|
return $this; |
96
|
|
|
} |
97
|
|
|
|
98
|
2 |
|
throw new TelegramSDKException(sprintf('Command class "%s" should be an instance of "Telegram\Bot\Commands\CommandInterface"', |
99
|
2 |
|
get_class($command))); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Remove a command from the list. |
104
|
|
|
* |
105
|
|
|
* @param $name |
106
|
|
|
*/ |
107
|
4 |
|
public function removeCommand($name) |
108
|
|
|
{ |
109
|
4 |
|
unset($this->commands[$name]); |
110
|
4 |
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Removes a list of commands. |
114
|
|
|
* |
115
|
|
|
* @param array $names |
116
|
|
|
* |
117
|
|
|
* @return CommandBus |
118
|
|
|
*/ |
119
|
2 |
|
public function removeCommands(array $names) |
120
|
|
|
{ |
121
|
2 |
|
foreach ($names as $name) { |
122
|
2 |
|
$this->removeCommand($name); |
123
|
2 |
|
} |
124
|
|
|
|
125
|
2 |
|
return $this; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Handles Inbound Messages and Executes Appropriate Command. |
130
|
|
|
* |
131
|
|
|
* @param $message |
132
|
|
|
* @param $update |
133
|
|
|
* |
134
|
|
|
* @throws TelegramSDKException |
135
|
|
|
* |
136
|
|
|
* @return Update |
137
|
|
|
*/ |
138
|
4 |
|
public function handler($message, Update $update) |
139
|
|
|
{ |
140
|
4 |
|
$match = $this->parseCommand($message); |
141
|
4 |
|
if (!empty($match)) { |
142
|
4 |
|
$command = $match[1]; |
143
|
|
|
// $bot = (!empty($match[2])) ? $match[2] : ''; |
|
|
|
|
144
|
4 |
|
$arguments = $match[3]; |
145
|
4 |
|
$this->execute($command, $arguments, $update); |
146
|
4 |
|
} |
147
|
|
|
|
148
|
4 |
|
return $update; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Parse a Command for a Match. |
153
|
|
|
* |
154
|
|
|
* @param $text |
155
|
|
|
* |
156
|
|
|
* @throws \InvalidArgumentException |
157
|
|
|
* |
158
|
|
|
* @return array |
159
|
|
|
*/ |
160
|
4 |
|
public function parseCommand($text) |
161
|
|
|
{ |
162
|
4 |
|
if (trim($text) === '') { |
163
|
|
|
throw new \InvalidArgumentException('Message is empty, Cannot parse for command'); |
164
|
|
|
} |
165
|
|
|
|
166
|
4 |
|
preg_match('/^\/([^\s@]+)@?(\S+)?\s?(.*)$/', $text, $matches); |
167
|
|
|
|
168
|
4 |
|
return $matches; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Execute the command. |
173
|
|
|
* |
174
|
|
|
* @param $name |
175
|
|
|
* @param $arguments |
176
|
|
|
* @param $message |
177
|
|
|
* |
178
|
|
|
* @return mixed |
179
|
|
|
*/ |
180
|
4 |
|
public function execute($name, $arguments, $message) |
181
|
|
|
{ |
182
|
4 |
|
if (array_key_exists($name, $this->commands)) { |
183
|
2 |
|
return $this->commands[$name]->make($this->telegram, $arguments, $message); |
184
|
2 |
|
} elseif (array_key_exists('help', $this->commands)) { |
185
|
|
|
return $this->commands['help']->make($this->telegram, $arguments, $message); |
186
|
|
|
} |
187
|
|
|
|
188
|
2 |
|
return 'Ok'; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Use PHP Reflection and Laravel Container to instantiate the command with type hinted dependencies. |
193
|
|
|
* |
194
|
|
|
* @param $commandClass |
195
|
|
|
* |
196
|
|
|
* @return object |
197
|
|
|
*/ |
198
|
|
|
private function buildDependencyInjectedCommand($commandClass) |
199
|
|
|
{ |
200
|
|
|
|
201
|
|
|
// check if the command has a constructor |
202
|
|
|
if (!method_exists($commandClass, '__construct')) { |
203
|
|
|
return new $commandClass(); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
// get constructor params |
207
|
|
|
$constructorReflector = new \ReflectionMethod($commandClass, '__construct'); |
208
|
|
|
$params = $constructorReflector->getParameters(); |
209
|
|
|
|
210
|
|
|
// if no params are needed proceed with normal instantiation |
211
|
|
|
if (empty($params)) { |
212
|
|
|
return new $commandClass(); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
// otherwise fetch each dependency out of the container |
216
|
|
|
$container = $this->telegram->getContainer(); |
217
|
|
|
$dependencies = []; |
218
|
|
|
foreach ($params as $param) { |
219
|
|
|
$dependencies[] = $container->make($param->getClass()->name); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
// and instantiate the object with dependencies through ReflectionClass |
223
|
|
|
$classReflector = new \ReflectionClass($commandClass); |
224
|
|
|
|
225
|
|
|
return $classReflector->newInstanceArgs($dependencies); |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.