Passed
Push — master ( d686b8...2ab801 )
by Shahrad
02:31
created

WebhookHandler::getCrossData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace TelegramBot;
4
5
use TelegramBot\Entities\Update;
6
use TelegramBot\Exception\InvalidBotTokenException;
7
use TelegramBot\Util\DotEnv;
8
9
/**
10
 * Class Webhook
11
 *
12
 * @link    https://github.com/telegram-bot-php/core
13
 * @author  Shahrad Elahi (https://github.com/shahradelahi)
14
 * @license https://github.com/telegram-bot-php/core/blob/master/LICENSE (MIT License)
15
 */
16
abstract class WebhookHandler extends Telegram
17
{
18
19
	/**
20
	 * @var ?Update
21
	 */
22
	protected ?Update $update;
23
24
	/**
25
	 * @var array<Plugin>
26
	 */
27
	private array $plugins = [];
28
29
	/**
30
	 * @var bool
31
	 */
32
	private bool $isActive = false;
33
34
	/**
35
	 * The default configuration of the webhook.
36
	 *
37
	 * @var array
38
	 */
39
	private array $config = [
40
		'autoload_env_file' => false,
41
		'env_file_path' => null,
42
	];
43
44
	/**
45
	 * Webhook constructor.
46
	 *
47
	 * @param string $api_key The API key of the bot. Leave it blank for autoload from .env file.
48
	 */
49
	public function __construct(string $api_key = '')
50
	{
51
		parent::__construct($api_key);
52
53
		if (!Telegram::validateToken(self::getApiKey())) {
54
			throw new InvalidBotTokenException();
55
		}
56
	}
57
58
	/**
59
	 * Initialize the receiver.
60
	 *
61
	 * @return void
62
	 */
63
	public function init(): void
64
	{
65
		$this->config['env_file_path'] = $_SERVER['DOCUMENT_ROOT'] . '/.env';
66
	}
67
68
	/**
69
	 * Add a plugin to the receiver
70
	 *
71
	 * @param array<Plugin> $plugins
72
	 */
73
	public function addPlugin(array $plugins): void
74
	{
75
		foreach ($plugins as $plugin) {
76
			if (!is_subclass_of($plugin, Plugin::class)) {
77
				throw new \RuntimeException(
78
					sprintf('The plugin %s must be an instance of %s', get_class($plugin), Plugin::class)
79
				);
80
			}
81
			$this->plugins[] = $plugin;
82
		}
83
	}
84
85
	/**
86
	 * Match the update with the given plugins
87
	 *
88
	 * @param array<Plugin> $plugins
89
	 * @param ?Update $update The update to match
90
	 * @return void
91
	 */
92
	public function loadPluginsWith(array $plugins, Update $update = null): void
93
	{
94
		$update = $update ?? ($this->update ?? Telegram::getUpdate());
95
96
		foreach ($plugins as $plugin) {
97
			if (!is_subclass_of($plugin, Plugin::class)) {
98
				throw new \InvalidArgumentException(
99
					sprintf('The plugin %s must be an instance of %s', get_class($plugin), Plugin::class)
100
				);
101
			}
102
		}
103
104
		if ($update instanceof Update) {
105
			$this->spreadUpdateWith($update, $plugins);
106
		}
107
	}
108
109
	/**
110
	 * Match the message to the plugins
111
	 *
112
	 * @param ?Update $update The update to match
113
	 * @return void
114
	 */
115
	public function loadPlugins(Update $update = null): void
116
	{
117
		$update = $update ?? ($this->update ?? Telegram::getUpdate());
118
		$this->loadPluginsWith($this->plugins, $update);
0 ignored issues
show
Bug introduced by
It seems like $update can also be of type false; however, parameter $update of TelegramBot\WebhookHandler::loadPluginsWith() does only seem to accept TelegramBot\Entities\Update|null, maybe add an additional type check? ( Ignorable by Annotation )

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

118
		$this->loadPluginsWith($this->plugins, /** @scrutinizer ignore-type */ $update);
Loading history...
119
	}
120
121
	/**
122
	 * Load the environment's
123
	 *
124
	 * @param string $path
125
	 * @retrun void
126
	 */
127
	public function loadFileOfEnv(string $path): void
128
	{
129
		DotEnv::load($path);
130
	}
131
132
	/**
133
	 * Update the configuration
134
	 *
135
	 * @param array $configuration
136
	 * @return void
137
	 */
138
	public function updateConfiguration(array $configuration): void
139
	{
140
		$this->config = array_merge($this->config, $configuration);
141
	}
142
143
	/**
144
	 * Resolve the request.
145
	 *
146
	 * @param ?Update $update The custom to work with
147
	 * @param array $config The configuration of the receiver
148
	 *
149
	 * @retrun void
150
	 */
151
	public function resolve(Update $update = null, array $config = []): void
152
	{
153
		$method = '__process';
154
		if (!method_exists($this, $method)) {
155
			throw new \RuntimeException(sprintf('The method %s does not exist', $method));
156
		}
157
158
		if (is_array($config)) $this->updateConfiguration($config);
0 ignored issues
show
introduced by
The condition is_array($config) is always true.
Loading history...
159
160
		if (!empty($update)) $this->update = $update;
161
		else $this->update = Telegram::getUpdate() !== false ? Telegram::getUpdate() : null;
0 ignored issues
show
Documentation Bug introduced by
It seems like TelegramBot\Telegram::ge...ram::getUpdate() : null can also be of type false. However, the property $update is declared as type TelegramBot\Entities\Update|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
162
163
		if (empty($this->update)) {
164
			TelegramLog::error(
165
				'The update is empty, the request is not processed'
166
			);
167
			return;
168
		}
169
170
		putenv('TG_CURRENT_UPDATE=' . $this->update->getRawData(false));
171
172
		$this->$method($this->update);
173
	}
174
175
	/**
176
	 * This function will get update and spread it to the plugins
177
	 *
178
	 * @param Update $update
179
	 * @param array<Plugin> $plugins
180
	 * @return void
181
	 */
182
	private function spreadUpdateWith(Update $update, array $plugins): void
183
	{
184
		$this->isActive = true;
185
186
		foreach ($plugins as $plugin) {
187
			/** @var Plugin $plugin */
188
			(new $plugin())->__execute($this, $update);
189
			if ($this->isActive === false) break;
190
		}
191
192
		$this->isActive = false;
193
	}
194
195
	/**
196
	 * Kill the speeding process
197
	 *
198
	 * @return void
199
	 */
200
	public function kill(): void
201
	{
202
		$this->isActive = false;
203
	}
204
205
	/**
206
	 * Use this method on the webhook class to get the updates
207
	 *
208
	 * @param Update $update
209
	 * @return void
210
	 */
211
	abstract public function __process(Update $update): void;
212
213
}