Completed
Push — master ( 06a30b...a45079 )
by Irfaq
02:24
created

CommandBus::__call()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 9.4286
cc 2
eloc 4
nc 2
nop 2
crap 2.0625
1
<?php
2
3
namespace Telegram\Bot\Commands;
4
5
use Telegram\Bot\Api;
6
use Telegram\Bot\Objects\Update;
7
use Telegram\Bot\Exceptions\TelegramSDKException;
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 100
    public function __construct(Api $telegram)
32
    {
33 100
        $this->telegram = $telegram;
34 100
    }
35
36
    /**
37
     * Returns the list of commands.
38
     *
39
     * @return array
40
     */
41 10
    public function getCommands()
42
    {
43 10
        return $this->commands;
44
    }
45
46
    /**
47
     * Add a list of commands.
48
     *
49
     * @param array $commands
50
     *
51
     * @return CommandBus
52
     */
53 8
    public function addCommands(array $commands)
54
    {
55 8
        foreach ($commands as $command) {
56 8
            $this->addCommand($command);
57 8
        }
58
59 8
        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 20
    public function addCommand($command)
72
    {
73 20
        if (!is_object($command)) {
74 12
            if (!class_exists($command)) {
75 2
                throw new TelegramSDKException(
76 2
                    sprintf(
77 2
                        'Command class "%s" not found! Please make sure the class exists.',
78
                        $command
79 2
                    )
80 2
                );
81
            }
82
83 10
            if ($this->telegram->hasContainer()) {
84 2
                $command = $this->buildDependencyInjectedCommand($command);
85 2
            } else {
86 8
                $command = new $command();
87
            }
88 10
        }
89
90 18
        if ($command instanceof CommandInterface) {
91
92
            /*
93
             * At this stage we definitely have a proper command to use.
94
             *
95
             * @var Command $command
96
             */
97 16
            $this->commands[$command->getName()] = $command;
98
99 16
            return $this;
100
        }
101
102 2
        throw new TelegramSDKException(
103 2
            sprintf(
104 2
                'Command class "%s" should be an instance of "Telegram\Bot\Commands\CommandInterface"',
105 2
                get_class($command)
106 2
            )
107 2
        );
108
    }
109
110
    /**
111
     * Remove a command from the list.
112
     *
113
     * @param $name
114
     *
115
     * @return CommandBus
116
     */
117 4
    public function removeCommand($name)
118
    {
119 4
        unset($this->commands[$name]);
120
121 4
        return $this;
122
    }
123
124
    /**
125
     * Removes a list of commands.
126
     *
127
     * @param array $names
128
     *
129
     * @return CommandBus
130
     */
131 2
    public function removeCommands(array $names)
132
    {
133 2
        foreach ($names as $name) {
134 2
            $this->removeCommand($name);
135 2
        }
136
137 2
        return $this;
138
    }
139
140
    /**
141
     * Parse a Command for a Match.
142
     *
143
     * @param $text
144
     *
145
     * @throws \InvalidArgumentException
146
     *
147
     * @return array
148
     */
149 16
    public function parseCommand($text)
150
    {
151 16
        if (trim($text) === '') {
152 2
            throw new \InvalidArgumentException('Message is empty, Cannot parse for command');
153
        }
154
155 14
        preg_match('/^\/([^\s@]+)@?(\S+)?\s?(.*)$/', $text, $matches);
156
157 14
        return $matches;
158
    }
159
160
    /**
161
     * Handles Inbound Messages and Executes Appropriate Command.
162
     *
163
     * @param $message
164
     * @param $update
165
     *
166
     * @throws TelegramSDKException
167
     *
168
     * @return Update
169
     */
170 8
    protected function handler($message, Update $update)
171
    {
172 8
        $match = $this->parseCommand($message);
173 8
        if (!empty($match)) {
174 8
            $command = strtolower($match[1]); //All commands must be lowercase.
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
175
//            $bot = (!empty($match[2])) ? $match[2] : '';
176 8
            $arguments = $match[3];
177
178 8
            $this->execute($command, $arguments, $update);
179 8
        }
180
181 8
        return $update;
182
    }
183
184
    /**
185
     * Execute the command.
186
     *
187
     * @param $name
188
     * @param $arguments
189
     * @param $message
190
     *
191
     * @return mixed
192
     */
193 10
    protected function execute($name, $arguments, $message)
194
    {
195 10
        if (array_key_exists($name, $this->commands)) {
196 6
            return $this->commands[$name]->make($this->telegram, $arguments, $message);
197 4
        } elseif (array_key_exists('help', $this->commands)) {
198
            return $this->commands['help']->make($this->telegram, $arguments, $message);
199
        }
200
201 4
        return 'Ok';
202
    }
203
204
    /**
205
     * Use PHP Reflection and Laravel Container to instantiate the command with type hinted dependencies.
206
     *
207
     * @param $commandClass
208
     *
209
     * @return object
210
     */
211 2
    private function buildDependencyInjectedCommand($commandClass)
212
    {
213
214
        // check if the command has a constructor
215 2
        if (!method_exists($commandClass, '__construct')) {
216
            return new $commandClass();
217
        }
218
219
        // get constructor params
220 2
        $constructorReflector = new \ReflectionMethod($commandClass, '__construct');
221 2
        $params = $constructorReflector->getParameters();
222
223
        // if no params are needed proceed with normal instantiation
224 2
        if (empty($params)) {
225
            return new $commandClass();
226
        }
227
228
        // otherwise fetch each dependency out of the container
229 2
        $container = $this->telegram->getContainer();
230 2
        $dependencies = [];
231 2
        foreach ($params as $param) {
232 2
            $dependencies[] = $container->make($param->getClass()->name);
233 2
        }
234
235
        // and instantiate the object with dependencies through ReflectionClass
236 2
        $classReflector = new \ReflectionClass($commandClass);
237
238 2
        return $classReflector->newInstanceArgs($dependencies);
239
    }
240
241
    /**
242
     * Handle calls to missing methods.
243
     *
244
     * @param  string  $method
245
     * @param  array   $parameters
246
     * @return mixed
247
     *
248
     * @throws \BadMethodCallException
249
     */
250 10
    public function __call($method, $parameters)
251
    {
252 10
        if(method_exists($this, $method)) {
253 10
            return call_user_func_array([$this, $method], $parameters);
254
        }
255
256
        throw new \BadMethodCallException("Method [$method] does not exist.");
257
    }
258
}
259